[
  {
    "path": ".github/CODEOWNERS",
    "content": "*   @Kvel2D @Praytic\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[INSERT CONTACT METHOD].\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contribution guidance\n\n## How to contribute\n\nYou can contribute in different ways:\n\n- Report a bug in Issues\n- Write a suggestion in Discussions\n- Submit a modification to source code!\n\nFor the last one, you will need to download the Godot editor and obtain assets.\nRead below to find out how to obtain assets.\n\n## Editing the game in the Godot editor\n\nFirst, obtain necessary files:\n\n1. Download Godot editor *version 4.3* from the [Godot website](https://godotengine.org).\n2. Clone the game repository using Git.\n3. Download assets folder from this [Google Drive folder](https://drive.google.com/drive/folders/1U4wTjBu2qo1cInH3IAowsFC5yq56V5uQ?usp=sharing).\n4. Copy and paste downloaded assets into 'assets' folder in the game repository.\n5. You will see a popup asking whether you want to replace some files - press \"Yes\".\n\nThen, follow these steps to correctly import assets into Godot editor:\n\n1. Open the game project in the Godot editor.\n2. Wait for Godot editor to import assets. Open the \"Output\" window to confirm that the process is finished. There will be some errors - that's expected.\n3. Press Ctrl-S to save changes.\n4. Close Godot editor\n5. Open a terminal with Git and run this command: $ git status. You should see that some files were modified (by Godot editor).\n6. Run this command: $ git restore\n7. Open the game project in the Godot editor again.\n8. Wait for Godot editor to import assets. This time, there should be no errors.\n9. Run this command again: $ git status. There should be no local changes if steps were followed correctly.\n\nNote: Public version of assets contains censored versions of item icons, tower icons and tower sprites. Such assets will look like they are a solid \"blue\" color.\n\n## Copyright / Contributor License Agreement\nAny code you submit will become part of the repository and be distributed under the YouTD2 license. By submitting code to the project you agree that the code is your work and you can give it to the project.\n\nYou also agree by submitting your code that you grant all transferrable rights to the code to the project maintainer, including for example re-licensing the code, modifying the code, and distributing it in source or binary forms. Specifically, this includes a requirement that you assign copyright to the project maintainer. For this reason, do not modify any copyright statements in files in any PRs.\n"
  },
  {
    "path": ".github/RCLONE.md",
    "content": "# Setup rclone\n\nRclone is an advanced way to sync assets between your computer and google drive.\n\nNote that if you're using the public version of assets (assets_public), you can ignore this page and manually download files from drive.\n\n## Setup steps\n\n1. Install rclone from [here](https://rclone.org/downloads/).\n2. Go to this [page](https://console.cloud.google.com/apis/credentials/oauthclient/909699965518-qt5c21qf6r7mr3rg26vkh6nml4s397e7.apps.googleusercontent.com?project=youtd2-385722). Copy and save `client_id` and `client_secret` to a text file. You will need them in the next step.\n3. Follow the instructions [here](https://rclone.org/drive/) to configure `rcloud`. When prompted for `client_id` and `client_secret`, use the strings you have copied in the previous step.\n4. Check that the remote is installed correctly. This command will print the installed `<remote>`.\n```\nrclone listremotes\n```\n5. This command should print the list of folders insides assets in Google Drive.\n```\nrclone lsd <remote>:assets\n```\n6. Transfer files to your local.\n```\nrclone sync -P --filter-from rclone-filter \"<remote>:assets\" \"assets\"\n```\n\nNow you should be able to run the project inside the Godot editor. If you make changes to a file inside assets folder, make sure to update Google Drive as well. There are two options.\n\n**First option - Google Drive upload.**\n\n1. Upload a file to [Google Drive](https://drive.google.com/drive/u/1/folders/1V9GN1uoX9-mu2J5IoWPaNJU2aC_ejGIA)\n2. Run `rclone sync`\n3. Generate `.import` by opening the file in the editor\n4. Commit `.import` file to remote\n\n**Second option - rclone copy.**\n1. Move a file to `assets` folder\n2. Generate `.import` by opening the file in the editor\n3. Commit `.import` file to remote\n4. Upload the file to <remote>.\n```\nrclone copy -v --filter-from rclone-filter assets <remote>:assets\n```\n"
  },
  {
    "path": ".github/TRANSLATING.md",
    "content": "# Translation guidance\n\n## How to contribute to translation\n\nTranslated text strings are stored in texts.csv. This file is not included on Github because it is too big.\nDownload link: [texts.csv](https://drive.google.com/file/d/1dfaUKx5CoU9oVQQ4DgFVJH_twJ7M5k4Q/view?usp=drive_link).\n\nYou can contribute translations like this:\n1. Download the texts.csv file\n2. Edit the texts.csv file\n3. Create new column for your language, for example \"es\"\n4. Add translated strings to that column\n\nThen you can submit the changes like this:\n1. Create a new Issue on Github\n2. Attach changed texts.csv file to the Issue\n3. Follow the format from here: https://github.com/Praytic/youtd2/issues/483\n\n## How to add a new language\n\nThis section is intended for developers. If you only want to contribute new translation texts, you can skip this section and let someone else handle adding the new language.\n\n1. Find the locale code here: https://docs.godotengine.org/en/stable/tutorials/i18n/locales.html\n2. Create new column in texts.csv with locale code in first row.\n3. Close texts.csv and open Godot editor, confirm in editor log that texts.csv was reloaded.\n4. Go to Menubar -> Project -> Project Settings -> Localization -> Add. Then add the translation file.\n5. Edit src/enums/language.gd. Add new language to the following: \"enm\", \"language_map\", \"language_option_map\", \"language_option_locale_map\"\n6. Open settings_menu.tscn in editor and modify the language OptionButton. Add new language and use the same index as the one in language.gd.\n7. Start the game and confirm that new language works.\n"
  },
  {
    "path": ".github/workflows/github-actions-youtd.yml",
    "content": "name: build-and-publish\n\n# NOTE: disabled this export job because it doesn't work\n# with webrtc lib. Webrtc lib files need to be included\n# together with the game but this job for some reason fails\n# to do it. It only adds executable and .pck file to the\n# zip.\n\n# on:\n#   push:\n#     # Sequence of patterns matched against refs/heads\n#     # branches:\n#     #   - workflow*\n#     # Sequence of patterns matched against refs/tags\n#     tags:\n#       - v*\n\njobs:\n  setup:\n    runs-on: ubuntu-latest\n    name: cache repo with assets\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: list assets in gdrive\n      uses: wei/rclone@v1\n      with:\n        args: lsf -R --filter-from rclone-filter \"assets\" | sort > .assets-list\n      env:\n        RCLONE_CONF: ${{ secrets.RCLONE_GDRIVE_CONF }}\n\n    - name: restore cache\n      uses: actions/cache@v3\n      with:\n        path: assets\n        key: assets-${{ hashFiles('.assets-list') }}\n\n    - name: sync assets from gdrive via rclone\n      uses: wei/rclone@v1\n      with:\n        args: sync -P --filter-from rclone-filter \"gdrive:assets\" \"assets\"\n      env:\n        RCLONE_CONF: ${{ secrets.RCLONE_GDRIVE_CONF }}\n\n    - name: upload repo with assets\n      id: upload_repo_with_assets\n      uses: actions/upload-artifact@v3\n      with:\n        path: |\n          ./*\n          !.git/\n        name: repo-with-assets\n\n    - name: generate version for the build\n      id: version_generation\n      run: |\n        latest_tag=$(git ls-remote --tags --sort=-v:refname origin | grep -v 'vrefs/heads/main' | grep -o 'refs/tags/[^^{]*' | sed 's/refs\\/tags\\///' | head -n 1)\n        short_hash=$(git rev-parse --short HEAD)\n        version=${latest_tag:1}\n        echo \"tag_version=${latest_tag}-${short_hash}\" | tee -a $GITHUB_OUTPUT\n        echo \"version=${version}\" | tee -a $GITHUB_OUTPUT\n        echo \"commit_ref=$GITHUB_REF_NAME\" | tee -a $GITHUB_OUTPUT\n\n    outputs:\n      tag_version: ${{ steps.version_generation.outputs.tag_version }}\n      version: ${{ steps.version_generation.outputs.version }}\n      commit_ref: ${{ steps.version_generation.outputs.commit_ref }}\n\n  export_game:\n    runs-on: ubuntu-latest\n    needs: setup\n    name: export game\n    steps:\n    - name: download repo with assets\n      uses: actions/download-artifact@v3\n      with:\n        path: ./\n        name: repo-with-assets\n\n    - name: release requested check\n      run: |\n        if [[ ${{ needs.setup.outputs.commit_ref }} =~ ^v[0-9]+\\.[0-9]+\\.[0-9]+$ ]] ; then\n            echo \"NEED=true\" >> \"$GITHUB_ENV\"\n            echo 'true'\n        else\n            echo \"NEED=false\" >> \"$GITHUB_ENV\"\n            echo 'false'\n        fi\n\n    - name: update project.godot with new version\n      run: |\n        project_godot_file=\"${{ github.workspace }}/project.godot\"\n        sed -i 's/\\(config\\/version=\"\\).*\\(\"\\)/\\1'\"${{ needs.setup.outputs.tag_version }}\"'\\2/' \"${project_godot_file}\"\n        echo \"New project.godot contents:\"\n        cat \"${project_godot_file}\"\n\n    - name: update release version for Sentry lib\n      run: |\n        sed -i \"s/youtd2@[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+/youtd2@${{ needs.setup.outputs.version }}/g\" \"${{ github.workspace }}/build/web/full-size.html\"\n\n    - name: create .godot dirs\n      run: |\n        mkdir -p .godot/{editor,imported}\n\n    - name: export game\n      id: export\n      uses: firebelley/godot-export@v5.2.0\n      with:\n        godot_executable_download_url: https://github.com/godotengine/godot-builds/releases/download/4.1.3-stable/Godot_v4.1.3-stable_linux.x86_64.zip\n        godot_export_templates_download_url: https://github.com/godotengine/godot-builds/releases/download/4.1.3-stable/Godot_v4.1.3-stable_export_templates.tpz\n        relative_project_path: ./\n        export_debug: false\n        archive_output: true\n        cache: true\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: repack web artifact\n      run: |\n        zip -uj ${{ steps.export.outputs.archive_directory }}/web.zip ${{ github.workspace }}/build/web/*\n        cp ${{ github.workspace }}/build/web/* ${{ steps.export.outputs.build_directory }}/web/\n\n    - uses: actions/upload-artifact@v3\n      with:\n        name: youtd-${{ needs.setup.outputs.tag_version }}\n        path: ${{ steps.export.outputs.archive_directory }}/*.zip\n        if-no-files-found: error\n\n    outputs:\n      tag_version: ${{ needs.setup.outputs.tag_version }}\n      commit_ref: ${{ needs.setup.outputs.commit_ref }}\n      release_flag: ${{ env.NEED }}\n\n  upload_artifacts:\n    needs: export_game\n    strategy:\n      matrix:\n        platform: [windows, macos, web, linux]\n    runs-on: ubuntu-latest\n    steps:\n    - name: download exported files\n      uses: actions/download-artifact@v3\n      with:\n        name: youtd-${{ needs.export_game.outputs.tag_version }}\n        path: exported_files\n\n    - name: rename artifacts\n      id: rename_artifacts\n      run: |\n        VERSION_TAG=\"${{ needs.export_game.outputs.tag_version }}\"\n        mv \"exported_files/${{ matrix.platform }}.zip\" \"exported_files/${{ matrix.platform }}-$VERSION_TAG.zip\"\n        echo \"${{ matrix.platform }}=exported_files/$platform-$VERSION_TAG.zip\" >> $GITHUB_OUTPUT\n\n    - name: upload artifacts\n      id: upload_artifacts\n      uses: actions/upload-artifact@v3\n      with:\n        name: ${{ matrix.platform }}-${{ needs.export_game.outputs.tag_version }}\n        path: exported_files/${{ matrix.platform }}-${{ needs.export_game.outputs.tag_version }}.zip\n\n    outputs:\n      macos_artifact: ${{ steps.rename_artifacts.outputs.macos_artifact }}\n      linux_artifact: ${{ steps.rename_artifacts.outputs.linux_artifact }}\n      web_artifact: ${{ steps.rename_artifacts.outputs.web_artifact }}\n      windows_artifact: ${{ steps.rename_artifacts.outputs.windows_artifact }}\n\n  create_release:\n    name: create release\n    needs: [upload_artifacts, export_game]\n    if: needs.export_game.outputs.release_flag == 'true'\n    runs-on: ubuntu-latest\n    steps:\n      - name: show props\n        run: |\n          echo \"Commit ref: $GITHUB_REF_NAME\"\n          echo \"Release tag: ${{ needs.export_game.outputs.commit_ref }}\"\n\n      - name: download artifacts\n        uses: actions/download-artifact@v3\n        with:\n          path: .\n\n      - name: display structure of downloaded files\n        run: ls -R\n        working-directory: .\n\n      - name: release client\n        uses: ncipollo/release-action@v1.11.2\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          tag: ${{ needs.export_game.outputs.commit_ref }}\n          generateReleaseNotes: true\n          artifacts: ./**/*.zip\n\n  clean_up_artifacts:\n    needs: [create_release, export_game]\n    runs-on: ubuntu-latest\n    steps:\n      - uses: geekyeggo/delete-artifact@v2\n        with:\n          name: |\n            youtd-${{ needs.export_game.outputs.tag_version }}\n            repo-with-assets\n"
  },
  {
    "path": ".gitignore",
    "content": "# Godot .gitignore config\n#\n# Aims to encompass the most commonly found files that we don't want committed\n# to Git, such as compilation output, IDE specific files, etc.\n#\n# It doesn't cover *all* thirdparty IDE extensions under the sun so if you have\n# specific needs covered here, you can add them to:\n#   .git/info/exclude\n#\n# Or contribute them to this file if they're common enough that a good number of\n# users would benefit from the shared rules.\n#\n# This file is organized by sections, with subsections ordered alphabetically.\n# - Build configuration\n# - Godot generated files\n# - General build output\n# - IDE and tool specific\n# - Visual Studio specific\n# - OS specific\n\n###########################\n### Build configuration ###\n###########################\n\n/custom.py\nmisc/hooks/pre-commit-custom-*\n\n#############################\n### Godot generated files ###\n#############################\n\n# Buildsystem\nbin/\n*.gen.*\ncompile_commands.json\nplatform/windows/godot_res.res\n\n# Generated by Godot binary\n.import/\n.godot/\n/gdnative_interface.h\nextension_api.json\nlogs/\n*.translation\n\n# Generated by unit tests\ntests/data/*.translation\n\n############################\n### General build output ###\n############################\n\n# C/C++ generated\n*.a\n*.ax\n*.d\n*.dll\n*.lib\n*.lo\n*.o\n*.os\n*.ox\n*.Plo\n*.so\n# Binutils tmp linker output of the form \"stXXXXXX\" where \"X\" is alphanumeric\nst[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]\n\n# Python generated\n__pycache__/\n*.pyc\n\n# Documentation\ndoc/_build/\n\n# Android\n.gradle/\nlocal.properties\n*.iml\n.gradletasknamecache\nproject.properties\nplatform/android/java/*/.cxx/\nplatform/android/java/*/build/\nplatform/android/java/*/libs/\n\n# iOS\n*.dSYM\n\n# Web platform\n*.bc\nplatform/web/node_modules/\n\n# Misc\n*.debug\n\n#############################\n### IDE and tool specific ###\n#############################\n\n# Automake\n.deps/*\n.dirstamp\n\n# ccls\n.ccls-cache/\n\n# clangd\n.clangd/\n.cache/\n\n# CLion\ncmake-build-debug\n\n# Code::Blocks\n*.cbp\n*.layout\n*.depend\n\n# CodeLite\n*.project\n*.workspace\n.codelite/\n\n# Cppcheck\n*.cppcheck\ncppcheck-cppcheck-build-dir/\n\n# Eclipse CDT\n.cproject\n.settings/\n*.pydevproject\n*.launch\n\n# Gcov and Lcov code coverage\n*.gcno\n*.gcda\n*.gcov.html\n*.func.html\n*.func-sort-c.html\n*index-sort-f.html\n*index-sort-l.html\n*index.html\ngodot.info\namber.png\nemerald.png\nglass.png\nruby.png\nsnow.png\nupdown.png\ngcov.css\n\n# Geany\n*.geany\n.geanyprj\n\n# Gprof\ngmon.out\n\n# Jetbrains IDEs\n.idea/\n.fleet/\n\n# Kate\n*.kate-swp\n\n# Kdevelop\n*.kdev4\n\n# Qt Creator\n*.config\n*.creator\n*.creator.*\n*.files\n*.includes\n*.cflags\n*.cxxflags\n\n# SCons\n.sconf_temp\n.sconsign*.dblite\n.scons_env.json\n.scons_node_count\n\n# Sourcetrail\n*.srctrl*\n\n# Tags\n# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore\n# Ignore tags created by etags, ctags, gtags (GNU global) and cscope\nTAGS\n!TAGS/\ntags\n*.tags\n!tags/\ngtags.files\nGTAGS\nGRTAGS\nGPATH\ncscope.files\ncscope.out\ncscope.in.out\ncscope.po.out\n\n# Vim\n*.swo\n*.swp\n\n# Visual Studio Code\n.vscode/\n*.code-workspace\n.history/\n\n# Xcode\nxcuserdata/\n*.xcscmblueprint\n*.xccheckout\n*.xcodeproj/*\n\n##############################\n### Visual Studio specific ###\n##############################\n\n# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n# Ignore Visual Studio temporary files, build results, and\n# files generated by popular Visual Studio add-ons.\n\n# Actual VS project files we don't use\n*.sln\n*.vcxproj*\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Ww][Ii][Nn]32/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.tlog\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n\n# Others\nClientBin/\nenc_temp_folder/\n~$*\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# Hint file for IntelliSense\ncpp.hint\n\n###################\n### OS specific ###\n###################\n\n# Linux\n*~\n.directory\n\n# macOS\n.DS_Store\n__MACOSX\n\n# Windows\n# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore\n[Tt]humbs.db\n[Tt]humbs.db:encryptable\nehthumbs.db\nehthumbs_vista.db\n*.stackdump\n[Dd]esktop.ini\n$RECYCLE.BIN/\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n*.lnk\n\n\n########################\n### Project specific ###\n########################\n\n/build/windows/YouTD2.zip\n/build/linux/YouTD2.zip\n/build/macos/YouTD2.zip\n/build/web/*\n!/build/README.md\n!/build/web/full-size.html\n!/build/web/loading_screen.mp4\n!/build/web/loading_screen.png\noverride.cfg\n/webrtc/*\n!/webrtc/README.md\n\n#######################\n### Assets specific ###\n#######################\n\n# Archives\n*.7z\n*.br\n*.gz\n*.tar\n*.zip\n\n# Documents\n*.pdf\n\n# Images\n*.gif\n*.ico\n*.jpg\n*.png\n*.psd\n*.webp\n\n# Fonts\n*.woff2\n*.otf\n*.ttf\n\n# Audio\n*.mp3\n*.wav\n*.ogg\n\n# Other\n*.exe\n/assets/secrets/secrets.csv\n/assets/secrets/badwords.csv\n/assets/texts/texts.csv\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 Icob2Games\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# YouTD 2\n\n![youtd2_logo](https://github.com/user-attachments/assets/ea8a358b-aa12-4d28-9fc5-861bf8d2c497)\n\nYouTD 2 is a remake of the tower defense mod \"YouTD\" from WC3.\n\n_[itch.io](https://praytic.itch.io/youtd2)_  \n_[Discord](https://discord.gg/EksA2CfCS9)_  \n\n## Contributing\nSee [CONTRIBUTING.md](.github/CONTRIBUTING.md).\n\n## Matchmaking server\n\nRepository for matchmaking server is [here](https://github.com/Kvel2D/youtd2-server).\n\n## Credits\n\nDeveloped by [Dmitry Degtyarev](https://github.com/Kvel2D), [Praytic](https://github.com/Praytic) and every direct and indirect [contributors](https://github.com/Praytic/youtd2/graphs/contributors) to the GitHub.\n\nBased on \"YouTD\" - a WC3 mod created by geX and the YouTD community.\n\nAlso thank you to everyone posting feedback and questions on YouTD2 Discord.\n\n## License\n\nYouTD 2 source code is licensed under the [MIT licence](https://github.com/Praytic/youtd2/tree/main?tab=MIT-1-ov-file#readme).\n\nAssets files are licensed under [CC-BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/legalcode).\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Nakama.gd",
    "content": "@tool\nextends Node\n\n# The default host address of the server.\nconst DEFAULT_HOST : String = \"127.0.0.1\"\n\n# The default port number of the server.\nconst DEFAULT_PORT : int = 7350\n\n# The default timeout for the connections.\nconst DEFAULT_TIMEOUT = 3\n\n# The default protocol scheme for the client connection.\nconst DEFAULT_CLIENT_SCHEME : String = \"http\"\n\n# The default protocol scheme for the socket connection.\nconst DEFAULT_SOCKET_SCHEME : String = \"ws\"\n\n# The default log level for the Nakama logger.\nconst DEFAULT_LOG_LEVEL = NakamaLogger.LOG_LEVEL.DEBUG\n\nvar _http_adapter = null\nvar logger = NakamaLogger.new()\n\nfunc _ready() -> void:\n\tprocess_mode = Node.PROCESS_MODE_ALWAYS\n\nfunc get_client_adapter() -> NakamaHTTPAdapter:\n\tif _http_adapter == null:\n\t\t_http_adapter = NakamaHTTPAdapter.new()\n\t\t_http_adapter.logger = logger\n\t\t_http_adapter.name = \"NakamaHTTPAdapter\"\n\t\tadd_child(_http_adapter)\n\treturn _http_adapter\n\nfunc create_socket_adapter() -> NakamaSocketAdapter:\n\tvar adapter = NakamaSocketAdapter.new()\n\tadapter.name = \"NakamaWebSocketAdapter\"\n\tadapter.logger = logger\n\tadd_child(adapter)\n\treturn adapter\n\nfunc create_client(p_server_key : String,\n\t\tp_host : String = DEFAULT_HOST,\n\t\tp_port : int = DEFAULT_PORT,\n\t\tp_scheme : String = DEFAULT_CLIENT_SCHEME,\n\t\tp_timeout : int = DEFAULT_TIMEOUT,\n\t\tp_log_level : int = DEFAULT_LOG_LEVEL) -> NakamaClient:\n\tlogger._level = p_log_level\n\treturn NakamaClient.new(get_client_adapter(), p_server_key, p_scheme, p_host, p_port, p_timeout)\n\nfunc create_socket(p_host : String = DEFAULT_HOST,\n\t\tp_port : int = DEFAULT_PORT,\n\t\tp_scheme : String = DEFAULT_SOCKET_SCHEME) -> NakamaSocket:\n\treturn NakamaSocket.new(create_socket_adapter(), p_host, p_port, p_scheme, true)\n\nfunc create_socket_from(p_client : NakamaClient) -> NakamaSocket:\n\tvar scheme = \"ws\"\n\tif p_client.scheme == \"https\":\n\t\tscheme = \"wss\"\n\treturn NakamaSocket.new(create_socket_adapter(), p_client.host, p_client.port, scheme, true)\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/NakamaEvent.gd",
    "content": "extends SatoriAsyncResult\n\n# NOTE: renamed from original \"Event\" to avoid name conflicts\nclass_name NakamaEvent\n\n# The name of the event.\nvar name: String\n\n# The time when the event was triggered.\nvar timestamp: String\n\n# Optional value.\nvar value: String\n\n# NakamaEvent metadata, if any.\nvar metadata: Dictionary\n\n# Optional event ID assigned by the client, used to de-duplicate in retransmission scenarios.\n# If not supplied the server will assign a randomly generated unique event identifier.\nvar id: String\n\n# The event constructor.\n # Initializes a new NakamaEvent object.\n #\n # @param name The name of the event.\n # @param timestamp The timestamp of the event.\n # @param value The value associated with the event (optional).\n # @param metadata The metadata associated with the event (optional).\n # @param id The ID of the event (optional).\nfunc _init(name: String, timestamp: float, value: String = \"\", metadata: Dictionary = {}, id: String = \"\", p_exception = null):\n\tsuper(p_exception)\n\t\n\tself.name = name\n\tself.timestamp = unix_to_protobuf_timestamp_format(timestamp)\n\tself.value = value\n\tself.metadata = metadata\n\tself.id = id\n\nfunc to_api_event_dict() -> Dictionary:\n\treturn {\n\t\t\"name\": self.name,\n\t\t\"timestamp\": self.timestamp,\n\t\t\"value\": self.value,\n\t\t\"metadata\": self.metadata,\n\t\t\"id\": self.id\n\t}\n\nfunc unix_to_protobuf_timestamp_format(unix_time: float) -> String:\n\t# Extract microseconds precision from unix time\n\tvar microseconds = int(fmod(unix_time, 1.0) * 1_000_000)\n\t\n\t# Convert seconds to datetime structure\n\tvar datetime = Time.get_datetime_dict_from_unix_time(int(unix_time))\n\t\n\tvar year = datetime.year\n\tvar month = str(datetime.month).pad_zeros(2)\n\tvar day = str(datetime.day).pad_zeros(2)\n\tvar hour = str(datetime.hour).pad_zeros(2)\n\tvar minute = str(datetime.minute).pad_zeros(2)\n\tvar second = str(datetime.second).pad_zeros(2)\n\tvar microsecond = str(microseconds).pad_zeros(6)\n\n\t# Construct the protobuf timestamp format string\n\tvar timestamp_str = \"%s-%s-%sT%s:%s:%s.%sZ\" % [year, month, day, hour, minute, second, microsecond]\n\t\n\treturn timestamp_str\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/SatoriAPI.gd",
    "content": "### Code generated by codegen/main.go. DO NOT EDIT. ###\n\nextends RefCounted\nclass_name SatoriAPI\n\n# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.\nclass ApiAuthenticateLogoutRequest extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"refresh_token\": {\"name\": \"_refresh_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Refresh token to invalidate.\n\tvar _refresh_token\n\tvar refresh_token : String:\n\t\tget:\n\t\t\treturn \"\" if not _refresh_token is String else String(_refresh_token)\n\t\n\t# Session token to log out.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAuthenticateLogoutRequest:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiAuthenticateLogoutRequest\", p_dict), ApiAuthenticateLogoutRequest) as ApiAuthenticateLogoutRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"refresh_token: %s, \" % _refresh_token\n\t\toutput += \"token: %s, \" % _token\n\t\toutput += map_string\n\t\treturn output\n\n# Authenticate against the server with a refresh token.\nclass ApiAuthenticateRefreshRequest extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"refresh_token\": {\"name\": \"_refresh_token\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Refresh token.\n\tvar _refresh_token\n\tvar refresh_token : String:\n\t\tget:\n\t\t\treturn \"\" if not _refresh_token is String else String(_refresh_token)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAuthenticateRefreshRequest:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiAuthenticateRefreshRequest\", p_dict), ApiAuthenticateRefreshRequest) as ApiAuthenticateRefreshRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"refresh_token: %s, \" % _refresh_token\n\t\toutput += map_string\n\t\treturn output\n\n# \nclass ApiAuthenticateRequest extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"custom\": {\"name\": \"_custom\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"default\": {\"name\": \"_default\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Optional custom properties to update with this call.\n\t# If not set, properties are left as they are on the server.\n\tvar _custom\n\tvar custom : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _custom is Dictionary else _custom.duplicate()\n\t\n\t# Optional default properties to update with this call.\n\t# If not set, properties are left as they are on the server.\n\tvar _default\n\tvar default : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _default is Dictionary else _default.duplicate()\n\t\n\t# Identity ID. Must be between eight and 128 characters (inclusive).\n\t# Must be an alphanumeric string with only underscores and hyphens allowed.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAuthenticateRequest:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiAuthenticateRequest\", p_dict), ApiAuthenticateRequest) as ApiAuthenticateRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_custom) == TYPE_DICTIONARY:\n\t\t\tfor k in _custom:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _custom[k]]\n\t\toutput += \"custom: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\tif typeof(_default) == TYPE_DICTIONARY:\n\t\t\tfor k in _default:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _default[k]]\n\t\toutput += \"default: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += map_string\n\t\treturn output\n\n# A single event. Usually, but not necessarily, part of a batch.\nclass ApiEvent extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"timestamp\": {\"name\": \"_timestamp\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Optional event ID assigned by the client, used to de-duplicate in retransmission scenarios.\n\t# If not supplied the server will assign a randomly generated unique event identifier.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\t\n\t# Event metadata, if any.\n\tvar _metadata\n\tvar metadata : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _metadata is Dictionary else _metadata.duplicate()\n\t\n\t# Event name.\n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\t\n\t# The time when the event was triggered on the producer side.\n\tvar _timestamp\n\tvar timestamp : String:\n\t\tget:\n\t\t\treturn \"\" if not _timestamp is String else String(_timestamp)\n\t\n\t# Optional value.\n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiEvent:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiEvent\", p_dict), ApiEvent) as ApiEvent\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"id: %s, \" % _id\n\t\tif typeof(_metadata) == TYPE_DICTIONARY:\n\t\t\tfor k in _metadata:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _metadata[k]]\n\t\toutput += \"metadata: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"timestamp: %s, \" % _timestamp\n\t\toutput += \"value: %s, \" % _value\n\t\toutput += map_string\n\t\treturn output\n\n# \nclass ApiEventRequest extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"events\": {\"name\": \"_events\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": TYPE_DICTIONARY},\n\t}\n\t\n\t# Some number of events produced by a client.\n\tvar _events\n\tvar events : Array:\n\t\tget:\n\t\t\treturn Array() if not _events is Array else Array(_events)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiEventRequest:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiEventRequest\", p_dict), ApiEventRequest) as ApiEventRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"events: %s, \" % [_events]\n\t\toutput += map_string\n\t\treturn output\n\n# An experiment that this user is partaking.\nclass ApiExperiment extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# \n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\t\n\t# Value associated with this Experiment.\n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiExperiment:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiExperiment\", p_dict), ApiExperiment) as ApiExperiment\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"value: %s, \" % _value\n\t\toutput += map_string\n\t\treturn output\n\n# All experiments that this identity is involved with.\nclass ApiExperimentList extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"experiments\": {\"name\": \"_experiments\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": TYPE_DICTIONARY},\n\t}\n\t\n\t# All experiments for this identity.\n\tvar _experiments\n\tvar experiments : Array:\n\t\tget:\n\t\t\treturn Array() if not _experiments is Array else Array(_experiments)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiExperimentList:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiExperimentList\", p_dict), ApiExperimentList) as ApiExperimentList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"experiments: %s, \" % [_experiments]\n\t\toutput += map_string\n\t\treturn output\n\n# Feature flag available to the identity.\nclass ApiFlag extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"condition_changed\": {\"name\": \"_condition_changed\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Whether the value for this flag has conditionally changed from the default state.\n\tvar _condition_changed\n\tvar condition_changed : bool:\n\t\tget:\n\t\t\treturn false if not _condition_changed is bool else bool(_condition_changed)\n\t\n\t# \n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\t\n\t# Value associated with this flag.\n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFlag:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiFlag\", p_dict), ApiFlag) as ApiFlag\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"condition_changed: %s, \" % _condition_changed\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"value: %s, \" % _value\n\t\toutput += map_string\n\t\treturn output\n\n# \nclass ApiFlagList extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"flags\": {\"name\": \"_flags\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": TYPE_DICTIONARY},\n\t}\n\t\n\t# \n\tvar _flags\n\tvar flags : Array:\n\t\tget:\n\t\t\treturn Array() if not _flags is Array else Array(_flags)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFlagList:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiFlagList\", p_dict), ApiFlagList) as ApiFlagList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"flags: %s, \" % [_flags]\n\t\toutput += map_string\n\t\treturn output\n\n# A response containing all the messages for an identity.\nclass ApiGetMessageListResponse extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cacheable_cursor\": {\"name\": \"_cacheable_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"messages\": {\"name\": \"_messages\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": TYPE_DICTIONARY},\n\t\t\"next_cursor\": {\"name\": \"_next_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"prev_cursor\": {\"name\": \"_prev_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Cacheable cursor to list newer messages. Durable and designed to be stored, unlike next/prev cursors.\n\tvar _cacheable_cursor\n\tvar cacheable_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cacheable_cursor is String else String(_cacheable_cursor)\n\t\n\t# The list of messages.\n\tvar _messages\n\tvar messages : Array:\n\t\tget:\n\t\t\treturn Array() if not _messages is Array else Array(_messages)\n\t\n\t# The cursor to send when retrieving the next page, if any.\n\tvar _next_cursor\n\tvar next_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _next_cursor is String else String(_next_cursor)\n\t\n\t# The cursor to send when retrieving the previous page, if any.\n\tvar _prev_cursor\n\tvar prev_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _prev_cursor is String else String(_prev_cursor)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGetMessageListResponse:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiGetMessageListResponse\", p_dict), ApiGetMessageListResponse) as ApiGetMessageListResponse\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"cacheable_cursor: %s, \" % _cacheable_cursor\n\t\toutput += \"messages: %s, \" % [_messages]\n\t\toutput += \"next_cursor: %s, \" % _next_cursor\n\t\toutput += \"prev_cursor: %s, \" % _prev_cursor\n\t\toutput += map_string\n\t\treturn output\n\n# Enrich/replace the current session with a new ID.\nclass ApiIdentifyRequest extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"custom\": {\"name\": \"_custom\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"default\": {\"name\": \"_default\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Optional custom properties to update with this call.\n\t# If not set, properties are left as they are on the server.\n\tvar _custom\n\tvar custom : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _custom is Dictionary else _custom.duplicate()\n\t\n\t# Optional default properties to update with this call.\n\t# If not set, properties are left as they are on the server.\n\tvar _default\n\tvar default : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _default is Dictionary else _default.duplicate()\n\t\n\t# Identity ID to enrich the current session and return a new session. Old session will no longer be usable.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiIdentifyRequest:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiIdentifyRequest\", p_dict), ApiIdentifyRequest) as ApiIdentifyRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_custom) == TYPE_DICTIONARY:\n\t\t\tfor k in _custom:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _custom[k]]\n\t\toutput += \"custom: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\tif typeof(_default) == TYPE_DICTIONARY:\n\t\t\tfor k in _default:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _default[k]]\n\t\toutput += \"default: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += map_string\n\t\treturn output\n\n# A single live event.\nclass ApiLiveEvent extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"active_end_time_sec\": {\"name\": \"_active_end_time_sec\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"active_start_time_sec\": {\"name\": \"_active_start_time_sec\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"description\": {\"name\": \"_description\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# End time of current event run.\n\tvar _active_end_time_sec\n\tvar active_end_time_sec : String:\n\t\tget:\n\t\t\treturn \"\" if not _active_end_time_sec is String else String(_active_end_time_sec)\n\t\n\t# Start time of current event run.\n\tvar _active_start_time_sec\n\tvar active_start_time_sec : String:\n\t\tget:\n\t\t\treturn \"\" if not _active_start_time_sec is String else String(_active_start_time_sec)\n\t\n\t# Description.\n\tvar _description\n\tvar description : String:\n\t\tget:\n\t\t\treturn \"\" if not _description is String else String(_description)\n\t\n\t# The live event identifier.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\t\n\t# Name.\n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\t\n\t# Event value.\n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLiveEvent:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiLiveEvent\", p_dict), ApiLiveEvent) as ApiLiveEvent\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"active_end_time_sec: %s, \" % _active_end_time_sec\n\t\toutput += \"active_start_time_sec: %s, \" % _active_start_time_sec\n\t\toutput += \"description: %s, \" % _description\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"value: %s, \" % _value\n\t\toutput += map_string\n\t\treturn output\n\n# List of Live events.\nclass ApiLiveEventList extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"live_events\": {\"name\": \"_live_events\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": TYPE_DICTIONARY},\n\t}\n\t\n\t# Live events.\n\tvar _live_events\n\tvar live_events : Array:\n\t\tget:\n\t\t\treturn Array() if not _live_events is Array else Array(_live_events)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLiveEventList:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiLiveEventList\", p_dict), ApiLiveEventList) as ApiLiveEventList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"live_events: %s, \" % [_live_events]\n\t\toutput += map_string\n\t\treturn output\n\n# A scheduled message.\nclass ApiMessage extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"consume_time\": {\"name\": \"_consume_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"read_time\": {\"name\": \"_read_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"schedule_id\": {\"name\": \"_schedule_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"send_time\": {\"name\": \"_send_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"text\": {\"name\": \"_text\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# The time the message was consumed by the identity.\n\tvar _consume_time\n\tvar consume_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _consume_time is String else String(_consume_time)\n\t\n\t# The time the message was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\t\n\t# A key-value pairs of metadata.\n\tvar _metadata\n\tvar metadata : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _metadata is Dictionary else _metadata.duplicate()\n\t\n\t# The time the message was read by the client.\n\tvar _read_time\n\tvar read_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _read_time is String else String(_read_time)\n\t\n\t# The identifier of the schedule.\n\tvar _schedule_id\n\tvar schedule_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _schedule_id is String else String(_schedule_id)\n\t\n\t# The send time for the message.\n\tvar _send_time\n\tvar send_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _send_time is String else String(_send_time)\n\t\n\t# The message's text.\n\tvar _text\n\tvar text : String:\n\t\tget:\n\t\t\treturn \"\" if not _text is String else String(_text)\n\t\n\t# The time the message was updated.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiMessage:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiMessage\", p_dict), ApiMessage) as ApiMessage\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"consume_time: %s, \" % _consume_time\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\tif typeof(_metadata) == TYPE_DICTIONARY:\n\t\t\tfor k in _metadata:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _metadata[k]]\n\t\toutput += \"metadata: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\toutput += \"read_time: %s, \" % _read_time\n\t\toutput += \"schedule_id: %s, \" % _schedule_id\n\t\toutput += \"send_time: %s, \" % _send_time\n\t\toutput += \"text: %s, \" % _text\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += map_string\n\t\treturn output\n\n# Properties associated with an identity.\nclass ApiProperties extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"computed\": {\"name\": \"_computed\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"custom\": {\"name\": \"_custom\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"default\": {\"name\": \"_default\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\t\n\t# Event computed properties.\n\tvar _computed\n\tvar computed : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _computed is Dictionary else _computed.duplicate()\n\t\n\t# Event custom properties.\n\tvar _custom\n\tvar custom : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _custom is Dictionary else _custom.duplicate()\n\t\n\t# Event default properties.\n\tvar _default\n\tvar default : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _default is Dictionary else _default.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiProperties:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiProperties\", p_dict), ApiProperties) as ApiProperties\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_computed) == TYPE_DICTIONARY:\n\t\t\tfor k in _computed:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _computed[k]]\n\t\toutput += \"computed: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\tif typeof(_custom) == TYPE_DICTIONARY:\n\t\t\tfor k in _custom:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _custom[k]]\n\t\toutput += \"custom: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\tif typeof(_default) == TYPE_DICTIONARY:\n\t\t\tfor k in _default:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _default[k]]\n\t\toutput += \"default: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\toutput += map_string\n\t\treturn output\n\n# A session.\nclass ApiSession extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"properties\": {\"name\": \"_properties\", \"type\": \"ApiProperties\", \"required\": false},\n\t\t\"refresh_token\": {\"name\": \"_refresh_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# Properties associated with this identity.\n\tvar _properties\n\tvar properties : ApiProperties:\n\t\tget:\n\t\t\treturn _properties as ApiProperties\n\t\n\t# Refresh token.\n\tvar _refresh_token\n\tvar refresh_token : String:\n\t\tget:\n\t\t\treturn \"\" if not _refresh_token is String else String(_refresh_token)\n\t\n\t# Token credential.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSession:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiSession\", p_dict), ApiSession) as ApiSession\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"properties: %s, \" % _properties\n\t\toutput += \"refresh_token: %s, \" % _refresh_token\n\t\toutput += \"token: %s, \" % _token\n\t\toutput += map_string\n\t\treturn output\n\n# Update Properties associated with this identity.\nclass ApiUpdatePropertiesRequest extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"custom\": {\"name\": \"_custom\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"default\": {\"name\": \"_default\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"recompute\": {\"name\": \"_recompute\", \"type\": TYPE_BOOL, \"required\": false},\n\t}\n\t\n\t# Event custom properties.\n\tvar _custom\n\tvar custom : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _custom is Dictionary else _custom.duplicate()\n\t\n\t# Event default properties.\n\tvar _default\n\tvar default : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _default is Dictionary else _default.duplicate()\n\t\n\t# Informs the server to recompute the audience membership of the identity.\n\tvar _recompute\n\tvar recompute : bool:\n\t\tget:\n\t\t\treturn false if not _recompute is bool else bool(_recompute)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUpdatePropertiesRequest:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ApiUpdatePropertiesRequest\", p_dict), ApiUpdatePropertiesRequest) as ApiUpdatePropertiesRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_custom) == TYPE_DICTIONARY:\n\t\t\tfor k in _custom:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _custom[k]]\n\t\toutput += \"custom: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\tif typeof(_default) == TYPE_DICTIONARY:\n\t\t\tfor k in _default:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _default[k]]\n\t\toutput += \"default: [%s], \" % map_string\n\t\tmap_string = \"\"\n\t\toutput += \"recompute: %s, \" % _recompute\n\t\toutput += map_string\n\t\treturn output\n\n# \nclass ProtobufAny extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"type\": {\"name\": \"_type\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# \n\tvar _type\n\tvar type : String:\n\t\tget:\n\t\t\treturn \"\" if not _type is String else String(_type)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ProtobufAny:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"ProtobufAny\", p_dict), ProtobufAny) as ProtobufAny\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"type: %s, \" % _type\n\t\toutput += map_string\n\t\treturn output\n\n# \nclass RpcStatus extends SatoriAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"code\": {\"name\": \"_code\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"details\": {\"name\": \"_details\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": TYPE_DICTIONARY},\n\t\t\"message\": {\"name\": \"_message\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\t\n\t# \n\tvar _code\n\tvar code : int:\n\t\tget:\n\t\t\treturn 0 if not _code is int else int(_code)\n\t\n\t# \n\tvar _details\n\tvar details : Array:\n\t\tget:\n\t\t\treturn Array() if not _details is Array else Array(_details)\n\t\n\t# \n\tvar _message\n\tvar message : String:\n\t\tget:\n\t\t\treturn \"\" if not _message is String else String(_message)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> RpcStatus:\n\t\treturn _safe_ret(SatoriSerializer.deserialize(p_ns, \"RpcStatus\", p_dict), RpcStatus) as RpcStatus\n\n\tfunc serialize() -> Dictionary:\n\t\treturn SatoriSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\tvar map_string : String = \"\"\n\t\toutput += \"code: %s, \" % _code\n\t\toutput += \"details: %s, \" % [_details]\n\t\toutput += \"message: %s, \" % _message\n\t\toutput += map_string\n\t\treturn output\n\n# The low level client for the Satori API.\nclass ApiClient extends RefCounted:\n\n\tvar _base_uri : String\n\n\tvar _http_adapter\n\tvar _namespace : GDScript\n\tvar _server_key : String\n\tvar auto_refresh := true\n\tvar auto_refresh_time := 300\n\n\tvar auto_retry : bool:\n\t\tset(p_value):\n\t\t\t_http_adapter.auto_retry = p_value\n\t\tget:\n\t\t\treturn _http_adapter.auto_retry\n\n\tvar auto_retry_count : int:\n\t\tset(p_value):\n\t\t\t_http_adapter.auto_retry_count = p_value\n\t\tget:\n\t\t\treturn _http_adapter.auto_retry_count\n\n\tvar auto_retry_backoff_base : int:\n\t\tset(p_value):\n\t\t\t_http_adapter.auto_retry_backoff_base = p_value\n\t\tget:\n\t\t\treturn _http_adapter.auto_retry_backoff_base\n\n\tvar last_cancel_token:\n\t\tget:\n\t\t\treturn _http_adapter.get_last_token()\n\n\tfunc _init(p_base_uri : String, p_http_adapter, p_namespace : GDScript, p_server_key : String, p_timeout : int = 10):\n\t\t_base_uri = p_base_uri\n\t\t_http_adapter = p_http_adapter\n\t\t_http_adapter.timeout = p_timeout\n\t\t_namespace = p_namespace\n\t\t_server_key = p_server_key\n\n\t\t\n\tfunc _refresh_session(p_session : SatoriSession):\n\t\tif auto_refresh and p_session.is_valid() and p_session.refresh_token and not p_session.is_refresh_expired() and p_session.would_expire_in(auto_refresh_time):\n\t\t\tvar request = ApiAuthenticateRefreshRequest.new()\n\t\t\trequest._token = p_session.refresh_token\n\t\t\treturn await authenticate_refresh_async(_server_key, \"\", request)\n\t\treturn null\n\n\tfunc cancel_request(p_token):\n\t\tif p_token:\n\t\t\t_http_adapter.cancel_request(p_token)\n\n\t# A healthcheck which load balancers can use to check the service.\n\tfunc healthcheck_async(\n\t\tp_session : SatoriSession\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/healthcheck\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# A readycheck which load balancers can use to check the service.\n\tfunc readycheck_async(\n\t\tp_session : SatoriSession\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/readycheck\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# Authenticate against the server.\n\tfunc authenticate_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_body : ApiAuthenticateRequest\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v1/authenticate\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = SatoriSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.\n\tfunc authenticate_logout_async(\n\t\tp_session : SatoriSession\n\t\t, p_body : ApiAuthenticateLogoutRequest\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/authenticate/logout\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# Refresh a user's session using a refresh token retrieved from a previous authentication request.\n\tfunc authenticate_refresh_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_body : ApiAuthenticateRefreshRequest\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v1/authenticate/refresh\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = SatoriSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Publish an event for this session.\n\tfunc event_async(\n\t\tp_session : SatoriSession\n\t\t, p_body : ApiEventRequest\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/event\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# Get or list all available experiments for this identity.\n\tfunc get_experiments_async(\n\t\tp_session : SatoriSession\n\t\t, p_names = null # : array\n\t) -> ApiExperimentList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiExperimentList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/experiment\"\n\t\tvar query_params = \"\"\n\t\tif p_names != null:\n\t\t\tfor elem in p_names:\n\t\t\t\tquery_params += \"names=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiExperimentList.new(result)\n\t\tvar out : ApiExperimentList = SatoriSerializer.deserialize(_namespace, \"ApiExperimentList\", result)\n\t\treturn out\n\n\t# List all available flags for this identity.\n\tfunc get_flags_async(\n\t\tp_bearer_token : String\n\t\t, p_names = null # : array\n\t) -> ApiFlagList:\n\t\tvar urlpath : String = \"/v1/flag\"\n\t\tvar query_params = \"\"\n\t\tif p_names != null:\n\t\t\tfor elem in p_names:\n\t\t\t\tquery_params += \"names=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tif (p_bearer_token):\n\t\t\tvar header = \"Bearer %s\" % p_bearer_token\n\t\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiFlagList.new(result)\n\t\tvar out : ApiFlagList = SatoriSerializer.deserialize(_namespace, \"ApiFlagList\", result)\n\t\treturn out\n\n\t# Enrich/replace the current session with new identifier.\n\tfunc identify_async(\n\t\tp_session : SatoriSession\n\t\t, p_body : ApiIdentifyRequest\n\t) -> ApiSession:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiSession.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/identify\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = SatoriSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Delete the caller's identity and associated data.\n\tfunc delete_identity_async(\n\t\tp_session : SatoriSession\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/identity\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# List available live events.\n\tfunc get_live_events_async(\n\t\tp_session : SatoriSession\n\t\t, p_names = null # : array\n\t) -> ApiLiveEventList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiLiveEventList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/live-event\"\n\t\tvar query_params = \"\"\n\t\tif p_names != null:\n\t\t\tfor elem in p_names:\n\t\t\t\tquery_params += \"names=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiLiveEventList.new(result)\n\t\tvar out : ApiLiveEventList = SatoriSerializer.deserialize(_namespace, \"ApiLiveEventList\", result)\n\t\treturn out\n\n\t# Get the list of messages for the identity.\n\tfunc get_message_list_async(\n\t\tp_session : SatoriSession\n\t\t, p_limit = null # : integer\n\t\t, p_forward = null # : boolean\n\t\t, p_cursor = null # : string\n\t) -> ApiGetMessageListResponse:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiGetMessageListResponse.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/message\"\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_forward != null:\n\t\t\tquery_params += \"forward=%s&\" % str(bool(p_forward)).to_lower()\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % SatoriSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiGetMessageListResponse.new(result)\n\t\tvar out : ApiGetMessageListResponse = SatoriSerializer.deserialize(_namespace, \"ApiGetMessageListResponse\", result)\n\t\treturn out\n\n\t# Deletes a message for an identity.\n\tfunc delete_message_async(\n\t\tp_session : SatoriSession\n\t\t, p_id : String\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/message/{id}\"\n\t\turlpath = urlpath.replace(\"{id}\", SatoriSerializer.escape_http(p_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# Updates a message for an identity.\n\tfunc update_message_async(\n\t\tp_session : SatoriSession\n\t\t, p_id : String\n\t\t, p_body : \n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/message/{id}\"\n\t\turlpath = urlpath.replace(\"{id}\", SatoriSerializer.escape_http(p_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n\n\t# List properties associated with this identity.\n\tfunc list_properties_async(\n\t\tp_session : SatoriSession\n\t) -> ApiProperties:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiProperties.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/properties\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn ApiProperties.new(result)\n\t\tvar out : ApiProperties = SatoriSerializer.deserialize(_namespace, \"ApiProperties\", result)\n\t\treturn out\n\n\t# Update identity properties.\n\tfunc update_properties_async(\n\t\tp_session : SatoriSession\n\t\t, p_body : ApiUpdatePropertiesRequest\n\t) -> SatoriAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn SatoriAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v1/properties\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray = PackedByteArray()\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is SatoriException:\n\t\t\treturn SatoriAsyncResult.new(result)\n\t\treturn SatoriAsyncResult.new()\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/SatoriClient.gd",
    "content": "extends RefCounted\n\n## A client for the API in Satori Server.\nclass_name SatoriClient\n\n#region Properties\n\nvar _host\n## The host address of the server.\nvar host : String:\n\tget:\n\t\treturn _host\n\nvar _port\n## The port number of the server.\nvar port : int:\n\tget:\n\t\treturn _port\n\nvar _scheme\n## The protocol scheme used to connect with the server. Must be either \"http\" or \"https\".\nvar scheme : String:\n\tget:\n\t\treturn _scheme\n\n## The key used to authenticate with the server without a session.\nvar api_key : String\n\n## Set the timeout in seconds on requests sent to the server.\nvar timeout : int\n\nvar _api_client : SatoriAPI.ApiClient\n\nvar auto_refresh : bool = false:\n\tset(v):\n\t\tset_auto_refresh(v)\n\tget:\n\t\treturn get_auto_refresh()\n\nfunc get_auto_refresh():\n\treturn _api_client.auto_refresh\n\nfunc set_auto_refresh(p_value):\n\t_api_client.auto_refresh = p_value\n\n#endregion\n\n#region Initialization\n\nfunc _init(p_adapter : SatoriHTTPAdapter,\n\tp_api_key : String,\n\tp_scheme : String,\n\tp_host : String,\n\tp_port : int,\n\tp_timeout : int):\n\n\tapi_key = p_api_key\n\t_scheme = p_scheme\n\t_host = p_host\n\t_port = p_port\n\ttimeout = p_timeout\n\t_api_client = SatoriAPI.ApiClient.new(_scheme + \"://\" + _host + \":\" + str(_port), p_adapter, SatoriAPI, api_key, p_timeout)\n\n#endregion\n\n#region Client APIs\n\n## Authenticate against the server.\n## [p_id]: An optional user id.\n## [p_default_properties]: Optional default properties to update with this call.\n## If not set, properties are left as they are on the server.\n## [p_custom_properties]: Optional custom properties to update with this call.\n## If not set, properties are left as they are on the server.\nfunc authenticate_async(p_id: String, p_default_properties: Dictionary = {}, p_custom_properties: Dictionary = {}) -> SatoriSession:\n\treturn _parse_session(await _api_client.authenticate_async(api_key, \"\",\n\t\tSatoriAPI.ApiAuthenticateRequest.create(SatoriAPI, {\n\t\t\t\"id\": p_id,\n\t\t\t\"default\": p_default_properties,\n\t\t\t\"custom\": p_custom_properties\n\t\t})))\n\n## Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.\n## [p_session]: The session of the user.\nfunc authenticate_logout_async(p_session: SatoriSession) -> SatoriAsyncResult:\n\treturn await _api_client.authenticate_logout_async(p_session,\n\t\tSatoriAPI.ApiAuthenticateLogoutRequest.create(SatoriAPI, {\n\t\t\t\"refresh_token\": p_session.refresh_token,\n\t\t\t\"token\": p_session.token\n\t\t}))\n\n# Parses the Satori API session and returns a SatoriSession object.\nfunc _parse_session(p_session: SatoriAPI.ApiSession) -> SatoriSession:\n\tif p_session.is_exception():\n\t\treturn SatoriSession.new(null, null, p_session.get_exception())\n\t\n\treturn SatoriSession.new(p_session.token, p_session.refresh_token)\n\n## Refresh a user's session using a refresh token retrieved from a previous authentication request.\n## [p_sesison]: The session of the user.\nfunc session_refresh_async(p_session : SatoriSession) -> SatoriSession:\n\treturn _parse_session(await _api_client.authenticate_refresh_async(api_key, \"\",\n\t\tSatoriAPI.ApiAuthenticateRefreshRequest.create(SatoriAPI, {\n\t\t\t\"refresh_token\": p_session.refresh_token,\n\t\t})\n\t))\n\n## Send an event for this session.\n## [p_session]: The session of the user.\n## [p_event]: The event which will be sent.\nfunc event_async(p_session: SatoriSession, p_event: NakamaEvent) -> SatoriAsyncResult:\n\treturn await events_async(p_session, [\n\t\tp_event\n\t])\n\n## Send a batch of events for this session.\n## [p_session]: The session of the user.\n## [p_events]: The batch of events which will be sent.\nfunc events_async(p_session: SatoriSession, p_events: Array) -> SatoriAsyncResult:\n\tvar p_dict = {\n\t\t\"events\": p_events.map(func(e):\n\t\t\treturn e.to_api_event_dict())\n\t}\n\t\n\tvar req = SatoriAPI.ApiEventRequest.create(SatoriAPI, p_dict)\n\treturn await _api_client.event_async(p_session,\n\t\treq)\n\n## Get all experiments data.\n## [p_session]: The session of the user.\nfunc get_all_experiments_async(p_session: SatoriSession) -> SatoriAsyncResult:\n\treturn await _api_client.get_experiments_async(p_session)\n\n## Get specific experiments data.\n## [p_session]: The session of the user.\n## [p_names]: Experiment names.\nfunc get_experiments_async(p_session: SatoriSession, p_names: Array) -> SatoriAPI.ApiExperimentList:\n\treturn await _api_client.get_experiments_async(p_session, p_names)\n\n## Get a single flag for this identity.\n## This method will return the default value\n## specified and will not raise an exception if the network is unavailable\n## [p_session]: The session of the user.\n## [p_name]: The name of the flag.\n## [p_default]: The default value if the server is unreachable.\nfunc get_flag_async(p_session: SatoriSession, p_name: String, p_default: String = \"\") -> SatoriAPI.ApiFlag:\n\tvar p_names = [p_name]\n\tvar flags = await get_flags_async(p_session, p_names)\n\n\tif flags.is_exception():\n\t\treturn SatoriAPI.ApiFlag.create(SatoriAPI, {\n\t\t\t\"name\": p_name,\n\t\t\t\"value\": p_default\n\t\t})\n\t\n\tfor flag in flags.flags:\n\t\tif flag.name == p_name:\n\t\t\treturn flag\n\t\n\treturn null\n\n## List all available flags for this identity.\n## [p_session]: The session of the user.\n## [p_names]: Flag names, if empty all flags will be returned.\nfunc get_flags_async(p_session: SatoriSession, p_names: Array) -> SatoriAPI.ApiFlagList:\n\treturn await _api_client.get_flags_async(p_session.token, p_names)\n\n## List available live events.\n## [p_session]: The session of the user.\n## [p_names]: Live event names, if null or empty all live events are returned.\nfunc get_live_events_async(p_session: SatoriSession, p_names: Array = []) -> SatoriAPI.ApiLiveEventList:\n\treturn await _api_client.get_live_events_async(p_session, p_names)\n\n## Identify a session with a new ID.\n## [p_session]: The session of the user.\n## [p_id]: Identity ID to enrich the current session and return a new session.\n## The old session will no longer be usable.\n## Must be between eight and 128 characters (inclusive).\n## Must be an alphanumeric string with only underscores and hyphens allowed.\n## [p_default_properties]: The default properties.\n## [p_custom_properties]: The custom event properties.\nfunc identify_async(p_session: SatoriSession, p_id: String, p_default_properties: Dictionary = {}, p_custom_properties: Dictionary = {}) -> SatoriSession:\n\tvar req = SatoriAPI.ApiIdentifyRequest.create(SatoriAPI, {\n\t\t\"id\": p_id,\n\t\t\"default\": p_default_properties,\n\t\t\"custom\": p_custom_properties\n\t})\n\treturn _parse_session(await _api_client.identify_async(p_session, req))\n\n## List properties associated with this identity.\n## [p_session]: The session of the user.\nfunc list_properties_async(p_session: SatoriSession) -> SatoriAsyncResult:\n\treturn await _api_client.list_properties_async(p_session)\n\n## Update properties associated with this identity.\n## [p_session]: The session of the user.\n## [p_default_properties]: The default properties to update.\n## [p_custom_properties]: The custom properties to update.\n## [p_recompute]: Whether or not to recompute the user's audience membership immediately after property update.\nfunc update_properties_async(p_session: SatoriSession, p_default_properties: Dictionary, p_custom_properties: Dictionary, p_recompute: bool = false) -> SatoriAsyncResult:\n\tvar req = SatoriAPI.ApiUpdatePropertiesRequest.create(SatoriAPI, {\n\t\t\"default\": p_default_properties,\n\t\t\"custom\": p_custom_properties,\n\t\t\"recompute\": p_recompute\n\t})\n\treturn await _api_client.update_properties_async(p_session, req)\n\n## Delete the caller's identity and associated data.\n## [p_session]: The session of the user.\nfunc delete_identity_async(p_session: SatoriSession) -> SatoriAsyncResult:\n\treturn await _api_client.delete_identity_async(p_session)\n\n#endregion\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/SatoriHttpAdapter.gd",
    "content": "@tool\nextends Node\n\n# An adapter which implements the HTTP protocol.\nclass_name SatoriHTTPAdapter\n\n# The logger to use with the adapter.\nvar logger : RefCounted = SatoriLogger.new()\n\n# The timeout for requests\nvar timeout : int = 3\n# If request should be automatically retried when a network error occurs.\nvar auto_retry : bool = true\n# The maximum number of time a request will be retried when auto_retry is true\nvar auto_retry_count : int = 3\nvar auto_retry_backoff_base : int = 10\n# Whether or not to use threads when making HTTP requests.\nvar use_threads : bool = true\n\nvar _pending = {}\nvar id : int = 0\n\nclass AsyncRequest:\n\tvar id : int\n\tvar request : HTTPRequest\n\tvar uri : String\n\tvar method : int\n\tvar headers : PackedStringArray\n\tvar body : PackedByteArray\n\tvar retry_count := 3\n\tvar backoff_time := 10\n\tvar logger : SatoriLogger\n\n\tvar cancelled = false\n\tvar result : int = HTTPRequest.RESULT_NO_RESPONSE\n\tvar response_code : int = -1\n\tvar response_body : PackedByteArray\n\tvar timer : SceneTreeTimer = null\n\tvar cur_try : int = 1\n\tvar rng = RandomNumberGenerator.new()\n\n\tfunc _init(p_id : int, p_request : HTTPRequest, p_uri : String,\n\t\t\tp_method : int, p_headers : PackedStringArray, p_body : PackedByteArray,\n\t\t\tp_retry_count : int, p_backoff_time : int, p_logger : SatoriLogger):\n\t\trng.seed = Time.get_ticks_usec()\n\t\tid = p_id\n\t\trequest = p_request\n\t\turi = p_uri\n\t\tmethod = p_method\n\t\theaders = p_headers\n\t\tbody = p_body\n\t\tretry_count = p_retry_count\n\t\tbackoff_time = p_backoff_time\n\t\tlogger = p_logger\n\n\tfunc should_retry():\n\t\treturn cur_try < retry_count and not cancelled\n\n\tfunc retry():\n\t\tvar time = pow(backoff_time, cur_try) * rng.randf_range(0.5, 1)\n\t\tlogger.debug(\"Retrying request %d. Tries left: %d. Backoff: %d ms\" % [\n\t\t\tid, retry_count - cur_try, time\n\t\t])\n\t\tcur_try += 1\n\t\tawait backoff(time)\n\t\tif cancelled:\n\t\t\treturn\n\t\treturn await make_request()\n\n\tfunc make_request():\n\t\tvar err = request.request(uri, headers, method, body.get_string_from_utf8())\n\t\tif err != OK:\n\t\t\tawait request.get_tree().process_frame\n\t\t\tresult = HTTPRequest.RESULT_CANT_CONNECT\n\t\t\tlogger.debug(\"Request %d failed to start, error: %d\" % [id, err])\n\t\t\treturn\n\n\t\tvar args = await request.request_completed\n\t\tresult = args[0]\n\t\tresponse_code = args[1]\n\t\tresponse_body = args[3]\n\n\tfunc backoff(p_time : int):\n\t\ttimer = request.get_tree().create_timer(p_time / 1000.0)\n\t\tawait timer.timeout\n\t\ttimer = null\n\n\tfunc cancel():\n\t\tcancelled = true\n\t\trequest.cancel_request()\n\t\tif timer:\n\t\t\ttimer.time_left = 0\n\t\telse:\n\t\t\trequest.call_deferred(\"emit_signal\", \"request_completed\", HTTPRequest.RESULT_REQUEST_FAILED, 0, [], [])\n\n\tfunc parse_result():\n\t\tif cancelled:\n\t\t\treturn SatoriException.new(\"Request cancelled\", -1, -1, true)\n\t\telif result != HTTPRequest.RESULT_SUCCESS:\n\t\t\tif result == null:\n\t\t\t\tresult = 0\n\t\t\treturn SatoriException.new(\"HTTPRequest failed!\", result)\n\n\t\tvar json = JSON.new()\n\n\t\tvar json_error = json.parse(response_body.get_string_from_utf8())\n\t\tif json_error != OK:\n\t\t\tlogger.debug(\"Unable to parse request %d response. JSON error: %d, JSON error message: %s, response code: %d\" % [\n\t\t\t\tid, json_error, json.get_error_message(), response_code\n\t\t\t])\n\t\t\treturn SatoriException.new(\"Failed to decode JSON response\", response_code)\n\n\t\tvar parsed = json.get_data()\n\n\t\tif response_code != HTTPClient.RESPONSE_OK:\n\t\t\tvar error = \"\"\n\t\t\tvar code = -1\n\t\t\tif typeof(parsed) == TYPE_DICTIONARY:\n\t\t\t\tif \"message\" in parsed:\n\t\t\t\t\terror = parsed[\"message\"]\n\t\t\t\telif \"error\" in parsed:\n\t\t\t\t\terror = parsed[\"error\"]\n\t\t\t\telse:\n\t\t\t\t\terror = str(parsed)\n\t\t\t\tcode = parsed[\"code\"] if \"code\" in parsed else -1\n\t\t\telse:\n\t\t\t\terror = str(parsed)\n\t\t\tif typeof(error) == TYPE_DICTIONARY:\n\t\t\t\terror = JSON.stringify(error)\n\t\t\tlogger.debug(\"Request %d returned response code: %d, RPC code: %d, error: %s\" % [\n\t\t\t\tid, response_code, code, error\n\t\t\t])\n\t\t\treturn SatoriException.new(error, response_code, code)\n\n\t\treturn parsed\n\n\n# Send a HTTP request.\n# @param method - HTTP method to use for this request.\n# @param uri - The fully qualified URI to use.\n# @param headers - Request headers to set.\n# @param body - Request content body to set.\n# @param timeoutSec - Request timeout.\n# Returns a task which resolves to the contents of the response.\nfunc send_async(p_method : String, p_uri : String, p_headers : Dictionary, p_body : PackedByteArray):\n\tvar req = HTTPRequest.new()\n\treq.timeout = timeout\n\tif use_threads and OS.get_name() != 'Web':\n\t\treq.use_threads = true # Threads not available nor needed on the web.\n\n\t# Parse method\n\tvar method = HTTPClient.METHOD_GET\n\tif p_method == \"POST\":\n\t\tmethod = HTTPClient.METHOD_POST\n\telif p_method == \"PUT\":\n\t\tmethod = HTTPClient.METHOD_PUT\n\telif p_method == \"DELETE\":\n\t\tmethod = HTTPClient.METHOD_DELETE\n\telif p_method == \"HEAD\":\n\t\tmethod = HTTPClient.METHOD_HEAD\n\tvar headers = PackedStringArray()\n\n\t# Parse headers\n\theaders.append(\"Accept: application/json\")\n\tfor k in p_headers:\n\t\theaders.append(\"%s: %s\" % [k, p_headers[k]])\n\n\tid += 1\n\tvar retry = auto_retry_count if auto_retry else 0\n\tvar backoff = auto_retry_backoff_base\n\t_pending[id] = AsyncRequest.new(id, req, p_uri, method, headers, p_body, retry, backoff, logger)\n\n\tlogger.debug(\"Sending request [ID: %d, Method: %s, Uri: %s, Headers: %s, Body: %s, Timeout: %d, Retries: %d, Backoff base: %d ms]\" % [\n\t\tid, p_method, p_uri, p_headers, p_body.get_string_from_utf8(), timeout, retry, backoff\n\t])\n\n\tadd_child(req)\n\n\treturn await _send_async(id, _pending)\n\nfunc get_last_token():\n\treturn id\n\nfunc cancel_request(p_token):\n\tif _pending.has(p_token):\n\t\t_pending[p_token].cancel()\n\nstatic func _clear_request(p_request : AsyncRequest, p_pending : Dictionary, p_id : int):\n\tif not p_request.request.is_queued_for_deletion():\n\t\tp_request.logger.debug(\"Freeing request %d\" % p_id)\n\t\tp_request.request.queue_free()\n\t\tp_pending.erase(p_id)\n\nstatic func _send_async(p_id : int, p_pending : Dictionary):\n\n\tvar req : AsyncRequest = p_pending[p_id]\n\tawait req.make_request()\n\n\twhile req.result != HTTPRequest.RESULT_SUCCESS:\n\t\treq.logger.debug(\"Request %d failed with result: %d, response code: %d\" % [\n\t\t\tp_id, req.result, req.response_code\n\t\t])\n\t\tif not req.should_retry():\n\t\t\tbreak\n\t\tawait req.retry()\n\n\t_clear_request(req, p_pending, p_id)\n\treturn req.parse_result()\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/SatoriSession.gd",
    "content": "extends  SatoriAsyncResult\nclass_name SatoriSession\n\nvar _token: String = \"\"\nvar token: String:\n    get:\n        return _token\n\nvar _refresh_token: String = \"\"\nvar refresh_token: String:\n    get:\n        return _refresh_token\n\nvar _expire_time: int = 0\nvar expire_time: int:\n    get:\n        return _expire_time\n\nvar expired: bool:\n    get:\n        return is_expired()\n\nvar _refresh_expire_time: int = 0\nvar refresh_expire_time: int:\n    get:\n        return _refresh_expire_time\n\nvar _identity_id: String = \"\"\nvar identity_id: String:\n    get:\n        return _identity_id\n\nvar _valid : bool = false\nvar valid : bool:\n    get:\n        return _valid\n\nfunc is_expired() -> bool:\n    return _expire_time < Time.get_unix_time_from_system()\n\nfunc would_expire_in(p_secs : int) -> bool:\n    return _expire_time < Time.get_unix_time_from_system() + p_secs\n\nfunc has_refresh_expired(offset: float) -> bool:\n    return _expire_time < offset\n\nfunc is_refresh_expired() -> bool:\n    return _refresh_expire_time < Time.get_unix_time_from_system()\n\nfunc is_valid():\n    return _valid\n\n# Initializes a new instance of the SatoriSession class.\n# \n# @param p_token - The authentication token.\n# @param p_refresh_token - The refresh token.\n# @param p_exception - The exception to be thrown, if any.\nfunc _init(p_token = null, p_refresh_token = null, p_exception = null):\n    super(p_exception)\n    \n    _refresh_expire_time = 0\n    if p_token:\n        _update(p_token, p_refresh_token)\n\nfunc _update(p_token, p_refresh_token):\n    _token = p_token\n    _refresh_token = p_refresh_token\n    \n    var decoded = _jwt_unpack(p_token)\n    if decoded.is_empty():\n        _valid = false\n        return\n    \n    _valid = true\n    _expire_time = int(decoded.get(\"exp\", 0))\n    _identity_id = str(decoded.get(\"iid\", \"\"))\n    _refresh_expire_time = int(_jwt_unpack(refresh_token).get(\"exp\", 0)) if !refresh_token.is_empty() else 0\n\nfunc _to_string():\n    if is_exception():\n        return get_exception()._to_string()\n    \n    return \"Session<AuthToken=%s, ExpireTime=%d, RefreshToken=%s, RefreshExpireTime=%d, IdentityId=%s>\" % [\n        _token, _expire_time, _refresh_token, _refresh_expire_time, identity_id]\n\nfunc _jwt_unpack(p_token : String) -> Dictionary:\n    # Hack decode JSON payload from JWT.\n    if p_token.find(\".\") == -1:\n        _ex = SatoriException.new(\"Missing payload: %s\" % p_token)\n        return {}\n    var payload = p_token.split('.')[1];\n    var pad_length = ceil(payload.length() / 4.0) * 4;\n    # Pad base64\n    for i in range(0, pad_length - payload.length()):\n        payload += \"=\"\n    payload = payload.replace(\"-\", \"+\").replace(\"_\", \"/\")\n    var unpacked = Marshalls.base64_to_utf8(payload)\n    \n    var json = JSON.new()\n    var error = json.parse(unpacked)\n\n    if error == OK:\n        var decoded = json.get_data()\n        if typeof(decoded) == TYPE_DICTIONARY:\n            return decoded\n    _ex = SatoriException.new(\"Unable to unpack token: %s\" % p_token)\n    return {}"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriAsyncResult.gd",
    "content": "extends RefCounted\nclass_name SatoriAsyncResult\n\nvar exception : SatoriException:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn get_exception()\n\nvar _ex = null\n\nfunc _init(p_ex = null):\n\t_ex = p_ex\n\nfunc is_exception():\n\treturn get_exception() != null\n\nfunc was_cancelled():\n\treturn is_exception() and get_exception().cancelled\n\nfunc get_exception() -> SatoriException:\n\treturn _ex as SatoriException\n\nfunc _to_string():\n\tif is_exception():\n\t\treturn get_exception()._to_string()\n\treturn \"SatoriAsyncResult<>\"\n\nstatic func _safe_ret(p_obj, p_type : GDScript):\n\tif is_instance_of(p_obj, p_type):\n\t\treturn p_obj\n\telif p_obj is SatoriException:\n\t\treturn p_type.new(p_obj)\n\treturn p_type.new(SatoriException.new())\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriException.gd",
    "content": "extends RefCounted\n\n# An exception generated during a request.\n# Usually contains at least an error message.\nclass_name SatoriException\n\nvar _status_code : int = -1\nvar status_code : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _status_code\n\nvar _grpc_status_code : int = -1\nvar grpc_status_code : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _grpc_status_code\n\nvar _message : String = \"\"\nvar message : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _message\n\nvar _cancelled : bool = false\nvar cancelled : bool:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _cancelled\n\nfunc _init(p_message : String = \"\", p_status_code : int = -1, p_grpc_status_code : int = -1, p_cancelled : bool = false):\n\t_status_code = p_status_code\n\t_grpc_status_code = p_grpc_status_code\n\t_message = p_message\n\t_cancelled = p_cancelled\n\nfunc _to_string() -> String:\n\treturn \"SatoriException(StatusCode={%s}, Message='{%s}', GrpcStatusCode={%s})\" % [_status_code, _message, _grpc_status_code]\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriLogger.gd",
    "content": "extends RefCounted\nclass_name SatoriLogger\n\nenum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}\n\nvar _level = LOG_LEVEL.ERROR\nvar _module = \"Satori\"\n\nfunc _init(p_module : String = \"Satori\", p_level : int = LOG_LEVEL.ERROR):\n\t_level = p_level\n\t_module = p_module\n\nfunc _log(level : int, msg):\n\tif level <= _level:\n\t\tif level == LOG_LEVEL.ERROR:\n\t\t\tprinterr(\"=== %s : ERROR === %s\" % [_module, str(msg)])\n\t\telse:\n\t\t\tvar what = \"=== UNKNOWN === \"\n\t\t\tfor k in LOG_LEVEL:\n\t\t\t\tif level == LOG_LEVEL[k]:\n\t\t\t\t\twhat = \"=== %s : %s === \" % [_module, k]\n\t\t\t\t\tbreak\n\t\t\tprint(what + str(msg))\n\nfunc error(msg):\n\t_log(LOG_LEVEL.ERROR, msg)\n\nfunc warning(msg):\n\t_log(LOG_LEVEL.WARNING, msg)\n\nfunc info(msg):\n\t_log(LOG_LEVEL.INFO, msg)\n\nfunc verbose(msg):\n\t_log(LOG_LEVEL.VERBOSE, msg)\n\nfunc debug(msg):\n\t_log(LOG_LEVEL.DEBUG, msg)\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriSerializer.gd",
    "content": "extends RefCounted\nclass_name SatoriSerializer\n\nstatic func serialize(p_obj : Object) -> Dictionary:\n\tvar out = {}\n\tvar schema = p_obj.get(\"_SCHEMA\")\n\tif schema == null:\n\t\treturn {} # No schema defined\n\tfor k in schema:\n\t\tvar prop = schema[k]\n\t\tvar val = p_obj.get(prop[\"name\"])\n\t\tif val == null:\n\t\t\tcontinue\n\t\tvar type = prop[\"type\"]\n\t\tvar content = prop.get(\"content\", TYPE_NIL)\n\t\tif typeof(content) == TYPE_STRING:\n\t\t\tcontent = TYPE_OBJECT\n\t\tvar val_type = typeof(val)\n\t\tmatch val_type:\n\t\t\tTYPE_OBJECT: # Simple objects\n\t\t\t\tout[k] = serialize(val)\n\t\t\tTYPE_ARRAY: # Array of objects\n\t\t\t\tvar arr = []\n\t\t\t\tif val.size() > 0 and typeof(val[0]) == TYPE_OBJECT: # Array of objects\n\t\t\t\t\tfor e in val:\n\t\t\t\t\t\tarr.append(serialize(e))\n\t\t\t\telse:\n\t\t\t\t\tarr = val\n\t\t\t\tout[k] = arr\n\t\t\tTYPE_PACKED_INT32_ARRAY, TYPE_PACKED_STRING_ARRAY: # Array of ints, bools, or strings\n\t\t\t\tvar arr = []\n\t\t\t\tfor e in val:\n\t\t\t\t\tif content == TYPE_BOOL:\n\t\t\t\t\t\te = bool(e)\n\t\t\t\t\tif typeof(e) != content:\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tarr.append(e)\n\t\t\t\tout[k] = arr\n\t\t\tTYPE_DICTIONARY: # Maps\n\t\t\t\tvar dict = {}\n\t\t\t\tif content == TYPE_OBJECT: # Map of objects\n\t\t\t\t\tfor l in val:\n\t\t\t\t\t\tif typeof(val[l]) != TYPE_OBJECT:\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tdict[l] = serialize(val[l])\n\t\t\t\telse: # Map of simple types\n\t\t\t\t\tfor l in val:\n\t\t\t\t\t\tvar e = val[l]\n\t\t\t\t\t\tif content == TYPE_FLOAT:\n\t\t\t\t\t\t\te = float(e)\n\t\t\t\t\t\telif content == TYPE_INT:\n\t\t\t\t\t\t\te = int(e)\n\t\t\t\t\t\telif content == TYPE_BOOL:\n\t\t\t\t\t\t\te = bool(e)\n\t\t\t\t\t\tif typeof(e) != content:\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tdict[l] = e\n\t\t\t\tout[k] = dict\n\t\t\t_:\n\t\t\t\tout[k] = val\n\treturn out\n\nstatic func deserialize(p_ns : GDScript, p_cls_name : String, p_dict : Dictionary) -> Object:\n\tvar cls : GDScript = p_ns.get(p_cls_name)\n\tvar schema = cls.get(\"_SCHEMA\")\n\tif schema == null:\n\t\treturn SatoriException.new() # No schema defined\n\tvar obj = cls.new()\n\tfor k in schema:\n\t\tvar prop = schema[k]\n\t\tvar pname = prop[\"name\"]\n\t\tvar type = prop[\"type\"]\n\t\tvar required = prop[\"required\"]\n\t\tvar content = prop.get(\"content\", TYPE_NIL)\n\t\tvar type_cmp = type\n\t\tif typeof(type) == TYPE_STRING: # A class\n\t\t\ttype_cmp = TYPE_DICTIONARY\n\t\tif type_cmp == TYPE_PACKED_STRING_ARRAY or type_cmp == TYPE_PACKED_INT32_ARRAY: # A specialized array\n\t\t\ttype_cmp = TYPE_ARRAY\n\n\t\tvar content_cmp = content\n\t\tif typeof(content) == TYPE_STRING: # A dictionary or array of classes\n\t\t\tcontent_cmp = TYPE_DICTIONARY\n\n\t\tvar val = p_dict.get(k, null)\n\n\t\t# Ints might and up being recognized as floats. Change that if needed\n\t\tif type_cmp == TYPE_INT:\n\t\t\tif typeof(val) == TYPE_FLOAT:\n\t\t\t\tval = int(val)\n\t\t\telif typeof(val) == TYPE_STRING and val.is_valid_int():\n\t\t\t\tval = val.to_int()\n\n\t\tif typeof(val) == type_cmp:\n\t\t\tif typeof(type) == TYPE_STRING:\n\t\t\t\tobj.set(pname, deserialize(p_ns, type, val))\n\t\t\telif type_cmp == TYPE_DICTIONARY:\n\t\t\t\tvar v = {}\n\t\t\t\tfor l in val:\n\t\t\t\t\tif typeof(content) == TYPE_STRING:\n\t\t\t\t\t\tv[l] = deserialize(p_ns, content, val[l])\n\t\t\t\t\telif content == TYPE_FLOAT:\n\t\t\t\t\t\tv[l] = float(val[l])\n\t\t\t\t\telif content == TYPE_INT:\n\t\t\t\t\t\tv[l] = int(val[l])\n\t\t\t\t\telif content == TYPE_BOOL:\n\t\t\t\t\t\tv[l] = bool(val[l])\n\t\t\t\t\telse:\n\t\t\t\t\t\tv[l] = str(val[l])\n\t\t\t\tobj.set(pname, v)\n\t\t\telif type_cmp == TYPE_ARRAY:\n\t\t\t\tvar v\n\t\t\t\tmatch content:\n\t\t\t\t\tTYPE_INT, TYPE_BOOL: v = PackedInt32Array()\n\t\t\t\t\tTYPE_STRING: v = PackedStringArray()\n\t\t\t\t\t_: v = Array()\n\t\t\t\tfor e in val:\n\t\t\t\t\tif typeof(e) == TYPE_DICTIONARY: \n\t\t\t\t\t\tv.append(e) # Avoid deserialization if e is already a dictionary\n\t\t\t\t\telif typeof(content) == TYPE_STRING:\n\t\t\t\t\t\tv.append(deserialize(p_ns, content, e))\n\t\t\t\t\telif content == TYPE_FLOAT:\n\t\t\t\t\t\tv.append(float(e))\n\t\t\t\t\telif content == TYPE_INT:\n\t\t\t\t\t\tv.append(int(e))\n\t\t\t\t\telif content == TYPE_BOOL:\n\t\t\t\t\t\tv.append(bool(e))\n\t\t\t\t\telse:\n\t\t\t\t\t\tv.append(str(e))\n\t\t\t\tobj.set(pname, v)\n\t\t\telse:\n\t\t\t\tobj.set(pname, val)\n\t\telif required:\n\t\t\tobj._ex = SatoriException.new(\"ERROR [%s]: Missing or invalid required prop %s = %s:\\n\\t%s\" % [p_cls_name, prop, p_dict.get(k), p_dict])\n\t\t\treturn obj\n\treturn obj\n\n\n###\n# Compatibility with Godot 3.1 which does not expose String.http_escape\n###\nconst HEX = [\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"A\",\"B\",\"C\",\"D\",\"E\",\"F\"]\n\nstatic func escape_http(p_str : String) -> String:\n\tvar out : String = \"\"\n\tfor o in p_str:\n\t\tif (o == '.' or o == '-' or o == '_' or o == '~' or\n\t\t\t(o >= 'a' and o <= 'z') or\n\t\t\t(o >= 'A' and o <= 'Z') or\n\t\t\t(o >= '0' and o <= '9')):\n\t\t\tout += o\n\t\telse:\n\t\t\tfor b in o.to_utf8_buffer():\n\t\t\t\tout += \"%%%s\" % to_hex(b)\n\treturn out\n\nstatic func to_hex(p_val : int) -> String:\n\tvar v := p_val\n\tvar o := \"\"\n\twhile v != 0:\n\t\to = HEX[v % 16] + o\n\t\tv /= 16\n\treturn o\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/Satori.gd",
    "content": "@tool\nextends Node\n\n# The default host address of the server.\nconst DEFAULT_HOST : String = \"127.0.0.1\"\n\n# The default port number of the server.\nconst DEFAULT_PORT : int = 7450\n\n# The default timeout for the connections.\nconst DEFAULT_TIMEOUT = 15\n\n# The default protocol scheme for the client connection.\nconst DEFAULT_CLIENT_SCHEME : String = \"http\"\n\n# The default log level for the Satori logger.\nconst DEFAULT_LOG_LEVEL = SatoriLogger.LOG_LEVEL.DEBUG\n\nvar _http_adapter = null\nvar logger = SatoriLogger.new()\n\nfunc _ready() -> void:\n\tprocess_mode = Node.PROCESS_MODE_ALWAYS\n\nfunc get_client_adapter() -> SatoriHTTPAdapter:\n\tif _http_adapter == null:\n\t\t_http_adapter = SatoriHTTPAdapter.new()\n\t\t_http_adapter.logger = logger\n\t\t_http_adapter.name = \"SatoriHTTPAdapter\"\n\t\tadd_child(_http_adapter)\n\treturn _http_adapter\n\nfunc create_client(p_api_key : String,\n\t\tp_host : String = DEFAULT_HOST,\n\t\tp_port : int = DEFAULT_PORT,\n\t\tp_scheme : String = DEFAULT_CLIENT_SCHEME,\n\t\tp_timeout : int = DEFAULT_TIMEOUT,\n\t\tp_log_level : int = DEFAULT_LOG_LEVEL,\n\t\t) -> SatoriClient:\n\tlogger._level = p_log_level\n\treturn SatoriClient.new(get_client_adapter(), p_api_key, p_scheme, p_host, p_port, p_timeout)\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/api/NakamaAPI.gd",
    "content": "### Code generated by codegen/main.go. DO NOT EDIT. ###\n\nextends RefCounted\nclass_name NakamaAPI\n\n# A single user-role pair.\nclass GroupUserListGroupUser extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"state\": {\"name\": \"_state\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"user\": {\"name\": \"_user\", \"type\": \"ApiUser\", \"required\": false},\n\t}\n\n\t# Their relationship to the group.\n\tvar _state\n\tvar state : int:\n\t\tget:\n\t\t\treturn 0 if not _state is int else int(_state)\n\n\t# User.\n\tvar _user\n\tvar user : ApiUser:\n\t\tget:\n\t\t\treturn _user as ApiUser\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> GroupUserListGroupUser:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"GroupUserListGroupUser\", p_dict), GroupUserListGroupUser) as GroupUserListGroupUser\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"state: %s, \" % _state\n\t\toutput += \"user: %s, \" % _user\n\t\treturn output\n\n# A single group-role pair.\nclass UserGroupListUserGroup extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"group\": {\"name\": \"_group\", \"type\": \"ApiGroup\", \"required\": false},\n\t\t\"state\": {\"name\": \"_state\", \"type\": TYPE_INT, \"required\": false},\n\t}\n\n\t# Group.\n\tvar _group\n\tvar group : ApiGroup:\n\t\tget:\n\t\t\treturn _group as ApiGroup\n\n\t# The user's relationship to the group.\n\tvar _state\n\tvar state : int:\n\t\tget:\n\t\t\treturn 0 if not _state is int else int(_state)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> UserGroupListUserGroup:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"UserGroupListUserGroup\", p_dict), UserGroupListUserGroup) as UserGroupListUserGroup\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"group: %s, \" % _group\n\t\toutput += \"state: %s, \" % _state\n\t\treturn output\n\n# Record values to write.\nclass WriteLeaderboardRecordRequestLeaderboardRecordWrite extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"operator\": {\"name\": \"_operator\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"score\": {\"name\": \"_score\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"subscore\": {\"name\": \"_subscore\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Optional record metadata.\n\tvar _metadata\n\tvar metadata : String:\n\t\tget:\n\t\t\treturn \"\" if not _metadata is String else String(_metadata)\n\n\t# Operator override.\n\tvar _operator\n\tvar operator : int:\n\t\tget:\n\t\t\treturn ApiOperator.values()[0] if not ApiOperator.values().has(_operator) else _operator\n\n\t# The score value to submit.\n\tvar _score\n\tvar score : String:\n\t\tget:\n\t\t\treturn \"\" if not _score is String else String(_score)\n\n\t# An optional secondary value.\n\tvar _subscore\n\tvar subscore : String:\n\t\tget:\n\t\t\treturn \"\" if not _subscore is String else String(_subscore)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> WriteLeaderboardRecordRequestLeaderboardRecordWrite:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"WriteLeaderboardRecordRequestLeaderboardRecordWrite\", p_dict), WriteLeaderboardRecordRequestLeaderboardRecordWrite) as WriteLeaderboardRecordRequestLeaderboardRecordWrite\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"metadata: %s, \" % _metadata\n\t\toutput += \"operator: %s, \" % _operator\n\t\toutput += \"score: %s, \" % _score\n\t\toutput += \"subscore: %s, \" % _subscore\n\t\treturn output\n\n# Record values to write.\nclass WriteTournamentRecordRequestTournamentRecordWrite extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"operator\": {\"name\": \"_operator\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"score\": {\"name\": \"_score\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"subscore\": {\"name\": \"_subscore\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# A JSON object of additional properties (optional).\n\tvar _metadata\n\tvar metadata : String:\n\t\tget:\n\t\t\treturn \"\" if not _metadata is String else String(_metadata)\n\n\t# Operator override.\n\tvar _operator\n\tvar operator : int:\n\t\tget:\n\t\t\treturn ApiOperator.values()[0] if not ApiOperator.values().has(_operator) else _operator\n\n\t# The score value to submit.\n\tvar _score\n\tvar score : String:\n\t\tget:\n\t\t\treturn \"\" if not _score is String else String(_score)\n\n\t# An optional secondary value.\n\tvar _subscore\n\tvar subscore : String:\n\t\tget:\n\t\t\treturn \"\" if not _subscore is String else String(_subscore)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> WriteTournamentRecordRequestTournamentRecordWrite:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"WriteTournamentRecordRequestTournamentRecordWrite\", p_dict), WriteTournamentRecordRequestTournamentRecordWrite) as WriteTournamentRecordRequestTournamentRecordWrite\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"metadata: %s, \" % _metadata\n\t\toutput += \"operator: %s, \" % _operator\n\t\toutput += \"score: %s, \" % _score\n\t\toutput += \"subscore: %s, \" % _subscore\n\t\treturn output\n\n# A user with additional account details. Always the current user.\nclass ApiAccount extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"custom_id\": {\"name\": \"_custom_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"devices\": {\"name\": \"_devices\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiAccountDevice\"},\n\t\t\"disable_time\": {\"name\": \"_disable_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"email\": {\"name\": \"_email\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user\": {\"name\": \"_user\", \"type\": \"ApiUser\", \"required\": false},\n\t\t\"verify_time\": {\"name\": \"_verify_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"wallet\": {\"name\": \"_wallet\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The custom id in the user's account.\n\tvar _custom_id\n\tvar custom_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _custom_id is String else String(_custom_id)\n\n\t# The devices which belong to the user's account.\n\tvar _devices\n\tvar devices : Array:\n\t\tget:\n\t\t\treturn Array() if not _devices is Array else Array(_devices)\n\n\t# The UNIX time when the user's account was disabled/banned.\n\tvar _disable_time\n\tvar disable_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _disable_time is String else String(_disable_time)\n\n\t# The email address of the user.\n\tvar _email\n\tvar email : String:\n\t\tget:\n\t\t\treturn \"\" if not _email is String else String(_email)\n\n\t# The user object.\n\tvar _user\n\tvar user : ApiUser:\n\t\tget:\n\t\t\treturn _user as ApiUser\n\n\t# The UNIX time when the user's email was verified.\n\tvar _verify_time\n\tvar verify_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _verify_time is String else String(_verify_time)\n\n\t# The user's wallet data.\n\tvar _wallet\n\tvar wallet : String:\n\t\tget:\n\t\t\treturn \"\" if not _wallet is String else String(_wallet)\n\n\tvar _wallet_dict = null\n\tvar wallet_dict : Dictionary:\n\t\tget:\n\t\t\tif _wallet_dict == null:\n\t\t\t\tif _wallet == null:\n\t\t\t\t\treturn {}\n\t\t\t\tvar json = JSON.new()\n\t\t\t\tif json.parse(_wallet) != OK:\n\t\t\t\t\treturn {}\n\t\t\t\t_wallet_dict = json.get_data()\n\t\t\treturn _wallet_dict as Dictionary\n\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccount:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccount\", p_dict), ApiAccount) as ApiAccount\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"custom_id: %s, \" % _custom_id\n\t\toutput += \"devices: %s, \" % [_devices]\n\t\toutput += \"disable_time: %s, \" % _disable_time\n\t\toutput += \"email: %s, \" % _email\n\t\toutput += \"user: %s, \" % _user\n\t\toutput += \"verify_time: %s, \" % _verify_time\n\t\toutput += \"wallet: %s, \" % _wallet\n\t\treturn output\n\n# Send a Apple Sign In token to the server. Used with authenticate/link/unlink.\nclass ApiAccountApple extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# The ID token received from Apple to validate.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountApple:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountApple\", p_dict), ApiAccountApple) as ApiAccountApple\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"token: %s, \" % _token\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send a custom ID to the server. Used with authenticate/link/unlink.\nclass ApiAccountCustom extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# A custom identifier.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountCustom:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountCustom\", p_dict), ApiAccountCustom) as ApiAccountCustom\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"id: %s, \" % _id\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send a device to the server. Used with authenticate/link/unlink and user.\nclass ApiAccountDevice extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# A device identifier. Should be obtained by a platform-specific device API.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountDevice:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountDevice\", p_dict), ApiAccountDevice) as ApiAccountDevice\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"id: %s, \" % _id\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send an email with password to the server. Used with authenticate/link/unlink.\nclass ApiAccountEmail extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"email\": {\"name\": \"_email\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"password\": {\"name\": \"_password\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# A valid RFC-5322 email address.\n\tvar _email\n\tvar email : String:\n\t\tget:\n\t\t\treturn \"\" if not _email is String else String(_email)\n\n\t# A password for the user account.\n\tvar _password\n\tvar password : String:\n\t\tget:\n\t\t\treturn \"\" if not _password is String else String(_password)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountEmail:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountEmail\", p_dict), ApiAccountEmail) as ApiAccountEmail\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"email: %s, \" % _email\n\t\toutput += \"password: %s, \" % _password\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send a Facebook token to the server. Used with authenticate/link/unlink.\nclass ApiAccountFacebook extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# The OAuth token received from Facebook to access their profile API.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountFacebook:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountFacebook\", p_dict), ApiAccountFacebook) as ApiAccountFacebook\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"token: %s, \" % _token\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send a Facebook Instant Game token to the server. Used with authenticate/link/unlink.\nclass ApiAccountFacebookInstantGame extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"signed_player_info\": {\"name\": \"_signed_player_info\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t#\n\tvar _signed_player_info\n\tvar signed_player_info : String:\n\t\tget:\n\t\t\treturn \"\" if not _signed_player_info is String else String(_signed_player_info)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountFacebookInstantGame:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountFacebookInstantGame\", p_dict), ApiAccountFacebookInstantGame) as ApiAccountFacebookInstantGame\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"signed_player_info: %s, \" % _signed_player_info\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send Apple's Game Center account credentials to the server. Used with authenticate/link/unlink.\nclass ApiAccountGameCenter extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"bundle_id\": {\"name\": \"_bundle_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"player_id\": {\"name\": \"_player_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"public_key_url\": {\"name\": \"_public_key_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"salt\": {\"name\": \"_salt\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"signature\": {\"name\": \"_signature\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"timestamp_seconds\": {\"name\": \"_timestamp_seconds\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# Bundle ID (generated by GameCenter).\n\tvar _bundle_id\n\tvar bundle_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _bundle_id is String else String(_bundle_id)\n\n\t# Player ID (generated by GameCenter).\n\tvar _player_id\n\tvar player_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _player_id is String else String(_player_id)\n\n\t# The URL for the public encryption key.\n\tvar _public_key_url\n\tvar public_key_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _public_key_url is String else String(_public_key_url)\n\n\t# A random \"NSString\" used to compute the hash and keep it randomized.\n\tvar _salt\n\tvar salt : String:\n\t\tget:\n\t\t\treturn \"\" if not _salt is String else String(_salt)\n\n\t# The verification signature data generated.\n\tvar _signature\n\tvar signature : String:\n\t\tget:\n\t\t\treturn \"\" if not _signature is String else String(_signature)\n\n\t# Time since UNIX epoch when the signature was created.\n\tvar _timestamp_seconds\n\tvar timestamp_seconds : String:\n\t\tget:\n\t\t\treturn \"\" if not _timestamp_seconds is String else String(_timestamp_seconds)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountGameCenter:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountGameCenter\", p_dict), ApiAccountGameCenter) as ApiAccountGameCenter\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"bundle_id: %s, \" % _bundle_id\n\t\toutput += \"player_id: %s, \" % _player_id\n\t\toutput += \"public_key_url: %s, \" % _public_key_url\n\t\toutput += \"salt: %s, \" % _salt\n\t\toutput += \"signature: %s, \" % _signature\n\t\toutput += \"timestamp_seconds: %s, \" % _timestamp_seconds\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send a Google token to the server. Used with authenticate/link/unlink.\nclass ApiAccountGoogle extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# The OAuth token received from Google to access their profile API.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountGoogle:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountGoogle\", p_dict), ApiAccountGoogle) as ApiAccountGoogle\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"token: %s, \" % _token\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# Send a Steam token to the server. Used with authenticate/link/unlink.\nclass ApiAccountSteam extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# The account token received from Steam to access their profile API.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountSteam:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiAccountSteam\", p_dict), ApiAccountSteam) as ApiAccountSteam\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"token: %s, \" % _token\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# A message sent on a channel.\nclass ApiChannelMessage extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"_channel_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"code\": {\"name\": \"_code\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"content\": {\"name\": \"_content\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"group_id\": {\"name\": \"_group_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"message_id\": {\"name\": \"_message_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"persistent\": {\"name\": \"_persistent\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"room_name\": {\"name\": \"_room_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"sender_id\": {\"name\": \"_sender_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_one\": {\"name\": \"_user_id_one\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_two\": {\"name\": \"_user_id_two\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"username\": {\"name\": \"_username\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The channel this message belongs to.\n\tvar _channel_id\n\tvar channel_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _channel_id is String else String(_channel_id)\n\n\t# The code representing a message type or category.\n\tvar _code\n\tvar code : int:\n\t\tget:\n\t\t\treturn 0 if not _code is int else int(_code)\n\n\t# The content payload.\n\tvar _content\n\tvar content : String:\n\t\tget:\n\t\t\treturn \"\" if not _content is String else String(_content)\n\n\t# The UNIX time when the message was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# The ID of the group, or an empty string if this message was not sent through a group channel.\n\tvar _group_id\n\tvar group_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _group_id is String else String(_group_id)\n\n\t# The unique ID of this message.\n\tvar _message_id\n\tvar message_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _message_id is String else String(_message_id)\n\n\t# True if the message was persisted to the channel's history, false otherwise.\n\tvar _persistent\n\tvar persistent : bool:\n\t\tget:\n\t\t\treturn false if not _persistent is bool else bool(_persistent)\n\n\t# The name of the chat room, or an empty string if this message was not sent through a chat room.\n\tvar _room_name\n\tvar room_name : String:\n\t\tget:\n\t\t\treturn \"\" if not _room_name is String else String(_room_name)\n\n\t# Message sender, usually a user ID.\n\tvar _sender_id\n\tvar sender_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _sender_id is String else String(_sender_id)\n\n\t# The UNIX time when the message was last updated.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.\n\tvar _user_id_one\n\tvar user_id_one : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id_one is String else String(_user_id_one)\n\n\t# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.\n\tvar _user_id_two\n\tvar user_id_two : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id_two is String else String(_user_id_two)\n\n\t# The username of the message sender, if any.\n\tvar _username\n\tvar username : String:\n\t\tget:\n\t\t\treturn \"\" if not _username is String else String(_username)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiChannelMessage:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiChannelMessage\", p_dict), ApiChannelMessage) as ApiChannelMessage\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"channel_id: %s, \" % _channel_id\n\t\toutput += \"code: %s, \" % _code\n\t\toutput += \"content: %s, \" % _content\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"group_id: %s, \" % _group_id\n\t\toutput += \"message_id: %s, \" % _message_id\n\t\toutput += \"persistent: %s, \" % _persistent\n\t\toutput += \"room_name: %s, \" % _room_name\n\t\toutput += \"sender_id: %s, \" % _sender_id\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"user_id_one: %s, \" % _user_id_one\n\t\toutput += \"user_id_two: %s, \" % _user_id_two\n\t\toutput += \"username: %s, \" % _username\n\t\treturn output\n\n# A list of channel messages, usually a result of a list operation.\nclass ApiChannelMessageList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cacheable_cursor\": {\"name\": \"_cacheable_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"messages\": {\"name\": \"_messages\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiChannelMessage\"},\n\t\t\"next_cursor\": {\"name\": \"_next_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"prev_cursor\": {\"name\": \"_prev_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Cacheable cursor to list newer messages. Durable and designed to be stored, unlike next/prev cursors.\n\tvar _cacheable_cursor\n\tvar cacheable_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cacheable_cursor is String else String(_cacheable_cursor)\n\n\t# A list of messages.\n\tvar _messages\n\tvar messages : Array:\n\t\tget:\n\t\t\treturn Array() if not _messages is Array else Array(_messages)\n\n\t# The cursor to send when retrieving the next page, if any.\n\tvar _next_cursor\n\tvar next_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _next_cursor is String else String(_next_cursor)\n\n\t# The cursor to send when retrieving the previous page, if any.\n\tvar _prev_cursor\n\tvar prev_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _prev_cursor is String else String(_prev_cursor)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiChannelMessageList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiChannelMessageList\", p_dict), ApiChannelMessageList) as ApiChannelMessageList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cacheable_cursor: %s, \" % _cacheable_cursor\n\t\toutput += \"messages: %s, \" % [_messages]\n\t\toutput += \"next_cursor: %s, \" % _next_cursor\n\t\toutput += \"prev_cursor: %s, \" % _prev_cursor\n\t\treturn output\n\n# Create a group with the current user as owner.\nclass ApiCreateGroupRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"avatar_url\": {\"name\": \"_avatar_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"description\": {\"name\": \"_description\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"lang_tag\": {\"name\": \"_lang_tag\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"max_count\": {\"name\": \"_max_count\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"open\": {\"name\": \"_open\", \"type\": TYPE_BOOL, \"required\": false},\n\t}\n\n\t# A URL for an avatar image.\n\tvar _avatar_url\n\tvar avatar_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _avatar_url is String else String(_avatar_url)\n\n\t# A description for the group.\n\tvar _description\n\tvar description : String:\n\t\tget:\n\t\t\treturn \"\" if not _description is String else String(_description)\n\n\t# The language expected to be a tag which follows the BCP-47 spec.\n\tvar _lang_tag\n\tvar lang_tag : String:\n\t\tget:\n\t\t\treturn \"\" if not _lang_tag is String else String(_lang_tag)\n\n\t# Maximum number of group members.\n\tvar _max_count\n\tvar max_count : int:\n\t\tget:\n\t\t\treturn 0 if not _max_count is int else int(_max_count)\n\n\t# A unique name for the group.\n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\n\t# Mark a group as open or not where only admins can accept members.\n\tvar _open\n\tvar open : bool:\n\t\tget:\n\t\t\treturn false if not _open is bool else bool(_open)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiCreateGroupRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiCreateGroupRequest\", p_dict), ApiCreateGroupRequest) as ApiCreateGroupRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"avatar_url: %s, \" % _avatar_url\n\t\toutput += \"description: %s, \" % _description\n\t\toutput += \"lang_tag: %s, \" % _lang_tag\n\t\toutput += \"max_count: %s, \" % _max_count\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"open: %s, \" % _open\n\t\treturn output\n\n# Storage objects to delete.\nclass ApiDeleteStorageObjectId extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"collection\": {\"name\": \"_collection\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"key\": {\"name\": \"_key\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"version\": {\"name\": \"_version\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The collection which stores the object.\n\tvar _collection\n\tvar collection : String:\n\t\tget:\n\t\t\treturn \"\" if not _collection is String else String(_collection)\n\n\t# The key of the object within the collection.\n\tvar _key\n\tvar key : String:\n\t\tget:\n\t\t\treturn \"\" if not _key is String else String(_key)\n\n\t# The version hash of the object.\n\tvar _version\n\tvar version : String:\n\t\tget:\n\t\t\treturn \"\" if not _version is String else String(_version)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiDeleteStorageObjectId:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiDeleteStorageObjectId\", p_dict), ApiDeleteStorageObjectId) as ApiDeleteStorageObjectId\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"collection: %s, \" % _collection\n\t\toutput += \"key: %s, \" % _key\n\t\toutput += \"version: %s, \" % _version\n\t\treturn output\n\n# Batch delete storage objects.\nclass ApiDeleteStorageObjectsRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"object_ids\": {\"name\": \"_object_ids\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiDeleteStorageObjectId\"},\n\t}\n\n\t# Batch of storage objects.\n\tvar _object_ids\n\tvar object_ids : Array:\n\t\tget:\n\t\t\treturn Array() if not _object_ids is Array else Array(_object_ids)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiDeleteStorageObjectsRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiDeleteStorageObjectsRequest\", p_dict), ApiDeleteStorageObjectsRequest) as ApiDeleteStorageObjectsRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"object_ids: %s, \" % [_object_ids]\n\t\treturn output\n\n# Represents an event to be passed through the server to registered event handlers.\nclass ApiEvent extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"external\": {\"name\": \"_external\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"properties\": {\"name\": \"_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"timestamp\": {\"name\": \"_timestamp\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# True if the event came directly from a client call, false otherwise.\n\tvar _external\n\tvar external : bool:\n\t\tget:\n\t\t\treturn false if not _external is bool else bool(_external)\n\n\t# An event name, type, category, or identifier.\n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\n\t# Arbitrary event property values.\n\tvar _properties\n\tvar properties : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _properties is Dictionary else _properties.duplicate()\n\n\t# The time when the event was triggered.\n\tvar _timestamp\n\tvar timestamp : String:\n\t\tget:\n\t\t\treturn \"\" if not _timestamp is String else String(_timestamp)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiEvent:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiEvent\", p_dict), ApiEvent) as ApiEvent\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"external: %s, \" % _external\n\t\toutput += \"name: %s, \" % _name\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_properties) == TYPE_DICTIONARY:\n\t\t\tfor k in _properties:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _properties[k]]\n\t\toutput += \"properties: [%s], \" % map_string\n\t\toutput += \"timestamp: %s, \" % _timestamp\n\t\treturn output\n\n# A friend of a user.\nclass ApiFriend extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"state\": {\"name\": \"_state\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user\": {\"name\": \"_user\", \"type\": \"ApiUser\", \"required\": false},\n\t}\n\n\t# The friend status.\n\tvar _state\n\tvar state : int:\n\t\tget:\n\t\t\treturn 0 if not _state is int else int(_state)\n\n\t# Time of the latest relationship update.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# The user object.\n\tvar _user\n\tvar user : ApiUser:\n\t\tget:\n\t\t\treturn _user as ApiUser\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFriend:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiFriend\", p_dict), ApiFriend) as ApiFriend\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"state: %s, \" % _state\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"user: %s, \" % _user\n\t\treturn output\n\n# A collection of zero or more friends of the user.\nclass ApiFriendList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"friends\": {\"name\": \"_friends\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiFriend\"},\n\t}\n\n\t# Cursor for the next page of results, if any.\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# The Friend objects.\n\tvar _friends\n\tvar friends : Array:\n\t\tget:\n\t\t\treturn Array() if not _friends is Array else Array(_friends)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFriendList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiFriendList\", p_dict), ApiFriendList) as ApiFriendList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"friends: %s, \" % [_friends]\n\t\treturn output\n\n# A group in the server.\nclass ApiGroup extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"avatar_url\": {\"name\": \"_avatar_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"creator_id\": {\"name\": \"_creator_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"description\": {\"name\": \"_description\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"edge_count\": {\"name\": \"_edge_count\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"lang_tag\": {\"name\": \"_lang_tag\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"max_count\": {\"name\": \"_max_count\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"open\": {\"name\": \"_open\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# A URL for an avatar image.\n\tvar _avatar_url\n\tvar avatar_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _avatar_url is String else String(_avatar_url)\n\n\t# The UNIX time when the group was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# The id of the user who created the group.\n\tvar _creator_id\n\tvar creator_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _creator_id is String else String(_creator_id)\n\n\t# A description for the group.\n\tvar _description\n\tvar description : String:\n\t\tget:\n\t\t\treturn \"\" if not _description is String else String(_description)\n\n\t# The current count of all members in the group.\n\tvar _edge_count\n\tvar edge_count : int:\n\t\tget:\n\t\t\treturn 0 if not _edge_count is int else int(_edge_count)\n\n\t# The id of a group.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# The language expected to be a tag which follows the BCP-47 spec.\n\tvar _lang_tag\n\tvar lang_tag : String:\n\t\tget:\n\t\t\treturn \"\" if not _lang_tag is String else String(_lang_tag)\n\n\t# The maximum number of members allowed.\n\tvar _max_count\n\tvar max_count : int:\n\t\tget:\n\t\t\treturn 0 if not _max_count is int else int(_max_count)\n\n\t# Additional information stored as a JSON object.\n\tvar _metadata\n\tvar metadata : String:\n\t\tget:\n\t\t\treturn \"\" if not _metadata is String else String(_metadata)\n\n\t# The unique name of the group.\n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\n\t# Anyone can join open groups, otherwise only admins can accept members.\n\tvar _open\n\tvar open : bool:\n\t\tget:\n\t\t\treturn false if not _open is bool else bool(_open)\n\n\t# The UNIX time when the group was last updated.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGroup:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiGroup\", p_dict), ApiGroup) as ApiGroup\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"avatar_url: %s, \" % _avatar_url\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"creator_id: %s, \" % _creator_id\n\t\toutput += \"description: %s, \" % _description\n\t\toutput += \"edge_count: %s, \" % _edge_count\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += \"lang_tag: %s, \" % _lang_tag\n\t\toutput += \"max_count: %s, \" % _max_count\n\t\toutput += \"metadata: %s, \" % _metadata\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"open: %s, \" % _open\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\treturn output\n\n# One or more groups returned from a listing operation.\nclass ApiGroupList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"groups\": {\"name\": \"_groups\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiGroup\"},\n\t}\n\n\t# A cursor used to get the next page.\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# One or more groups.\n\tvar _groups\n\tvar groups : Array:\n\t\tget:\n\t\t\treturn Array() if not _groups is Array else Array(_groups)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGroupList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiGroupList\", p_dict), ApiGroupList) as ApiGroupList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"groups: %s, \" % [_groups]\n\t\treturn output\n\n# A list of users belonging to a group, along with their role.\nclass ApiGroupUserList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"group_users\": {\"name\": \"_group_users\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"GroupUserListGroupUser\"},\n\t}\n\n\t# Cursor for the next page of results, if any.\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# User-role pairs for a group.\n\tvar _group_users\n\tvar group_users : Array:\n\t\tget:\n\t\t\treturn Array() if not _group_users is Array else Array(_group_users)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGroupUserList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiGroupUserList\", p_dict), ApiGroupUserList) as ApiGroupUserList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"group_users: %s, \" % [_group_users]\n\t\treturn output\n\n# Represents a complete leaderboard record with all scores and associated metadata.\nclass ApiLeaderboardRecord extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"expiry_time\": {\"name\": \"_expiry_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"leaderboard_id\": {\"name\": \"_leaderboard_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"max_num_score\": {\"name\": \"_max_num_score\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"num_score\": {\"name\": \"_num_score\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"owner_id\": {\"name\": \"_owner_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"rank\": {\"name\": \"_rank\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"score\": {\"name\": \"_score\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"subscore\": {\"name\": \"_subscore\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"username\": {\"name\": \"_username\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The UNIX time when the leaderboard record was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# The UNIX time when the leaderboard record expires.\n\tvar _expiry_time\n\tvar expiry_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _expiry_time is String else String(_expiry_time)\n\n\t# The ID of the leaderboard this score belongs to.\n\tvar _leaderboard_id\n\tvar leaderboard_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _leaderboard_id is String else String(_leaderboard_id)\n\n\t# The maximum number of score updates allowed by the owner.\n\tvar _max_num_score\n\tvar max_num_score : int:\n\t\tget:\n\t\t\treturn 0 if not _max_num_score is int else int(_max_num_score)\n\n\t# Metadata.\n\tvar _metadata\n\tvar metadata : String:\n\t\tget:\n\t\t\treturn \"\" if not _metadata is String else String(_metadata)\n\n\t# The number of submissions to this score record.\n\tvar _num_score\n\tvar num_score : int:\n\t\tget:\n\t\t\treturn 0 if not _num_score is int else int(_num_score)\n\n\t# The ID of the score owner, usually a user or group.\n\tvar _owner_id\n\tvar owner_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _owner_id is String else String(_owner_id)\n\n\t# The rank of this record.\n\tvar _rank\n\tvar rank : String:\n\t\tget:\n\t\t\treturn \"\" if not _rank is String else String(_rank)\n\n\t# The score value.\n\tvar _score\n\tvar score : String:\n\t\tget:\n\t\t\treturn \"\" if not _score is String else String(_score)\n\n\t# An optional subscore value.\n\tvar _subscore\n\tvar subscore : String:\n\t\tget:\n\t\t\treturn \"\" if not _subscore is String else String(_subscore)\n\n\t# The UNIX time when the leaderboard record was updated.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# The username of the score owner, if the owner is a user.\n\tvar _username\n\tvar username : String:\n\t\tget:\n\t\t\treturn \"\" if not _username is String else String(_username)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLeaderboardRecord:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiLeaderboardRecord\", p_dict), ApiLeaderboardRecord) as ApiLeaderboardRecord\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"expiry_time: %s, \" % _expiry_time\n\t\toutput += \"leaderboard_id: %s, \" % _leaderboard_id\n\t\toutput += \"max_num_score: %s, \" % _max_num_score\n\t\toutput += \"metadata: %s, \" % _metadata\n\t\toutput += \"num_score: %s, \" % _num_score\n\t\toutput += \"owner_id: %s, \" % _owner_id\n\t\toutput += \"rank: %s, \" % _rank\n\t\toutput += \"score: %s, \" % _score\n\t\toutput += \"subscore: %s, \" % _subscore\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"username: %s, \" % _username\n\t\treturn output\n\n# A set of leaderboard records, may be part of a leaderboard records page or a batch of individual records.\nclass ApiLeaderboardRecordList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"next_cursor\": {\"name\": \"_next_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"owner_records\": {\"name\": \"_owner_records\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiLeaderboardRecord\"},\n\t\t\"prev_cursor\": {\"name\": \"_prev_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"records\": {\"name\": \"_records\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiLeaderboardRecord\"},\n\t}\n\n\t# The cursor to send when retrieving the next page, if any.\n\tvar _next_cursor\n\tvar next_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _next_cursor is String else String(_next_cursor)\n\n\t# A batched set of leaderboard records belonging to specified owners.\n\tvar _owner_records\n\tvar owner_records : Array:\n\t\tget:\n\t\t\treturn Array() if not _owner_records is Array else Array(_owner_records)\n\n\t# The cursor to send when retrieving the previous page, if any.\n\tvar _prev_cursor\n\tvar prev_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _prev_cursor is String else String(_prev_cursor)\n\n\t# A list of leaderboard records.\n\tvar _records\n\tvar records : Array:\n\t\tget:\n\t\t\treturn Array() if not _records is Array else Array(_records)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLeaderboardRecordList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiLeaderboardRecordList\", p_dict), ApiLeaderboardRecordList) as ApiLeaderboardRecordList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"next_cursor: %s, \" % _next_cursor\n\t\toutput += \"owner_records: %s, \" % [_owner_records]\n\t\toutput += \"prev_cursor: %s, \" % _prev_cursor\n\t\toutput += \"records: %s, \" % [_records]\n\t\treturn output\n\n# Link Steam to the current user's account.\nclass ApiLinkSteamRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"account\": {\"name\": \"_account\", \"type\": \"ApiAccountSteam\", \"required\": false},\n\t\t\"sync\": {\"name\": \"_sync\", \"type\": TYPE_BOOL, \"required\": false},\n\t}\n\n\t# The Facebook account details.\n\tvar _account\n\tvar account : ApiAccountSteam:\n\t\tget:\n\t\t\treturn _account as ApiAccountSteam\n\n\t# Import Steam friends for the user.\n\tvar _sync\n\tvar sync : bool:\n\t\tget:\n\t\t\treturn false if not _sync is bool else bool(_sync)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLinkSteamRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiLinkSteamRequest\", p_dict), ApiLinkSteamRequest) as ApiLinkSteamRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"account: %s, \" % _account\n\t\toutput += \"sync: %s, \" % _sync\n\t\treturn output\n\n# List user subscriptions.\nclass ApiListSubscriptionsRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"limit\": {\"name\": \"_limit\", \"type\": TYPE_INT, \"required\": false},\n\t}\n\n\t#\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t#\n\tvar _limit\n\tvar limit : int:\n\t\tget:\n\t\t\treturn 0 if not _limit is int else int(_limit)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiListSubscriptionsRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiListSubscriptionsRequest\", p_dict), ApiListSubscriptionsRequest) as ApiListSubscriptionsRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"limit: %s, \" % _limit\n\t\treturn output\n\n# Represents a realtime match.\nclass ApiMatch extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"authoritative\": {\"name\": \"_authoritative\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"handler_name\": {\"name\": \"_handler_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"label\": {\"name\": \"_label\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"match_id\": {\"name\": \"_match_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"size\": {\"name\": \"_size\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"tick_rate\": {\"name\": \"_tick_rate\", \"type\": TYPE_INT, \"required\": false},\n\t}\n\n\t# True if it's an server-managed authoritative match, false otherwise.\n\tvar _authoritative\n\tvar authoritative : bool:\n\t\tget:\n\t\t\treturn false if not _authoritative is bool else bool(_authoritative)\n\n\t#\n\tvar _handler_name\n\tvar handler_name : String:\n\t\tget:\n\t\t\treturn \"\" if not _handler_name is String else String(_handler_name)\n\n\t# Match label, if any.\n\tvar _label\n\tvar label : String:\n\t\tget:\n\t\t\treturn \"\" if not _label is String else String(_label)\n\n\t# The ID of the match, can be used to join.\n\tvar _match_id\n\tvar match_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _match_id is String else String(_match_id)\n\n\t# Current number of users in the match.\n\tvar _size\n\tvar size : int:\n\t\tget:\n\t\t\treturn 0 if not _size is int else int(_size)\n\n\t#\n\tvar _tick_rate\n\tvar tick_rate : int:\n\t\tget:\n\t\t\treturn 0 if not _tick_rate is int else int(_tick_rate)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiMatch:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiMatch\", p_dict), ApiMatch) as ApiMatch\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"authoritative: %s, \" % _authoritative\n\t\toutput += \"handler_name: %s, \" % _handler_name\n\t\toutput += \"label: %s, \" % _label\n\t\toutput += \"match_id: %s, \" % _match_id\n\t\toutput += \"size: %s, \" % _size\n\t\toutput += \"tick_rate: %s, \" % _tick_rate\n\t\treturn output\n\n# A list of realtime matches.\nclass ApiMatchList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"matches\": {\"name\": \"_matches\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiMatch\"},\n\t}\n\n\t# A number of matches corresponding to a list operation.\n\tvar _matches\n\tvar matches : Array:\n\t\tget:\n\t\t\treturn Array() if not _matches is Array else Array(_matches)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiMatchList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiMatchList\", p_dict), ApiMatchList) as ApiMatchList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"matches: %s, \" % [_matches]\n\t\treturn output\n\n# A notification in the server.\nclass ApiNotification extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"code\": {\"name\": \"_code\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"content\": {\"name\": \"_content\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"persistent\": {\"name\": \"_persistent\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"sender_id\": {\"name\": \"_sender_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"subject\": {\"name\": \"_subject\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Category code for this notification.\n\tvar _code\n\tvar code : int:\n\t\tget:\n\t\t\treturn 0 if not _code is int else int(_code)\n\n\t# Content of the notification in JSON.\n\tvar _content\n\tvar content : String:\n\t\tget:\n\t\t\treturn \"\" if not _content is String else String(_content)\n\n\t# The UNIX time when the notification was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# ID of the Notification.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# True if this notification was persisted to the database.\n\tvar _persistent\n\tvar persistent : bool:\n\t\tget:\n\t\t\treturn false if not _persistent is bool else bool(_persistent)\n\n\t# ID of the sender, if a user. Otherwise 'null'.\n\tvar _sender_id\n\tvar sender_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _sender_id is String else String(_sender_id)\n\n\t# Subject of the notification.\n\tvar _subject\n\tvar subject : String:\n\t\tget:\n\t\t\treturn \"\" if not _subject is String else String(_subject)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiNotification:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiNotification\", p_dict), ApiNotification) as ApiNotification\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"code: %s, \" % _code\n\t\toutput += \"content: %s, \" % _content\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += \"persistent: %s, \" % _persistent\n\t\toutput += \"sender_id: %s, \" % _sender_id\n\t\toutput += \"subject: %s, \" % _subject\n\t\treturn output\n\n# A collection of zero or more notifications.\nclass ApiNotificationList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cacheable_cursor\": {\"name\": \"_cacheable_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"notifications\": {\"name\": \"_notifications\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiNotification\"},\n\t}\n\n\t# Use this cursor to paginate notifications. Cache this to catch up to new notifications.\n\tvar _cacheable_cursor\n\tvar cacheable_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cacheable_cursor is String else String(_cacheable_cursor)\n\n\t# Collection of notifications.\n\tvar _notifications\n\tvar notifications : Array:\n\t\tget:\n\t\t\treturn Array() if not _notifications is Array else Array(_notifications)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiNotificationList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiNotificationList\", p_dict), ApiNotificationList) as ApiNotificationList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cacheable_cursor: %s, \" % _cacheable_cursor\n\t\toutput += \"notifications: %s, \" % [_notifications]\n\t\treturn output\n\n# Operator that can be used to override the one set in the leaderboard.\n#  - NO_OVERRIDE: Do not override the leaderboard operator.\n#  - BEST: Override the leaderboard operator with BEST.\n#  - SET: Override the leaderboard operator with SET.\n#  - INCREMENT: Override the leaderboard operator with INCREMENT.\n#  - DECREMENT: Override the leaderboard operator with DECREMENT.# [ - NO_OVERRIDE: Do not override the leaderboard operator.  - BEST: Override the leaderboard operator with BEST.  - SET: Override the leaderboard operator with SET.  - INCREMENT: Override the leaderboard operator with INCREMENT.  - DECREMENT: Override the leaderboard operator with DECREMENT.]\nenum ApiOperator {NO_OVERRIDE = 0,BEST = 1,SET = 2,INCREMENT = 3,DECREMENT = 4,}\n\n# Storage objects to get.\nclass ApiReadStorageObjectId extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"collection\": {\"name\": \"_collection\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"key\": {\"name\": \"_key\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id\": {\"name\": \"_user_id\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The collection which stores the object.\n\tvar _collection\n\tvar collection : String:\n\t\tget:\n\t\t\treturn \"\" if not _collection is String else String(_collection)\n\n\t# The key of the object within the collection.\n\tvar _key\n\tvar key : String:\n\t\tget:\n\t\t\treturn \"\" if not _key is String else String(_key)\n\n\t# The user owner of the object.\n\tvar _user_id\n\tvar user_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id is String else String(_user_id)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiReadStorageObjectId:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiReadStorageObjectId\", p_dict), ApiReadStorageObjectId) as ApiReadStorageObjectId\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"collection: %s, \" % _collection\n\t\toutput += \"key: %s, \" % _key\n\t\toutput += \"user_id: %s, \" % _user_id\n\t\treturn output\n\n# Batch get storage objects.\nclass ApiReadStorageObjectsRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"object_ids\": {\"name\": \"_object_ids\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiReadStorageObjectId\"},\n\t}\n\n\t# Batch of storage objects.\n\tvar _object_ids\n\tvar object_ids : Array:\n\t\tget:\n\t\t\treturn Array() if not _object_ids is Array else Array(_object_ids)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiReadStorageObjectsRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiReadStorageObjectsRequest\", p_dict), ApiReadStorageObjectsRequest) as ApiReadStorageObjectsRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"object_ids: %s, \" % [_object_ids]\n\t\treturn output\n\n# Execute an Lua function on the server.\nclass ApiRpc extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"http_key\": {\"name\": \"_http_key\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"payload\": {\"name\": \"_payload\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The authentication key used when executed as a non-client HTTP request.\n\tvar _http_key\n\tvar http_key : String:\n\t\tget:\n\t\t\treturn \"\" if not _http_key is String else String(_http_key)\n\n\t# The identifier of the function.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# The payload of the function which must be a JSON object.\n\tvar _payload\n\tvar payload : String:\n\t\tget:\n\t\t\treturn \"\" if not _payload is String else String(_payload)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiRpc:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiRpc\", p_dict), ApiRpc) as ApiRpc\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"http_key: %s, \" % _http_key\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += \"payload: %s, \" % _payload\n\t\treturn output\n\n# A user's session used to authenticate messages.\nclass ApiSession extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"created\": {\"name\": \"_created\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"refresh_token\": {\"name\": \"_refresh_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# True if the corresponding account was just created, false otherwise.\n\tvar _created\n\tvar created : bool:\n\t\tget:\n\t\t\treturn false if not _created is bool else bool(_created)\n\n\t# Refresh token that can be used for session token renewal.\n\tvar _refresh_token\n\tvar refresh_token : String:\n\t\tget:\n\t\t\treturn \"\" if not _refresh_token is String else String(_refresh_token)\n\n\t# Authentication credentials.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSession:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiSession\", p_dict), ApiSession) as ApiSession\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"created: %s, \" % _created\n\t\toutput += \"refresh_token: %s, \" % _refresh_token\n\t\toutput += \"token: %s, \" % _token\n\t\treturn output\n\n# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.\nclass ApiSessionLogoutRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"refresh_token\": {\"name\": \"_refresh_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Refresh token to invalidate.\n\tvar _refresh_token\n\tvar refresh_token : String:\n\t\tget:\n\t\t\treturn \"\" if not _refresh_token is String else String(_refresh_token)\n\n\t# Session token to log out.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSessionLogoutRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiSessionLogoutRequest\", p_dict), ApiSessionLogoutRequest) as ApiSessionLogoutRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"refresh_token: %s, \" % _refresh_token\n\t\toutput += \"token: %s, \" % _token\n\t\treturn output\n\n# Authenticate against the server with a refresh token.\nclass ApiSessionRefreshRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"token\": {\"name\": \"_token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"vars\": {\"name\": \"_vars\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# Refresh token.\n\tvar _token\n\tvar token : String:\n\t\tget:\n\t\t\treturn \"\" if not _token is String else String(_token)\n\n\t# Extra information that will be bundled in the session token.\n\tvar _vars\n\tvar vars : Dictionary:\n\t\tget:\n\t\t\treturn Dictionary() if not _vars is Dictionary else _vars.duplicate()\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSessionRefreshRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiSessionRefreshRequest\", p_dict), ApiSessionRefreshRequest) as ApiSessionRefreshRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"token: %s, \" % _token\n\t\tvar map_string : String = \"\"\n\t\tif typeof(_vars) == TYPE_DICTIONARY:\n\t\t\tfor k in _vars:\n\t\t\t\tmap_string += \"{%s=%s}, \" % [k, _vars[k]]\n\t\toutput += \"vars: [%s], \" % map_string\n\t\treturn output\n\n# An object within the storage engine.\nclass ApiStorageObject extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"collection\": {\"name\": \"_collection\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"key\": {\"name\": \"_key\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"permission_read\": {\"name\": \"_permission_read\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"permission_write\": {\"name\": \"_permission_write\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id\": {\"name\": \"_user_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"version\": {\"name\": \"_version\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The collection which stores the object.\n\tvar _collection\n\tvar collection : String:\n\t\tget:\n\t\t\treturn \"\" if not _collection is String else String(_collection)\n\n\t# The UNIX time when the object was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# The key of the object within the collection.\n\tvar _key\n\tvar key : String:\n\t\tget:\n\t\t\treturn \"\" if not _key is String else String(_key)\n\n\t# The read access permissions for the object.\n\tvar _permission_read\n\tvar permission_read : int:\n\t\tget:\n\t\t\treturn 0 if not _permission_read is int else int(_permission_read)\n\n\t# The write access permissions for the object.\n\tvar _permission_write\n\tvar permission_write : int:\n\t\tget:\n\t\t\treturn 0 if not _permission_write is int else int(_permission_write)\n\n\t# The UNIX time when the object was last updated.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# The user owner of the object.\n\tvar _user_id\n\tvar user_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id is String else String(_user_id)\n\n\t# The value of the object.\n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\t# The version hash of the object.\n\tvar _version\n\tvar version : String:\n\t\tget:\n\t\t\treturn \"\" if not _version is String else String(_version)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObject:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiStorageObject\", p_dict), ApiStorageObject) as ApiStorageObject\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"collection: %s, \" % _collection\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"key: %s, \" % _key\n\t\toutput += \"permission_read: %s, \" % _permission_read\n\t\toutput += \"permission_write: %s, \" % _permission_write\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"user_id: %s, \" % _user_id\n\t\toutput += \"value: %s, \" % _value\n\t\toutput += \"version: %s, \" % _version\n\t\treturn output\n\n# A storage acknowledgement.\nclass ApiStorageObjectAck extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"collection\": {\"name\": \"_collection\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"key\": {\"name\": \"_key\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id\": {\"name\": \"_user_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"version\": {\"name\": \"_version\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The collection which stores the object.\n\tvar _collection\n\tvar collection : String:\n\t\tget:\n\t\t\treturn \"\" if not _collection is String else String(_collection)\n\n\t# The key of the object within the collection.\n\tvar _key\n\tvar key : String:\n\t\tget:\n\t\t\treturn \"\" if not _key is String else String(_key)\n\n\t# The owner of the object.\n\tvar _user_id\n\tvar user_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id is String else String(_user_id)\n\n\t# The version hash of the object.\n\tvar _version\n\tvar version : String:\n\t\tget:\n\t\t\treturn \"\" if not _version is String else String(_version)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjectAck:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiStorageObjectAck\", p_dict), ApiStorageObjectAck) as ApiStorageObjectAck\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"collection: %s, \" % _collection\n\t\toutput += \"key: %s, \" % _key\n\t\toutput += \"user_id: %s, \" % _user_id\n\t\toutput += \"version: %s, \" % _version\n\t\treturn output\n\n# Batch of acknowledgements for the storage object write.\nclass ApiStorageObjectAcks extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"acks\": {\"name\": \"_acks\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiStorageObjectAck\"},\n\t}\n\n\t# Batch of storage write acknowledgements.\n\tvar _acks\n\tvar acks : Array:\n\t\tget:\n\t\t\treturn Array() if not _acks is Array else Array(_acks)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjectAcks:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiStorageObjectAcks\", p_dict), ApiStorageObjectAcks) as ApiStorageObjectAcks\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"acks: %s, \" % [_acks]\n\t\treturn output\n\n# List of storage objects.\nclass ApiStorageObjectList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"objects\": {\"name\": \"_objects\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiStorageObject\"},\n\t}\n\n\t# The cursor for the next page of results, if any.\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# The list of storage objects.\n\tvar _objects\n\tvar objects : Array:\n\t\tget:\n\t\t\treturn Array() if not _objects is Array else Array(_objects)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjectList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiStorageObjectList\", p_dict), ApiStorageObjectList) as ApiStorageObjectList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"objects: %s, \" % [_objects]\n\t\treturn output\n\n# Batch of storage objects.\nclass ApiStorageObjects extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"objects\": {\"name\": \"_objects\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiStorageObject\"},\n\t}\n\n\t# The batch of storage objects.\n\tvar _objects\n\tvar objects : Array:\n\t\tget:\n\t\t\treturn Array() if not _objects is Array else Array(_objects)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjects:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiStorageObjects\", p_dict), ApiStorageObjects) as ApiStorageObjects\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"objects: %s, \" % [_objects]\n\t\treturn output\n\n# Environment where a purchase/subscription took place,\n# - UNKNOWN: Unknown environment.\n#  - SANDBOX: Sandbox/test environment.\n#  - PRODUCTION: Production environment.# [- UNKNOWN: Unknown environment.  - SANDBOX: Sandbox/test environment.  - PRODUCTION: Production environment.]\nenum ApiStoreEnvironment {UNKNOWN = 0,SANDBOX = 1,PRODUCTION = 2,}\n\n# Validation Provider,\n# - APPLE_APP_STORE: Apple App Store\n#  - GOOGLE_PLAY_STORE: Google Play Store\n#  - HUAWEI_APP_GALLERY: Huawei App Gallery# [- APPLE_APP_STORE: Apple App Store  - GOOGLE_PLAY_STORE: Google Play Store  - HUAWEI_APP_GALLERY: Huawei App Gallery]\nenum ApiStoreProvider {APPLE_APP_STORE = 0,GOOGLE_PLAY_STORE = 1,HUAWEI_APP_GALLERY = 2,}\n\n# A list of validated subscriptions stored by Nakama.\nclass ApiSubscriptionList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"prev_cursor\": {\"name\": \"_prev_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"validated_subscriptions\": {\"name\": \"_validated_subscriptions\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiValidatedSubscription\"},\n\t}\n\n\t# The cursor to send when retrieving the next page, if any.\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# The cursor to send when retrieving the previous page, if any.\n\tvar _prev_cursor\n\tvar prev_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _prev_cursor is String else String(_prev_cursor)\n\n\t# Stored validated subscriptions.\n\tvar _validated_subscriptions\n\tvar validated_subscriptions : Array:\n\t\tget:\n\t\t\treturn Array() if not _validated_subscriptions is Array else Array(_validated_subscriptions)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSubscriptionList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiSubscriptionList\", p_dict), ApiSubscriptionList) as ApiSubscriptionList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"prev_cursor: %s, \" % _prev_cursor\n\t\toutput += \"validated_subscriptions: %s, \" % [_validated_subscriptions]\n\t\treturn output\n\n# A tournament on the server.\nclass ApiTournament extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"authoritative\": {\"name\": \"_authoritative\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"can_enter\": {\"name\": \"_can_enter\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"category\": {\"name\": \"_category\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"description\": {\"name\": \"_description\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"duration\": {\"name\": \"_duration\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"end_active\": {\"name\": \"_end_active\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"end_time\": {\"name\": \"_end_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"max_num_score\": {\"name\": \"_max_num_score\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"max_size\": {\"name\": \"_max_size\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"next_reset\": {\"name\": \"_next_reset\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"operator\": {\"name\": \"_operator\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"prev_reset\": {\"name\": \"_prev_reset\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"size\": {\"name\": \"_size\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"sort_order\": {\"name\": \"_sort_order\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"start_active\": {\"name\": \"_start_active\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"start_time\": {\"name\": \"_start_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"title\": {\"name\": \"_title\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Whether the leaderboard was created authoritatively or not.\n\tvar _authoritative\n\tvar authoritative : bool:\n\t\tget:\n\t\t\treturn false if not _authoritative is bool else bool(_authoritative)\n\n\t# True if the tournament is active and can enter. A computed value.\n\tvar _can_enter\n\tvar can_enter : bool:\n\t\tget:\n\t\t\treturn false if not _can_enter is bool else bool(_can_enter)\n\n\t# The category of the tournament. e.g. \"vip\" could be category 1.\n\tvar _category\n\tvar category : int:\n\t\tget:\n\t\t\treturn 0 if not _category is int else int(_category)\n\n\t# The UNIX time when the tournament was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# The description of the tournament. May be blank.\n\tvar _description\n\tvar description : String:\n\t\tget:\n\t\t\treturn \"\" if not _description is String else String(_description)\n\n\t# Duration of the tournament in seconds.\n\tvar _duration\n\tvar duration : int:\n\t\tget:\n\t\t\treturn 0 if not _duration is int else int(_duration)\n\n\t# The UNIX time when the tournament stops being active until next reset. A computed value.\n\tvar _end_active\n\tvar end_active : int:\n\t\tget:\n\t\t\treturn 0 if not _end_active is int else int(_end_active)\n\n\t# The UNIX time when the tournament will be stopped.\n\tvar _end_time\n\tvar end_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _end_time is String else String(_end_time)\n\n\t# The ID of the tournament.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# The maximum score updates allowed per player for the current tournament.\n\tvar _max_num_score\n\tvar max_num_score : int:\n\t\tget:\n\t\t\treturn 0 if not _max_num_score is int else int(_max_num_score)\n\n\t# The maximum number of players for the tournament.\n\tvar _max_size\n\tvar max_size : int:\n\t\tget:\n\t\t\treturn 0 if not _max_size is int else int(_max_size)\n\n\t# Additional information stored as a JSON object.\n\tvar _metadata\n\tvar metadata : String:\n\t\tget:\n\t\t\treturn \"\" if not _metadata is String else String(_metadata)\n\n\t# The UNIX time when the tournament is next playable. A computed value.\n\tvar _next_reset\n\tvar next_reset : int:\n\t\tget:\n\t\t\treturn 0 if not _next_reset is int else int(_next_reset)\n\n\t# Operator.\n\tvar _operator\n\tvar operator : int:\n\t\tget:\n\t\t\treturn ApiOperator.values()[0] if not ApiOperator.values().has(_operator) else _operator\n\n\t# The UNIX time when the tournament was last reset. A computed value.\n\tvar _prev_reset\n\tvar prev_reset : int:\n\t\tget:\n\t\t\treturn 0 if not _prev_reset is int else int(_prev_reset)\n\n\t# The current number of players in the tournament.\n\tvar _size\n\tvar size : int:\n\t\tget:\n\t\t\treturn 0 if not _size is int else int(_size)\n\n\t# ASC (0) or DESC (1) sort mode of scores in the tournament.\n\tvar _sort_order\n\tvar sort_order : int:\n\t\tget:\n\t\t\treturn 0 if not _sort_order is int else int(_sort_order)\n\n\t# The UNIX time when the tournament start being active. A computed value.\n\tvar _start_active\n\tvar start_active : int:\n\t\tget:\n\t\t\treturn 0 if not _start_active is int else int(_start_active)\n\n\t# The UNIX time when the tournament will start.\n\tvar _start_time\n\tvar start_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _start_time is String else String(_start_time)\n\n\t# The title for the tournament.\n\tvar _title\n\tvar title : String:\n\t\tget:\n\t\t\treturn \"\" if not _title is String else String(_title)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiTournament:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiTournament\", p_dict), ApiTournament) as ApiTournament\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"authoritative: %s, \" % _authoritative\n\t\toutput += \"can_enter: %s, \" % _can_enter\n\t\toutput += \"category: %s, \" % _category\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"description: %s, \" % _description\n\t\toutput += \"duration: %s, \" % _duration\n\t\toutput += \"end_active: %s, \" % _end_active\n\t\toutput += \"end_time: %s, \" % _end_time\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += \"max_num_score: %s, \" % _max_num_score\n\t\toutput += \"max_size: %s, \" % _max_size\n\t\toutput += \"metadata: %s, \" % _metadata\n\t\toutput += \"next_reset: %s, \" % _next_reset\n\t\toutput += \"operator: %s, \" % _operator\n\t\toutput += \"prev_reset: %s, \" % _prev_reset\n\t\toutput += \"size: %s, \" % _size\n\t\toutput += \"sort_order: %s, \" % _sort_order\n\t\toutput += \"start_active: %s, \" % _start_active\n\t\toutput += \"start_time: %s, \" % _start_time\n\t\toutput += \"title: %s, \" % _title\n\t\treturn output\n\n# A list of tournaments.\nclass ApiTournamentList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"tournaments\": {\"name\": \"_tournaments\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiTournament\"},\n\t}\n\n\t# A pagination cursor (optional).\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# The list of tournaments returned.\n\tvar _tournaments\n\tvar tournaments : Array:\n\t\tget:\n\t\t\treturn Array() if not _tournaments is Array else Array(_tournaments)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiTournamentList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiTournamentList\", p_dict), ApiTournamentList) as ApiTournamentList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"tournaments: %s, \" % [_tournaments]\n\t\treturn output\n\n# A set of tournament records which may be part of a tournament records page or a batch of individual records.\nclass ApiTournamentRecordList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"next_cursor\": {\"name\": \"_next_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"owner_records\": {\"name\": \"_owner_records\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiLeaderboardRecord\"},\n\t\t\"prev_cursor\": {\"name\": \"_prev_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"records\": {\"name\": \"_records\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiLeaderboardRecord\"},\n\t}\n\n\t# The cursor to send when retireving the next page (optional).\n\tvar _next_cursor\n\tvar next_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _next_cursor is String else String(_next_cursor)\n\n\t# A batched set of tournament records belonging to specified owners.\n\tvar _owner_records\n\tvar owner_records : Array:\n\t\tget:\n\t\t\treturn Array() if not _owner_records is Array else Array(_owner_records)\n\n\t# The cursor to send when retrieving the previous page (optional).\n\tvar _prev_cursor\n\tvar prev_cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _prev_cursor is String else String(_prev_cursor)\n\n\t# A list of tournament records.\n\tvar _records\n\tvar records : Array:\n\t\tget:\n\t\t\treturn Array() if not _records is Array else Array(_records)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiTournamentRecordList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiTournamentRecordList\", p_dict), ApiTournamentRecordList) as ApiTournamentRecordList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"next_cursor: %s, \" % _next_cursor\n\t\toutput += \"owner_records: %s, \" % [_owner_records]\n\t\toutput += \"prev_cursor: %s, \" % _prev_cursor\n\t\toutput += \"records: %s, \" % [_records]\n\t\treturn output\n\n# Update a user's account details.\nclass ApiUpdateAccountRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"avatar_url\": {\"name\": \"_avatar_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"display_name\": {\"name\": \"_display_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"lang_tag\": {\"name\": \"_lang_tag\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"location\": {\"name\": \"_location\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"timezone\": {\"name\": \"_timezone\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"username\": {\"name\": \"_username\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# A URL for an avatar image.\n\tvar _avatar_url\n\tvar avatar_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _avatar_url is String else String(_avatar_url)\n\n\t# The display name of the user.\n\tvar _display_name\n\tvar display_name : String:\n\t\tget:\n\t\t\treturn \"\" if not _display_name is String else String(_display_name)\n\n\t# The language expected to be a tag which follows the BCP-47 spec.\n\tvar _lang_tag\n\tvar lang_tag : String:\n\t\tget:\n\t\t\treturn \"\" if not _lang_tag is String else String(_lang_tag)\n\n\t# The location set by the user.\n\tvar _location\n\tvar location : String:\n\t\tget:\n\t\t\treturn \"\" if not _location is String else String(_location)\n\n\t# The timezone set by the user.\n\tvar _timezone\n\tvar timezone : String:\n\t\tget:\n\t\t\treturn \"\" if not _timezone is String else String(_timezone)\n\n\t# The username of the user's account.\n\tvar _username\n\tvar username : String:\n\t\tget:\n\t\t\treturn \"\" if not _username is String else String(_username)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUpdateAccountRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiUpdateAccountRequest\", p_dict), ApiUpdateAccountRequest) as ApiUpdateAccountRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"avatar_url: %s, \" % _avatar_url\n\t\toutput += \"display_name: %s, \" % _display_name\n\t\toutput += \"lang_tag: %s, \" % _lang_tag\n\t\toutput += \"location: %s, \" % _location\n\t\toutput += \"timezone: %s, \" % _timezone\n\t\toutput += \"username: %s, \" % _username\n\t\treturn output\n\n# Update fields in a given group.\nclass ApiUpdateGroupRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"avatar_url\": {\"name\": \"_avatar_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"description\": {\"name\": \"_description\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"group_id\": {\"name\": \"_group_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"lang_tag\": {\"name\": \"_lang_tag\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"name\": {\"name\": \"_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"open\": {\"name\": \"_open\", \"type\": TYPE_BOOL, \"required\": false},\n\t}\n\n\t# Avatar URL.\n\tvar _avatar_url\n\tvar avatar_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _avatar_url is String else String(_avatar_url)\n\n\t# Description string.\n\tvar _description\n\tvar description : String:\n\t\tget:\n\t\t\treturn \"\" if not _description is String else String(_description)\n\n\t# The ID of the group to update.\n\tvar _group_id\n\tvar group_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _group_id is String else String(_group_id)\n\n\t# Lang tag.\n\tvar _lang_tag\n\tvar lang_tag : String:\n\t\tget:\n\t\t\treturn \"\" if not _lang_tag is String else String(_lang_tag)\n\n\t# Name.\n\tvar _name\n\tvar name : String:\n\t\tget:\n\t\t\treturn \"\" if not _name is String else String(_name)\n\n\t# Open is true if anyone should be allowed to join, or false if joins must be approved by a group admin.\n\tvar _open\n\tvar open : bool:\n\t\tget:\n\t\t\treturn false if not _open is bool else bool(_open)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUpdateGroupRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiUpdateGroupRequest\", p_dict), ApiUpdateGroupRequest) as ApiUpdateGroupRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"avatar_url: %s, \" % _avatar_url\n\t\toutput += \"description: %s, \" % _description\n\t\toutput += \"group_id: %s, \" % _group_id\n\t\toutput += \"lang_tag: %s, \" % _lang_tag\n\t\toutput += \"name: %s, \" % _name\n\t\toutput += \"open: %s, \" % _open\n\t\treturn output\n\n# A user in the server.\nclass ApiUser extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"apple_id\": {\"name\": \"_apple_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"avatar_url\": {\"name\": \"_avatar_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"display_name\": {\"name\": \"_display_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"edge_count\": {\"name\": \"_edge_count\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"facebook_id\": {\"name\": \"_facebook_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"facebook_instant_game_id\": {\"name\": \"_facebook_instant_game_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"gamecenter_id\": {\"name\": \"_gamecenter_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"google_id\": {\"name\": \"_google_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"id\": {\"name\": \"_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"lang_tag\": {\"name\": \"_lang_tag\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"location\": {\"name\": \"_location\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"metadata\": {\"name\": \"_metadata\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"online\": {\"name\": \"_online\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"steam_id\": {\"name\": \"_steam_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"timezone\": {\"name\": \"_timezone\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"username\": {\"name\": \"_username\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The Apple Sign In ID in the user's account.\n\tvar _apple_id\n\tvar apple_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _apple_id is String else String(_apple_id)\n\n\t# A URL for an avatar image.\n\tvar _avatar_url\n\tvar avatar_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _avatar_url is String else String(_avatar_url)\n\n\t# The UNIX time when the user was created.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# The display name of the user.\n\tvar _display_name\n\tvar display_name : String:\n\t\tget:\n\t\t\treturn \"\" if not _display_name is String else String(_display_name)\n\n\t# Number of related edges to this user.\n\tvar _edge_count\n\tvar edge_count : int:\n\t\tget:\n\t\t\treturn 0 if not _edge_count is int else int(_edge_count)\n\n\t# The Facebook id in the user's account.\n\tvar _facebook_id\n\tvar facebook_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _facebook_id is String else String(_facebook_id)\n\n\t# The Facebook Instant Game ID in the user's account.\n\tvar _facebook_instant_game_id\n\tvar facebook_instant_game_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _facebook_instant_game_id is String else String(_facebook_instant_game_id)\n\n\t# The Apple Game Center in of the user's account.\n\tvar _gamecenter_id\n\tvar gamecenter_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _gamecenter_id is String else String(_gamecenter_id)\n\n\t# The Google id in the user's account.\n\tvar _google_id\n\tvar google_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _google_id is String else String(_google_id)\n\n\t# The id of the user's account.\n\tvar _id\n\tvar id : String:\n\t\tget:\n\t\t\treturn \"\" if not _id is String else String(_id)\n\n\t# The language expected to be a tag which follows the BCP-47 spec.\n\tvar _lang_tag\n\tvar lang_tag : String:\n\t\tget:\n\t\t\treturn \"\" if not _lang_tag is String else String(_lang_tag)\n\n\t# The location set by the user.\n\tvar _location\n\tvar location : String:\n\t\tget:\n\t\t\treturn \"\" if not _location is String else String(_location)\n\n\t# Additional information stored as a JSON object.\n\tvar _metadata\n\tvar metadata : String:\n\t\tget:\n\t\t\treturn \"\" if not _metadata is String else String(_metadata)\n\n\t# Indicates whether the user is currently online.\n\tvar _online\n\tvar online : bool:\n\t\tget:\n\t\t\treturn false if not _online is bool else bool(_online)\n\n\t# The Steam id in the user's account.\n\tvar _steam_id\n\tvar steam_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _steam_id is String else String(_steam_id)\n\n\t# The timezone set by the user.\n\tvar _timezone\n\tvar timezone : String:\n\t\tget:\n\t\t\treturn \"\" if not _timezone is String else String(_timezone)\n\n\t# The UNIX time when the user was last updated.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# The username of the user's account.\n\tvar _username\n\tvar username : String:\n\t\tget:\n\t\t\treturn \"\" if not _username is String else String(_username)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUser:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiUser\", p_dict), ApiUser) as ApiUser\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"apple_id: %s, \" % _apple_id\n\t\toutput += \"avatar_url: %s, \" % _avatar_url\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"display_name: %s, \" % _display_name\n\t\toutput += \"edge_count: %s, \" % _edge_count\n\t\toutput += \"facebook_id: %s, \" % _facebook_id\n\t\toutput += \"facebook_instant_game_id: %s, \" % _facebook_instant_game_id\n\t\toutput += \"gamecenter_id: %s, \" % _gamecenter_id\n\t\toutput += \"google_id: %s, \" % _google_id\n\t\toutput += \"id: %s, \" % _id\n\t\toutput += \"lang_tag: %s, \" % _lang_tag\n\t\toutput += \"location: %s, \" % _location\n\t\toutput += \"metadata: %s, \" % _metadata\n\t\toutput += \"online: %s, \" % _online\n\t\toutput += \"steam_id: %s, \" % _steam_id\n\t\toutput += \"timezone: %s, \" % _timezone\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"username: %s, \" % _username\n\t\treturn output\n\n# A list of groups belonging to a user, along with the user's role in each group.\nclass ApiUserGroupList extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"cursor\": {\"name\": \"_cursor\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_groups\": {\"name\": \"_user_groups\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserGroupListUserGroup\"},\n\t}\n\n\t# Cursor for the next page of results, if any.\n\tvar _cursor\n\tvar cursor : String:\n\t\tget:\n\t\t\treturn \"\" if not _cursor is String else String(_cursor)\n\n\t# Group-role pairs for a user.\n\tvar _user_groups\n\tvar user_groups : Array:\n\t\tget:\n\t\t\treturn Array() if not _user_groups is Array else Array(_user_groups)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUserGroupList:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiUserGroupList\", p_dict), ApiUserGroupList) as ApiUserGroupList\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"cursor: %s, \" % _cursor\n\t\toutput += \"user_groups: %s, \" % [_user_groups]\n\t\treturn output\n\n# A collection of zero or more users.\nclass ApiUsers extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"users\": {\"name\": \"_users\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiUser\"},\n\t}\n\n\t# The User objects.\n\tvar _users\n\tvar users : Array:\n\t\tget:\n\t\t\treturn Array() if not _users is Array else Array(_users)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUsers:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiUsers\", p_dict), ApiUsers) as ApiUsers\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"users: %s, \" % [_users]\n\t\treturn output\n\n#\nclass ApiValidatePurchaseAppleRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"persist\": {\"name\": \"_persist\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"receipt\": {\"name\": \"_receipt\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t#\n\tvar _persist\n\tvar persist : bool:\n\t\tget:\n\t\t\treturn false if not _persist is bool else bool(_persist)\n\n\t# Base64 encoded Apple receipt data payload.\n\tvar _receipt\n\tvar receipt : String:\n\t\tget:\n\t\t\treturn \"\" if not _receipt is String else String(_receipt)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidatePurchaseAppleRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidatePurchaseAppleRequest\", p_dict), ApiValidatePurchaseAppleRequest) as ApiValidatePurchaseAppleRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"persist: %s, \" % _persist\n\t\toutput += \"receipt: %s, \" % _receipt\n\t\treturn output\n\n#\nclass ApiValidatePurchaseGoogleRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"persist\": {\"name\": \"_persist\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"purchase\": {\"name\": \"_purchase\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t#\n\tvar _persist\n\tvar persist : bool:\n\t\tget:\n\t\t\treturn false if not _persist is bool else bool(_persist)\n\n\t# JSON encoded Google purchase payload.\n\tvar _purchase\n\tvar purchase : String:\n\t\tget:\n\t\t\treturn \"\" if not _purchase is String else String(_purchase)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidatePurchaseGoogleRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidatePurchaseGoogleRequest\", p_dict), ApiValidatePurchaseGoogleRequest) as ApiValidatePurchaseGoogleRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"persist: %s, \" % _persist\n\t\toutput += \"purchase: %s, \" % _purchase\n\t\treturn output\n\n#\nclass ApiValidatePurchaseHuaweiRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"persist\": {\"name\": \"_persist\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"purchase\": {\"name\": \"_purchase\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"signature\": {\"name\": \"_signature\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t#\n\tvar _persist\n\tvar persist : bool:\n\t\tget:\n\t\t\treturn false if not _persist is bool else bool(_persist)\n\n\t# JSON encoded Huawei InAppPurchaseData.\n\tvar _purchase\n\tvar purchase : String:\n\t\tget:\n\t\t\treturn \"\" if not _purchase is String else String(_purchase)\n\n\t# InAppPurchaseData signature.\n\tvar _signature\n\tvar signature : String:\n\t\tget:\n\t\t\treturn \"\" if not _signature is String else String(_signature)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidatePurchaseHuaweiRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidatePurchaseHuaweiRequest\", p_dict), ApiValidatePurchaseHuaweiRequest) as ApiValidatePurchaseHuaweiRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"persist: %s, \" % _persist\n\t\toutput += \"purchase: %s, \" % _purchase\n\t\toutput += \"signature: %s, \" % _signature\n\t\treturn output\n\n# Validate IAP response.\nclass ApiValidatePurchaseResponse extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"validated_purchases\": {\"name\": \"_validated_purchases\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiValidatedPurchase\"},\n\t}\n\n\t# Newly seen validated purchases.\n\tvar _validated_purchases\n\tvar validated_purchases : Array:\n\t\tget:\n\t\t\treturn Array() if not _validated_purchases is Array else Array(_validated_purchases)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidatePurchaseResponse:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidatePurchaseResponse\", p_dict), ApiValidatePurchaseResponse) as ApiValidatePurchaseResponse\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"validated_purchases: %s, \" % [_validated_purchases]\n\t\treturn output\n\n#\nclass ApiValidateSubscriptionAppleRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"persist\": {\"name\": \"_persist\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"receipt\": {\"name\": \"_receipt\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Persist the subscription.\n\tvar _persist\n\tvar persist : bool:\n\t\tget:\n\t\t\treturn false if not _persist is bool else bool(_persist)\n\n\t# Base64 encoded Apple receipt data payload.\n\tvar _receipt\n\tvar receipt : String:\n\t\tget:\n\t\t\treturn \"\" if not _receipt is String else String(_receipt)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidateSubscriptionAppleRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidateSubscriptionAppleRequest\", p_dict), ApiValidateSubscriptionAppleRequest) as ApiValidateSubscriptionAppleRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"persist: %s, \" % _persist\n\t\toutput += \"receipt: %s, \" % _receipt\n\t\treturn output\n\n#\nclass ApiValidateSubscriptionGoogleRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"persist\": {\"name\": \"_persist\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"receipt\": {\"name\": \"_receipt\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Persist the subscription.\n\tvar _persist\n\tvar persist : bool:\n\t\tget:\n\t\t\treturn false if not _persist is bool else bool(_persist)\n\n\t# JSON encoded Google purchase payload.\n\tvar _receipt\n\tvar receipt : String:\n\t\tget:\n\t\t\treturn \"\" if not _receipt is String else String(_receipt)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidateSubscriptionGoogleRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidateSubscriptionGoogleRequest\", p_dict), ApiValidateSubscriptionGoogleRequest) as ApiValidateSubscriptionGoogleRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"persist: %s, \" % _persist\n\t\toutput += \"receipt: %s, \" % _receipt\n\t\treturn output\n\n# Validate Subscription response.\nclass ApiValidateSubscriptionResponse extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"validated_subscription\": {\"name\": \"_validated_subscription\", \"type\": \"ApiValidatedSubscription\", \"required\": false},\n\t}\n\n\t#\n\tvar _validated_subscription\n\tvar validated_subscription : ApiValidatedSubscription:\n\t\tget:\n\t\t\treturn _validated_subscription as ApiValidatedSubscription\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidateSubscriptionResponse:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidateSubscriptionResponse\", p_dict), ApiValidateSubscriptionResponse) as ApiValidateSubscriptionResponse\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"validated_subscription: %s, \" % _validated_subscription\n\t\treturn output\n\n# Validated Purchase stored by Nakama.\nclass ApiValidatedPurchase extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"environment\": {\"name\": \"_environment\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"product_id\": {\"name\": \"_product_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"provider_response\": {\"name\": \"_provider_response\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"purchase_time\": {\"name\": \"_purchase_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"refund_time\": {\"name\": \"_refund_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"seen_before\": {\"name\": \"_seen_before\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"store\": {\"name\": \"_store\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"transaction_id\": {\"name\": \"_transaction_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id\": {\"name\": \"_user_id\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Timestamp when the receipt validation was stored in DB.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# Whether the purchase was done in production or sandbox environment.\n\tvar _environment\n\tvar environment : int:\n\t\tget:\n\t\t\treturn ApiStoreEnvironment.values()[0] if not ApiStoreEnvironment.values().has(_environment) else _environment\n\n\t# Purchase Product ID.\n\tvar _product_id\n\tvar product_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _product_id is String else String(_product_id)\n\n\t# Raw provider validation response.\n\tvar _provider_response\n\tvar provider_response : String:\n\t\tget:\n\t\t\treturn \"\" if not _provider_response is String else String(_provider_response)\n\n\t# Timestamp when the purchase was done.\n\tvar _purchase_time\n\tvar purchase_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _purchase_time is String else String(_purchase_time)\n\n\t#\n\tvar _refund_time\n\tvar refund_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _refund_time is String else String(_refund_time)\n\n\t# Whether the purchase had already been validated by Nakama before.\n\tvar _seen_before\n\tvar seen_before : bool:\n\t\tget:\n\t\t\treturn false if not _seen_before is bool else bool(_seen_before)\n\n\t#\n\tvar _store\n\tvar store : int:\n\t\tget:\n\t\t\treturn ApiStoreProvider.values()[0] if not ApiStoreProvider.values().has(_store) else _store\n\n\t# Purchase Transaction ID.\n\tvar _transaction_id\n\tvar transaction_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _transaction_id is String else String(_transaction_id)\n\n\t# Timestamp when the receipt validation was updated in DB.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# Purchase User ID.\n\tvar _user_id\n\tvar user_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id is String else String(_user_id)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidatedPurchase:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidatedPurchase\", p_dict), ApiValidatedPurchase) as ApiValidatedPurchase\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"environment: %s, \" % _environment\n\t\toutput += \"product_id: %s, \" % _product_id\n\t\toutput += \"provider_response: %s, \" % _provider_response\n\t\toutput += \"purchase_time: %s, \" % _purchase_time\n\t\toutput += \"refund_time: %s, \" % _refund_time\n\t\toutput += \"seen_before: %s, \" % _seen_before\n\t\toutput += \"store: %s, \" % _store\n\t\toutput += \"transaction_id: %s, \" % _transaction_id\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"user_id: %s, \" % _user_id\n\t\treturn output\n\n#\nclass ApiValidatedSubscription extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"active\": {\"name\": \"_active\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"create_time\": {\"name\": \"_create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"environment\": {\"name\": \"_environment\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"expiry_time\": {\"name\": \"_expiry_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"original_transaction_id\": {\"name\": \"_original_transaction_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"product_id\": {\"name\": \"_product_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"provider_notification\": {\"name\": \"_provider_notification\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"provider_response\": {\"name\": \"_provider_response\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"purchase_time\": {\"name\": \"_purchase_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"refund_time\": {\"name\": \"_refund_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"store\": {\"name\": \"_store\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"update_time\": {\"name\": \"_update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id\": {\"name\": \"_user_id\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# Whether the subscription is currently active or not.\n\tvar _active\n\tvar active : bool:\n\t\tget:\n\t\t\treturn false if not _active is bool else bool(_active)\n\n\t# UNIX Timestamp when the receipt validation was stored in DB.\n\tvar _create_time\n\tvar create_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _create_time is String else String(_create_time)\n\n\t# Whether the purchase was done in production or sandbox environment.\n\tvar _environment\n\tvar environment : int:\n\t\tget:\n\t\t\treturn ApiStoreEnvironment.values()[0] if not ApiStoreEnvironment.values().has(_environment) else _environment\n\n\t# Subscription expiration time. The subscription can still be auto-renewed to extend the expiration time further.\n\tvar _expiry_time\n\tvar expiry_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _expiry_time is String else String(_expiry_time)\n\n\t# Purchase Original transaction ID (we only keep track of the original subscription, not subsequent renewals).\n\tvar _original_transaction_id\n\tvar original_transaction_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _original_transaction_id is String else String(_original_transaction_id)\n\n\t# Purchase Product ID.\n\tvar _product_id\n\tvar product_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _product_id is String else String(_product_id)\n\n\t# Raw provider notification body.\n\tvar _provider_notification\n\tvar provider_notification : String:\n\t\tget:\n\t\t\treturn \"\" if not _provider_notification is String else String(_provider_notification)\n\n\t# Raw provider validation response body.\n\tvar _provider_response\n\tvar provider_response : String:\n\t\tget:\n\t\t\treturn \"\" if not _provider_response is String else String(_provider_response)\n\n\t# UNIX Timestamp when the purchase was done.\n\tvar _purchase_time\n\tvar purchase_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _purchase_time is String else String(_purchase_time)\n\n\t# Subscription refund time. If this time is set, the subscription was refunded.\n\tvar _refund_time\n\tvar refund_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _refund_time is String else String(_refund_time)\n\n\t#\n\tvar _store\n\tvar store : int:\n\t\tget:\n\t\t\treturn ApiStoreProvider.values()[0] if not ApiStoreProvider.values().has(_store) else _store\n\n\t# UNIX Timestamp when the receipt validation was updated in DB.\n\tvar _update_time\n\tvar update_time : String:\n\t\tget:\n\t\t\treturn \"\" if not _update_time is String else String(_update_time)\n\n\t# Subscription User ID.\n\tvar _user_id\n\tvar user_id : String:\n\t\tget:\n\t\t\treturn \"\" if not _user_id is String else String(_user_id)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiValidatedSubscription:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiValidatedSubscription\", p_dict), ApiValidatedSubscription) as ApiValidatedSubscription\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"active: %s, \" % _active\n\t\toutput += \"create_time: %s, \" % _create_time\n\t\toutput += \"environment: %s, \" % _environment\n\t\toutput += \"expiry_time: %s, \" % _expiry_time\n\t\toutput += \"original_transaction_id: %s, \" % _original_transaction_id\n\t\toutput += \"product_id: %s, \" % _product_id\n\t\toutput += \"provider_notification: %s, \" % _provider_notification\n\t\toutput += \"provider_response: %s, \" % _provider_response\n\t\toutput += \"purchase_time: %s, \" % _purchase_time\n\t\toutput += \"refund_time: %s, \" % _refund_time\n\t\toutput += \"store: %s, \" % _store\n\t\toutput += \"update_time: %s, \" % _update_time\n\t\toutput += \"user_id: %s, \" % _user_id\n\t\treturn output\n\n# The object to store.\nclass ApiWriteStorageObject extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"collection\": {\"name\": \"_collection\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"key\": {\"name\": \"_key\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"permission_read\": {\"name\": \"_permission_read\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"permission_write\": {\"name\": \"_permission_write\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"version\": {\"name\": \"_version\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The collection to store the object.\n\tvar _collection\n\tvar collection : String:\n\t\tget:\n\t\t\treturn \"\" if not _collection is String else String(_collection)\n\n\t# The key for the object within the collection.\n\tvar _key\n\tvar key : String:\n\t\tget:\n\t\t\treturn \"\" if not _key is String else String(_key)\n\n\t# The read access permissions for the object.\n\tvar _permission_read\n\tvar permission_read : int:\n\t\tget:\n\t\t\treturn 0 if not _permission_read is int else int(_permission_read)\n\n\t# The write access permissions for the object.\n\tvar _permission_write\n\tvar permission_write : int:\n\t\tget:\n\t\t\treturn 0 if not _permission_write is int else int(_permission_write)\n\n\t# The value of the object.\n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\t# The version hash of the object to check. Possible values are: [\"\", \"*\", \"#hash#\"].\n\tvar _version\n\tvar version : String:\n\t\tget:\n\t\t\treturn \"\" if not _version is String else String(_version)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiWriteStorageObject:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiWriteStorageObject\", p_dict), ApiWriteStorageObject) as ApiWriteStorageObject\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"collection: %s, \" % _collection\n\t\toutput += \"key: %s, \" % _key\n\t\toutput += \"permission_read: %s, \" % _permission_read\n\t\toutput += \"permission_write: %s, \" % _permission_write\n\t\toutput += \"value: %s, \" % _value\n\t\toutput += \"version: %s, \" % _version\n\t\treturn output\n\n# Write objects to the storage engine.\nclass ApiWriteStorageObjectsRequest extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"objects\": {\"name\": \"_objects\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ApiWriteStorageObject\"},\n\t}\n\n\t# The objects to store on the server.\n\tvar _objects\n\tvar objects : Array:\n\t\tget:\n\t\t\treturn Array() if not _objects is Array else Array(_objects)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ApiWriteStorageObjectsRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ApiWriteStorageObjectsRequest\", p_dict), ApiWriteStorageObjectsRequest) as ApiWriteStorageObjectsRequest\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"objects: %s, \" % [_objects]\n\t\treturn output\n\n# \nclass ProtobufAny extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"type_url\": {\"name\": \"_type_url\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"value\": {\"name\": \"_value\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# \n\tvar _type_url\n\tvar type_url : String:\n\t\tget:\n\t\t\treturn \"\" if not _type_url is String else String(_type_url)\n\n\t# \n\tvar _value\n\tvar value : String:\n\t\tget:\n\t\t\treturn \"\" if not _value is String else String(_value)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ProtobufAny:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ProtobufAny\", p_dict), ProtobufAny) as ProtobufAny\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"type_url: %s, \" % _type_url\n\t\toutput += \"value: %s, \" % _value\n\t\treturn output\n\n#\nclass RpcStatus extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"code\": {\"name\": \"_code\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"details\": {\"name\": \"_details\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"ProtobufAny\"},\n\t\t\"message\": {\"name\": \"_message\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t#\n\tvar _code\n\tvar code : int:\n\t\tget:\n\t\t\treturn 0 if not _code is int else int(_code)\n\n\t#\n\tvar _details\n\tvar details : Array:\n\t\tget:\n\t\t\treturn Array() if not _details is Array else Array(_details)\n\n\t#\n\tvar _message\n\tvar message : String:\n\t\tget:\n\t\t\treturn \"\" if not _message is String else String(_message)\n\n\tfunc _init(p_exception = null):\n\t\tsuper(p_exception)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> RpcStatus:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"RpcStatus\", p_dict), RpcStatus) as RpcStatus\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string() -> String:\n\t\tif is_exception():\n\t\t\treturn get_exception()._to_string()\n\t\tvar output : String = \"\"\n\t\toutput += \"code: %s, \" % _code\n\t\toutput += \"details: %s, \" % [_details]\n\t\toutput += \"message: %s, \" % _message\n\t\treturn output\n\n# The low level client for the Nakama API.\nclass ApiClient extends RefCounted:\n\n\tvar _base_uri : String\n\n\tvar _http_adapter\n\tvar _namespace : GDScript\n\tvar _server_key : String\n\tvar auto_refresh := true\n\tvar auto_refresh_time := 300\n\n\tvar auto_retry : bool:\n\t\tset(p_value):\n\t\t\t_http_adapter.auto_retry = p_value\n\t\tget:\n\t\t\treturn _http_adapter.auto_retry\n\n\tvar auto_retry_count : int:\n\t\tset(p_value):\n\t\t\t_http_adapter.auto_retry_count = p_value\n\t\tget:\n\t\t\treturn _http_adapter.auto_retry_count\n\n\tvar auto_retry_backoff_base : int:\n\t\tset(p_value):\n\t\t\t_http_adapter.auto_retry_backoff_base = p_value\n\t\tget:\n\t\t\treturn _http_adapter.auto_retry_backoff_base\n\n\tvar last_cancel_token:\n\t\tget:\n\t\t\treturn _http_adapter.get_last_token()\n\n\tfunc _init(p_base_uri : String, p_http_adapter, p_namespace : GDScript, p_server_key : String, p_timeout : int = 10):\n\t\t_base_uri = p_base_uri\n\t\t_http_adapter = p_http_adapter\n\t\t_http_adapter.timeout = p_timeout\n\t\t_namespace = p_namespace\n\t\t_server_key = p_server_key\n\n\tfunc _refresh_session(p_session : NakamaSession):\n\t\tif auto_refresh and p_session.is_valid() and p_session.refresh_token and not p_session.is_refresh_expired() and p_session.would_expire_in(auto_refresh_time):\n\t\t\tvar request = ApiSessionRefreshRequest.new()\n\t\t\trequest._token = p_session.refresh_token\n\t\t\treturn await session_refresh_async(_server_key, \"\", request)\n\t\treturn null\n\n\tfunc cancel_request(p_token):\n\t\tif p_token:\n\t\t\t_http_adapter.cancel_request(p_token)\n\n\t# A healthcheck which load balancers can use to check the service.\n\tfunc healthcheck_async(\n\t\tp_session : NakamaSession\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/healthcheck\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Delete the current user's account.\n\tfunc delete_account_async(\n\t\tp_session : NakamaSession\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Fetch the current user's account.\n\tfunc get_account_async(\n\t\tp_session : NakamaSession\n\t) -> ApiAccount:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiAccount.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiAccount.new(result)\n\t\tvar out : ApiAccount = NakamaSerializer.deserialize(_namespace, \"ApiAccount\", result)\n\t\treturn out\n\n\t# Update fields in the current user's account.\n\tfunc update_account_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiUpdateAccountRequest\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Authenticate a user with an Apple ID against the server.\n\tfunc authenticate_apple_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountApple\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/apple\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with a custom id against the server.\n\tfunc authenticate_custom_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountCustom\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/custom\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with a device id against the server.\n\tfunc authenticate_device_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountDevice\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/device\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with an email+password against the server.\n\tfunc authenticate_email_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountEmail\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/email\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with a Facebook OAuth token against the server.\n\tfunc authenticate_facebook_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountFacebook\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t\t, p_sync = null # : boolean\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/facebook\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tif p_sync != null:\n\t\t\tquery_params += \"sync=%s&\" % str(bool(p_sync)).to_lower()\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with a Facebook Instant Game token against the server.\n\tfunc authenticate_facebook_instant_game_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountFacebookInstantGame\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/facebookinstantgame\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with Apple's GameCenter against the server.\n\tfunc authenticate_game_center_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountGameCenter\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/gamecenter\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with Google against the server.\n\tfunc authenticate_google_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountGoogle\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/google\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Authenticate a user with Steam against the server.\n\tfunc authenticate_steam_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_account : ApiAccountSteam\n\t\t, p_create = null # : boolean\n\t\t, p_username = null # : string\n\t\t, p_sync = null # : boolean\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/authenticate/steam\"\n\t\tvar query_params = \"\"\n\t\tif p_create != null:\n\t\t\tquery_params += \"create=%s&\" % str(bool(p_create)).to_lower()\n\t\tif p_username != null:\n\t\t\tquery_params += \"username=%s&\" % NakamaSerializer.escape_http(p_username)\n\t\tif p_sync != null:\n\t\t\tquery_params += \"sync=%s&\" % str(bool(p_sync)).to_lower()\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Add an Apple ID to the social profiles on the current user's account.\n\tfunc link_apple_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountApple\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/apple\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add a custom ID to the social profiles on the current user's account.\n\tfunc link_custom_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountCustom\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/custom\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add a device ID to the social profiles on the current user's account.\n\tfunc link_device_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountDevice\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/device\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add an email+password to the social profiles on the current user's account.\n\tfunc link_email_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountEmail\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/email\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add Facebook to the social profiles on the current user's account.\n\tfunc link_facebook_async(\n\t\tp_session : NakamaSession\n\t\t, p_account : ApiAccountFacebook\n\t\t, p_sync = null # : boolean\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/facebook\"\n\t\tvar query_params = \"\"\n\t\tif p_sync != null:\n\t\t\tquery_params += \"sync=%s&\" % str(bool(p_sync)).to_lower()\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add Facebook Instant Game to the social profiles on the current user's account.\n\tfunc link_facebook_instant_game_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountFacebookInstantGame\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/facebookinstantgame\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add Apple's GameCenter to the social profiles on the current user's account.\n\tfunc link_game_center_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountGameCenter\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/gamecenter\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add Google to the social profiles on the current user's account.\n\tfunc link_google_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountGoogle\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/google\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add Steam to the social profiles on the current user's account.\n\tfunc link_steam_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiLinkSteamRequest\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/link/steam\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Refresh a user's session using a refresh token retrieved from a previous authentication request.\n\tfunc session_refresh_async(\n\t\tp_basic_auth_username : String\n\t\t, p_basic_auth_password : String\n\t\t, p_body : ApiSessionRefreshRequest\n\t) -> ApiSession:\n\t\tvar urlpath : String = \"/v2/account/session/refresh\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar credentials = Marshalls.utf8_to_base64(p_basic_auth_username + \":\" + p_basic_auth_password)\n\t\tvar header = \"Basic %s\" % credentials\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSession.new(result)\n\t\tvar out : ApiSession = NakamaSerializer.deserialize(_namespace, \"ApiSession\", result)\n\t\treturn out\n\n\t# Remove the Apple ID from the social profiles on the current user's account.\n\tfunc unlink_apple_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountApple\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/apple\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove the custom ID from the social profiles on the current user's account.\n\tfunc unlink_custom_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountCustom\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/custom\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove the device ID from the social profiles on the current user's account.\n\tfunc unlink_device_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountDevice\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/device\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove the email+password from the social profiles on the current user's account.\n\tfunc unlink_email_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountEmail\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/email\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove Facebook from the social profiles on the current user's account.\n\tfunc unlink_facebook_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountFacebook\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/facebook\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove Facebook Instant Game profile from the social profiles on the current user's account.\n\tfunc unlink_facebook_instant_game_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountFacebookInstantGame\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/facebookinstantgame\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove Apple's GameCenter from the social profiles on the current user's account.\n\tfunc unlink_game_center_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountGameCenter\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/gamecenter\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove Google from the social profiles on the current user's account.\n\tfunc unlink_google_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountGoogle\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/google\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Remove Steam from the social profiles on the current user's account.\n\tfunc unlink_steam_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiAccountSteam\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/account/unlink/steam\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List a channel's message history.\n\tfunc list_channel_messages_async(\n\t\tp_session : NakamaSession\n\t\t, p_channel_id : String\n\t\t, p_limit = null # : integer\n\t\t, p_forward = null # : boolean\n\t\t, p_cursor = null # : string\n\t) -> ApiChannelMessageList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiChannelMessageList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/channel/{channelId}\"\n\t\turlpath = urlpath.replace(\"{channelId}\", NakamaSerializer.escape_http(p_channel_id))\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_forward != null:\n\t\t\tquery_params += \"forward=%s&\" % str(bool(p_forward)).to_lower()\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiChannelMessageList.new(result)\n\t\tvar out : ApiChannelMessageList = NakamaSerializer.deserialize(_namespace, \"ApiChannelMessageList\", result)\n\t\treturn out\n\n\t# Submit an event for processing in the server's registered runtime custom events handler.\n\tfunc event_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiEvent\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/event\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Delete one or more users by ID or username.\n\tfunc delete_friends_async(\n\t\tp_session : NakamaSession\n\t\t, p_ids = null # : array\n\t\t, p_usernames = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/friend\"\n\t\tvar query_params = \"\"\n\t\tif p_ids != null:\n\t\t\tfor elem in p_ids:\n\t\t\t\tquery_params += \"ids=%s&\" % elem\n\t\tif p_usernames != null:\n\t\t\tfor elem in p_usernames:\n\t\t\t\tquery_params += \"usernames=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List all friends for the current user.\n\tfunc list_friends_async(\n\t\tp_session : NakamaSession\n\t\t, p_limit = null # : integer\n\t\t, p_state = null # : integer\n\t\t, p_cursor = null # : string\n\t) -> ApiFriendList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiFriendList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/friend\"\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_state != null:\n\t\t\tquery_params += \"state=%d&\" % p_state\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiFriendList.new(result)\n\t\tvar out : ApiFriendList = NakamaSerializer.deserialize(_namespace, \"ApiFriendList\", result)\n\t\treturn out\n\n\t# Add friends by ID or username to a user's account.\n\tfunc add_friends_async(\n\t\tp_session : NakamaSession\n\t\t, p_ids = null # : array\n\t\t, p_usernames = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/friend\"\n\t\tvar query_params = \"\"\n\t\tif p_ids != null:\n\t\t\tfor elem in p_ids:\n\t\t\t\tquery_params += \"ids=%s&\" % elem\n\t\tif p_usernames != null:\n\t\t\tfor elem in p_usernames:\n\t\t\t\tquery_params += \"usernames=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Block one or more users by ID or username.\n\tfunc block_friends_async(\n\t\tp_session : NakamaSession\n\t\t, p_ids = null # : array\n\t\t, p_usernames = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/friend/block\"\n\t\tvar query_params = \"\"\n\t\tif p_ids != null:\n\t\t\tfor elem in p_ids:\n\t\t\t\tquery_params += \"ids=%s&\" % elem\n\t\tif p_usernames != null:\n\t\t\tfor elem in p_usernames:\n\t\t\t\tquery_params += \"usernames=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Import Facebook friends and add them to a user's account.\n\tfunc import_facebook_friends_async(\n\t\tp_session : NakamaSession\n\t\t, p_account : ApiAccountFacebook\n\t\t, p_reset = null # : boolean\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/friend/facebook\"\n\t\tvar query_params = \"\"\n\t\tif p_reset != null:\n\t\t\tquery_params += \"reset=%s&\" % str(bool(p_reset)).to_lower()\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Import Steam friends and add them to a user's account.\n\tfunc import_steam_friends_async(\n\t\tp_session : NakamaSession\n\t\t, p_account : ApiAccountSteam\n\t\t, p_reset = null # : boolean\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/friend/steam\"\n\t\tvar query_params = \"\"\n\t\tif p_reset != null:\n\t\t\tquery_params += \"reset=%s&\" % str(bool(p_reset)).to_lower()\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_account.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List groups based on given filters.\n\tfunc list_groups_async(\n\t\tp_session : NakamaSession\n\t\t, p_name = null # : string\n\t\t, p_cursor = null # : string\n\t\t, p_limit = null # : integer\n\t\t, p_lang_tag = null # : string\n\t\t, p_members = null # : integer\n\t\t, p_open = null # : boolean\n\t) -> ApiGroupList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiGroupList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group\"\n\t\tvar query_params = \"\"\n\t\tif p_name != null:\n\t\t\tquery_params += \"name=%s&\" % NakamaSerializer.escape_http(p_name)\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_lang_tag != null:\n\t\t\tquery_params += \"lang_tag=%s&\" % NakamaSerializer.escape_http(p_lang_tag)\n\t\tif p_members != null:\n\t\t\tquery_params += \"members=%d&\" % p_members\n\t\tif p_open != null:\n\t\t\tquery_params += \"open=%s&\" % str(bool(p_open)).to_lower()\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiGroupList.new(result)\n\t\tvar out : ApiGroupList = NakamaSerializer.deserialize(_namespace, \"ApiGroupList\", result)\n\t\treturn out\n\n\t# Create a new group with the current user as the owner.\n\tfunc create_group_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiCreateGroupRequest\n\t) -> ApiGroup:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiGroup.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiGroup.new(result)\n\t\tvar out : ApiGroup = NakamaSerializer.deserialize(_namespace, \"ApiGroup\", result)\n\t\treturn out\n\n\t# Delete a group by ID.\n\tfunc delete_group_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Update fields in a given group.\n\tfunc update_group_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_body : ApiUpdateGroupRequest\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Add users to a group.\n\tfunc add_group_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_user_ids = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/add\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tif p_user_ids != null:\n\t\t\tfor elem in p_user_ids:\n\t\t\t\tquery_params += \"user_ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Ban a set of users from a group.\n\tfunc ban_group_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_user_ids = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/ban\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tif p_user_ids != null:\n\t\t\tfor elem in p_user_ids:\n\t\t\t\tquery_params += \"user_ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Demote a set of users in a group to the next role down.\n\tfunc demote_group_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_user_ids = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/demote\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tif p_user_ids != null:\n\t\t\tfor elem in p_user_ids:\n\t\t\t\tquery_params += \"user_ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Immediately join an open group, or request to join a closed one.\n\tfunc join_group_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/join\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Kick a set of users from a group.\n\tfunc kick_group_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_user_ids = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/kick\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tif p_user_ids != null:\n\t\t\tfor elem in p_user_ids:\n\t\t\t\tquery_params += \"user_ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Leave a group the user is a member of.\n\tfunc leave_group_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/leave\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Promote a set of users in a group to the next role up.\n\tfunc promote_group_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_user_ids = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/promote\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tif p_user_ids != null:\n\t\t\tfor elem in p_user_ids:\n\t\t\t\tquery_params += \"user_ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List all users that are part of a group.\n\tfunc list_group_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_group_id : String\n\t\t, p_limit = null # : integer\n\t\t, p_state = null # : integer\n\t\t, p_cursor = null # : string\n\t) -> ApiGroupUserList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiGroupUserList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/group/{groupId}/user\"\n\t\turlpath = urlpath.replace(\"{groupId}\", NakamaSerializer.escape_http(p_group_id))\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_state != null:\n\t\t\tquery_params += \"state=%d&\" % p_state\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiGroupUserList.new(result)\n\t\tvar out : ApiGroupUserList = NakamaSerializer.deserialize(_namespace, \"ApiGroupUserList\", result)\n\t\treturn out\n\n\t# Validate Apple IAP Receipt\n\tfunc validate_purchase_apple_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiValidatePurchaseAppleRequest\n\t) -> ApiValidatePurchaseResponse:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiValidatePurchaseResponse.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/purchase/apple\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiValidatePurchaseResponse.new(result)\n\t\tvar out : ApiValidatePurchaseResponse = NakamaSerializer.deserialize(_namespace, \"ApiValidatePurchaseResponse\", result)\n\t\treturn out\n\n\t# Validate Google IAP Receipt\n\tfunc validate_purchase_google_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiValidatePurchaseGoogleRequest\n\t) -> ApiValidatePurchaseResponse:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiValidatePurchaseResponse.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/purchase/google\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiValidatePurchaseResponse.new(result)\n\t\tvar out : ApiValidatePurchaseResponse = NakamaSerializer.deserialize(_namespace, \"ApiValidatePurchaseResponse\", result)\n\t\treturn out\n\n\t# Validate Huawei IAP Receipt\n\tfunc validate_purchase_huawei_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiValidatePurchaseHuaweiRequest\n\t) -> ApiValidatePurchaseResponse:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiValidatePurchaseResponse.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/purchase/huawei\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiValidatePurchaseResponse.new(result)\n\t\tvar out : ApiValidatePurchaseResponse = NakamaSerializer.deserialize(_namespace, \"ApiValidatePurchaseResponse\", result)\n\t\treturn out\n\n\t# List user's subscriptions.\n\tfunc list_subscriptions_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiListSubscriptionsRequest\n\t) -> ApiSubscriptionList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiSubscriptionList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/subscription\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiSubscriptionList.new(result)\n\t\tvar out : ApiSubscriptionList = NakamaSerializer.deserialize(_namespace, \"ApiSubscriptionList\", result)\n\t\treturn out\n\n\t# Validate Apple Subscription Receipt\n\tfunc validate_subscription_apple_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiValidateSubscriptionAppleRequest\n\t) -> ApiValidateSubscriptionResponse:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiValidateSubscriptionResponse.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/subscription/apple\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiValidateSubscriptionResponse.new(result)\n\t\tvar out : ApiValidateSubscriptionResponse = NakamaSerializer.deserialize(_namespace, \"ApiValidateSubscriptionResponse\", result)\n\t\treturn out\n\n\t# Validate Google Subscription Receipt\n\tfunc validate_subscription_google_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiValidateSubscriptionGoogleRequest\n\t) -> ApiValidateSubscriptionResponse:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiValidateSubscriptionResponse.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/subscription/google\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiValidateSubscriptionResponse.new(result)\n\t\tvar out : ApiValidateSubscriptionResponse = NakamaSerializer.deserialize(_namespace, \"ApiValidateSubscriptionResponse\", result)\n\t\treturn out\n\n\t# Get subscription by product id.\n\tfunc get_subscription_async(\n\t\tp_session : NakamaSession\n\t\t, p_product_id : String\n\t) -> ApiValidatedSubscription:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiValidatedSubscription.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/iap/subscription/{productId}\"\n\t\turlpath = urlpath.replace(\"{productId}\", NakamaSerializer.escape_http(p_product_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiValidatedSubscription.new(result)\n\t\tvar out : ApiValidatedSubscription = NakamaSerializer.deserialize(_namespace, \"ApiValidatedSubscription\", result)\n\t\treturn out\n\n\t# Delete a leaderboard record.\n\tfunc delete_leaderboard_record_async(\n\t\tp_session : NakamaSession\n\t\t, p_leaderboard_id : String\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/leaderboard/{leaderboardId}\"\n\t\turlpath = urlpath.replace(\"{leaderboardId}\", NakamaSerializer.escape_http(p_leaderboard_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List leaderboard records.\n\tfunc list_leaderboard_records_async(\n\t\tp_session : NakamaSession\n\t\t, p_leaderboard_id : String\n\t\t, p_owner_ids = null # : array\n\t\t, p_limit = null # : integer\n\t\t, p_cursor = null # : string\n\t\t, p_expiry = null # : string\n\t) -> ApiLeaderboardRecordList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiLeaderboardRecordList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/leaderboard/{leaderboardId}\"\n\t\turlpath = urlpath.replace(\"{leaderboardId}\", NakamaSerializer.escape_http(p_leaderboard_id))\n\t\tvar query_params = \"\"\n\t\tif p_owner_ids != null:\n\t\t\tfor elem in p_owner_ids:\n\t\t\t\tquery_params += \"owner_ids=%s&\" % elem\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tif p_expiry != null:\n\t\t\tquery_params += \"expiry=%s&\" % NakamaSerializer.escape_http(p_expiry)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiLeaderboardRecordList.new(result)\n\t\tvar out : ApiLeaderboardRecordList = NakamaSerializer.deserialize(_namespace, \"ApiLeaderboardRecordList\", result)\n\t\treturn out\n\n\t# Write a record to a leaderboard.\n\tfunc write_leaderboard_record_async(\n\t\tp_session : NakamaSession\n\t\t, p_leaderboard_id : String\n\t\t, p_record : WriteLeaderboardRecordRequestLeaderboardRecordWrite\n\t) -> ApiLeaderboardRecord:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiLeaderboardRecord.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/leaderboard/{leaderboardId}\"\n\t\turlpath = urlpath.replace(\"{leaderboardId}\", NakamaSerializer.escape_http(p_leaderboard_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_record.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiLeaderboardRecord.new(result)\n\t\tvar out : ApiLeaderboardRecord = NakamaSerializer.deserialize(_namespace, \"ApiLeaderboardRecord\", result)\n\t\treturn out\n\n\t# List leaderboard records that belong to a user.\n\tfunc list_leaderboard_records_around_owner_async(\n\t\tp_session : NakamaSession\n\t\t, p_leaderboard_id : String\n\t\t, p_owner_id : String\n\t\t, p_limit = null # : integer\n\t\t, p_expiry = null # : string\n\t\t, p_cursor = null # : string\n\t) -> ApiLeaderboardRecordList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiLeaderboardRecordList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/leaderboard/{leaderboardId}/owner/{ownerId}\"\n\t\turlpath = urlpath.replace(\"{leaderboardId}\", NakamaSerializer.escape_http(p_leaderboard_id))\n\t\turlpath = urlpath.replace(\"{ownerId}\", NakamaSerializer.escape_http(p_owner_id))\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_expiry != null:\n\t\t\tquery_params += \"expiry=%s&\" % NakamaSerializer.escape_http(p_expiry)\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiLeaderboardRecordList.new(result)\n\t\tvar out : ApiLeaderboardRecordList = NakamaSerializer.deserialize(_namespace, \"ApiLeaderboardRecordList\", result)\n\t\treturn out\n\n\t# Fetch list of running matches.\n\tfunc list_matches_async(\n\t\tp_session : NakamaSession\n\t\t, p_limit = null # : integer\n\t\t, p_authoritative = null # : boolean\n\t\t, p_label = null # : string\n\t\t, p_min_size = null # : integer\n\t\t, p_max_size = null # : integer\n\t\t, p_query = null # : string\n\t) -> ApiMatchList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiMatchList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/match\"\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_authoritative != null:\n\t\t\tquery_params += \"authoritative=%s&\" % str(bool(p_authoritative)).to_lower()\n\t\tif p_label != null:\n\t\t\tquery_params += \"label=%s&\" % NakamaSerializer.escape_http(p_label)\n\t\tif p_min_size != null:\n\t\t\tquery_params += \"min_size=%d&\" % p_min_size\n\t\tif p_max_size != null:\n\t\t\tquery_params += \"max_size=%d&\" % p_max_size\n\t\tif p_query != null:\n\t\t\tquery_params += \"query=%s&\" % NakamaSerializer.escape_http(p_query)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiMatchList.new(result)\n\t\tvar out : ApiMatchList = NakamaSerializer.deserialize(_namespace, \"ApiMatchList\", result)\n\t\treturn out\n\n\t# Delete one or more notifications for the current user.\n\tfunc delete_notifications_async(\n\t\tp_session : NakamaSession\n\t\t, p_ids = null # : array\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/notification\"\n\t\tvar query_params = \"\"\n\t\tif p_ids != null:\n\t\t\tfor elem in p_ids:\n\t\t\t\tquery_params += \"ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"DELETE\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Fetch list of notifications.\n\tfunc list_notifications_async(\n\t\tp_session : NakamaSession\n\t\t, p_limit = null # : integer\n\t\t, p_cacheable_cursor = null # : string\n\t) -> ApiNotificationList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiNotificationList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/notification\"\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_cacheable_cursor != null:\n\t\t\tquery_params += \"cacheable_cursor=%s&\" % NakamaSerializer.escape_http(p_cacheable_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiNotificationList.new(result)\n\t\tvar out : ApiNotificationList = NakamaSerializer.deserialize(_namespace, \"ApiNotificationList\", result)\n\t\treturn out\n\n\t# Execute a Lua function on the server.\n\tfunc rpc_func2_async(\n\t\tp_bearer_token : String\n\t\t, p_id : String\n\t\t, p_payload = null # : string\n\t\t, p_http_key = null # : string\n\t) -> ApiRpc:\n\t\tvar urlpath : String = \"/v2/rpc/{id}\"\n\t\turlpath = urlpath.replace(\"{id}\", NakamaSerializer.escape_http(p_id))\n\t\tvar query_params = \"\"\n\t\tif p_payload != null:\n\t\t\tquery_params += \"payload=%s&\" % NakamaSerializer.escape_http(p_payload)\n\t\tif p_http_key != null:\n\t\t\tquery_params += \"http_key=%s&\" % NakamaSerializer.escape_http(p_http_key)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tif (p_bearer_token):\n\t\t\tvar header = \"Bearer %s\" % p_bearer_token\n\t\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiRpc.new(result)\n\t\tvar out : ApiRpc = NakamaSerializer.deserialize(_namespace, \"ApiRpc\", result)\n\t\treturn out\n\n\t# Execute a Lua function on the server.\n\tfunc rpc_func_async(\n\t\tp_bearer_token : String\n\t\t, p_id : String\n\t\t, p_payload : String\n\t\t, p_http_key = null # : string\n\t) -> ApiRpc:\n\t\tvar urlpath : String = \"/v2/rpc/{id}\"\n\t\turlpath = urlpath.replace(\"{id}\", NakamaSerializer.escape_http(p_id))\n\t\tvar query_params = \"\"\n\t\tif p_http_key != null:\n\t\t\tquery_params += \"http_key=%s&\" % NakamaSerializer.escape_http(p_http_key)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tif (p_bearer_token):\n\t\t\tvar header = \"Bearer %s\" % p_bearer_token\n\t\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_payload).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiRpc.new(result)\n\t\tvar out : ApiRpc = NakamaSerializer.deserialize(_namespace, \"ApiRpc\", result)\n\t\treturn out\n\n\t# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.\n\tfunc session_logout_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiSessionLogoutRequest\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/session/logout\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# Get storage objects.\n\tfunc read_storage_objects_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiReadStorageObjectsRequest\n\t) -> ApiStorageObjects:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiStorageObjects.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/storage\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiStorageObjects.new(result)\n\t\tvar out : ApiStorageObjects = NakamaSerializer.deserialize(_namespace, \"ApiStorageObjects\", result)\n\t\treturn out\n\n\t# Write objects into the storage engine.\n\tfunc write_storage_objects_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiWriteStorageObjectsRequest\n\t) -> ApiStorageObjectAcks:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiStorageObjectAcks.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/storage\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiStorageObjectAcks.new(result)\n\t\tvar out : ApiStorageObjectAcks = NakamaSerializer.deserialize(_namespace, \"ApiStorageObjectAcks\", result)\n\t\treturn out\n\n\t# Delete one or more objects by ID or username.\n\tfunc delete_storage_objects_async(\n\t\tp_session : NakamaSession\n\t\t, p_body : ApiDeleteStorageObjectsRequest\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/storage/delete\"\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_body.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List publicly readable storage objects in a given collection.\n\tfunc list_storage_objects_async(\n\t\tp_session : NakamaSession\n\t\t, p_collection : String\n\t\t, p_user_id = null # : string\n\t\t, p_limit = null # : integer\n\t\t, p_cursor = null # : string\n\t) -> ApiStorageObjectList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiStorageObjectList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/storage/{collection}\"\n\t\turlpath = urlpath.replace(\"{collection}\", NakamaSerializer.escape_http(p_collection))\n\t\tvar query_params = \"\"\n\t\tif p_user_id != null:\n\t\t\tquery_params += \"user_id=%s&\" % NakamaSerializer.escape_http(p_user_id)\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiStorageObjectList.new(result)\n\t\tvar out : ApiStorageObjectList = NakamaSerializer.deserialize(_namespace, \"ApiStorageObjectList\", result)\n\t\treturn out\n\n\t# List publicly readable storage objects in a given collection.\n\tfunc list_storage_objects2_async(\n\t\tp_session : NakamaSession\n\t\t, p_collection : String\n\t\t, p_user_id : String\n\t\t, p_limit = null # : integer\n\t\t, p_cursor = null # : string\n\t) -> ApiStorageObjectList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiStorageObjectList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/storage/{collection}/{userId}\"\n\t\turlpath = urlpath.replace(\"{collection}\", NakamaSerializer.escape_http(p_collection))\n\t\turlpath = urlpath.replace(\"{userId}\", NakamaSerializer.escape_http(p_user_id))\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiStorageObjectList.new(result)\n\t\tvar out : ApiStorageObjectList = NakamaSerializer.deserialize(_namespace, \"ApiStorageObjectList\", result)\n\t\treturn out\n\n\t# List current or upcoming tournaments.\n\tfunc list_tournaments_async(\n\t\tp_session : NakamaSession\n\t\t, p_category_start = null # : integer\n\t\t, p_category_end = null # : integer\n\t\t, p_start_time = null # : integer\n\t\t, p_end_time = null # : integer\n\t\t, p_limit = null # : integer\n\t\t, p_cursor = null # : string\n\t) -> ApiTournamentList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiTournamentList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/tournament\"\n\t\tvar query_params = \"\"\n\t\tif p_category_start != null:\n\t\t\tquery_params += \"category_start=%d&\" % p_category_start\n\t\tif p_category_end != null:\n\t\t\tquery_params += \"category_end=%d&\" % p_category_end\n\t\tif p_start_time != null:\n\t\t\tquery_params += \"start_time=%d&\" % p_start_time\n\t\tif p_end_time != null:\n\t\t\tquery_params += \"end_time=%d&\" % p_end_time\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiTournamentList.new(result)\n\t\tvar out : ApiTournamentList = NakamaSerializer.deserialize(_namespace, \"ApiTournamentList\", result)\n\t\treturn out\n\n\t# List tournament records.\n\tfunc list_tournament_records_async(\n\t\tp_session : NakamaSession\n\t\t, p_tournament_id : String\n\t\t, p_owner_ids = null # : array\n\t\t, p_limit = null # : integer\n\t\t, p_cursor = null # : string\n\t\t, p_expiry = null # : string\n\t) -> ApiTournamentRecordList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiTournamentRecordList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/tournament/{tournamentId}\"\n\t\turlpath = urlpath.replace(\"{tournamentId}\", NakamaSerializer.escape_http(p_tournament_id))\n\t\tvar query_params = \"\"\n\t\tif p_owner_ids != null:\n\t\t\tfor elem in p_owner_ids:\n\t\t\t\tquery_params += \"owner_ids=%s&\" % elem\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tif p_expiry != null:\n\t\t\tquery_params += \"expiry=%s&\" % NakamaSerializer.escape_http(p_expiry)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiTournamentRecordList.new(result)\n\t\tvar out : ApiTournamentRecordList = NakamaSerializer.deserialize(_namespace, \"ApiTournamentRecordList\", result)\n\t\treturn out\n\n\t# Write a record to a tournament.\n\tfunc write_tournament_record2_async(\n\t\tp_session : NakamaSession\n\t\t, p_tournament_id : String\n\t\t, p_record : WriteTournamentRecordRequestTournamentRecordWrite\n\t) -> ApiLeaderboardRecord:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiLeaderboardRecord.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/tournament/{tournamentId}\"\n\t\turlpath = urlpath.replace(\"{tournamentId}\", NakamaSerializer.escape_http(p_tournament_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_record.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiLeaderboardRecord.new(result)\n\t\tvar out : ApiLeaderboardRecord = NakamaSerializer.deserialize(_namespace, \"ApiLeaderboardRecord\", result)\n\t\treturn out\n\n\t# Write a record to a tournament.\n\tfunc write_tournament_record_async(\n\t\tp_session : NakamaSession\n\t\t, p_tournament_id : String\n\t\t, p_record : WriteTournamentRecordRequestTournamentRecordWrite\n\t) -> ApiLeaderboardRecord:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiLeaderboardRecord.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/tournament/{tournamentId}\"\n\t\turlpath = urlpath.replace(\"{tournamentId}\", NakamaSerializer.escape_http(p_tournament_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"PUT\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\t\tcontent = JSON.stringify(p_record.serialize()).to_utf8_buffer()\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiLeaderboardRecord.new(result)\n\t\tvar out : ApiLeaderboardRecord = NakamaSerializer.deserialize(_namespace, \"ApiLeaderboardRecord\", result)\n\t\treturn out\n\n\t# Attempt to join an open and running tournament.\n\tfunc join_tournament_async(\n\t\tp_session : NakamaSession\n\t\t, p_tournament_id : String\n\t) -> NakamaAsyncResult:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn NakamaAsyncResult.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/tournament/{tournamentId}/join\"\n\t\turlpath = urlpath.replace(\"{tournamentId}\", NakamaSerializer.escape_http(p_tournament_id))\n\t\tvar query_params = \"\"\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"POST\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn NakamaAsyncResult.new(result)\n\t\treturn NakamaAsyncResult.new()\n\n\t# List tournament records for a given owner.\n\tfunc list_tournament_records_around_owner_async(\n\t\tp_session : NakamaSession\n\t\t, p_tournament_id : String\n\t\t, p_owner_id : String\n\t\t, p_limit = null # : integer\n\t\t, p_expiry = null # : string\n\t\t, p_cursor = null # : string\n\t) -> ApiTournamentRecordList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiTournamentRecordList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/tournament/{tournamentId}/owner/{ownerId}\"\n\t\turlpath = urlpath.replace(\"{tournamentId}\", NakamaSerializer.escape_http(p_tournament_id))\n\t\turlpath = urlpath.replace(\"{ownerId}\", NakamaSerializer.escape_http(p_owner_id))\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_expiry != null:\n\t\t\tquery_params += \"expiry=%s&\" % NakamaSerializer.escape_http(p_expiry)\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiTournamentRecordList.new(result)\n\t\tvar out : ApiTournamentRecordList = NakamaSerializer.deserialize(_namespace, \"ApiTournamentRecordList\", result)\n\t\treturn out\n\n\t# Fetch zero or more users by ID and/or username.\n\tfunc get_users_async(\n\t\tp_session : NakamaSession\n\t\t, p_ids = null # : array\n\t\t, p_usernames = null # : array\n\t\t, p_facebook_ids = null # : array\n\t) -> ApiUsers:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiUsers.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/user\"\n\t\tvar query_params = \"\"\n\t\tif p_ids != null:\n\t\t\tfor elem in p_ids:\n\t\t\t\tquery_params += \"ids=%s&\" % elem\n\t\tif p_usernames != null:\n\t\t\tfor elem in p_usernames:\n\t\t\t\tquery_params += \"usernames=%s&\" % elem\n\t\tif p_facebook_ids != null:\n\t\t\tfor elem in p_facebook_ids:\n\t\t\t\tquery_params += \"facebook_ids=%s&\" % elem\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiUsers.new(result)\n\t\tvar out : ApiUsers = NakamaSerializer.deserialize(_namespace, \"ApiUsers\", result)\n\t\treturn out\n\n\t# List groups the current user belongs to.\n\tfunc list_user_groups_async(\n\t\tp_session : NakamaSession\n\t\t, p_user_id : String\n\t\t, p_limit = null # : integer\n\t\t, p_state = null # : integer\n\t\t, p_cursor = null # : string\n\t) -> ApiUserGroupList:\n\t\tvar try_refresh = await _refresh_session(p_session)\n\t\tif try_refresh != null:\n\t\t\tif try_refresh.is_exception():\n\t\t\t\treturn ApiUserGroupList.new(try_refresh.get_exception())\n\t\t\tawait p_session.refresh(try_refresh)\n\t\tvar urlpath : String = \"/v2/user/{userId}/group\"\n\t\turlpath = urlpath.replace(\"{userId}\", NakamaSerializer.escape_http(p_user_id))\n\t\tvar query_params = \"\"\n\t\tif p_limit != null:\n\t\t\tquery_params += \"limit=%d&\" % p_limit\n\t\tif p_state != null:\n\t\t\tquery_params += \"state=%d&\" % p_state\n\t\tif p_cursor != null:\n\t\t\tquery_params += \"cursor=%s&\" % NakamaSerializer.escape_http(p_cursor)\n\t\tvar uri = \"%s%s%s\" % [_base_uri, urlpath, \"?\" + query_params if query_params else \"\"]\n\t\tvar method = \"GET\"\n\t\tvar headers = {}\n\t\tvar header = \"Bearer %s\" % p_session.token\n\t\theaders[\"Authorization\"] = header\n\n\t\tvar content : PackedByteArray\n\n\t\tvar result = await _http_adapter.send_async(method, uri, headers, content)\n\t\tif result is NakamaException:\n\t\t\treturn ApiUserGroupList.new(result)\n\t\tvar out : ApiUserGroupList = NakamaSerializer.deserialize(_namespace, \"ApiUserGroupList\", result)\n\t\treturn out\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/api/NakamaRTAPI.gd",
    "content": "extends NakamaAsyncResult\n\nclass_name NakamaRTAPI\n\n# A chat channel on the server.\nclass Channel extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"id\": {\"name\": \"id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presences\": {\"name\": \"presences\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t\t\"self\": {\"name\": \"self_presence\", \"type\": \"UserPresence\", \"required\": true},\n\t\t\"room_name\": {\"name\": \"room_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"group_id\": {\"name\": \"group_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_one\": {\"name\": \"user_id_one\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_two\": {\"name\": \"user_id_two\", \"type\": TYPE_STRING, \"required\": false}\n\t}\n\n\t# The server-assigned channel ID.\n\tvar id : String\n\n\t# The presences visible on the chat channel.\n\tvar presences : Array # of objects NakamaUserPresence\n\n\t# The presence of the current user. i.e. Your self.\n\tvar self_presence : NakamaRTAPI.UserPresence\n\n\t# The name of the chat room, or an empty string if this message was not sent through a chat room.\n\tvar room_name : String\n\n\t# The ID of the group, or an empty string if this message was not sent through a group channel.\n\tvar group_id : String\n\n\t# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.\n\tvar user_id_one : String\n\n\t# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.\n\tvar user_id_two : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"Channel<id=%s, presences=%s, self=%s, room_name=%s, group_id=%s, user_id_one=%s, user_id_two=%s>\" % [\n\t\t\tid, presences, self_presence, room_name, group_id, user_id_one, user_id_two\n\t\t]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> Channel:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"Channel\", p_dict), Channel) as Channel\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"channel\"\n\n\nclass ChannelMessageAck extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"channel_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"code\": {\"name\": \"code\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"create_time\": {\"name\": \"create_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"message_id\": {\"name\": \"message_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"persistent\": {\"name\": \"persistent\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"update_time\": {\"name\": \"update_time\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"username\": {\"name\": \"username\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"room_name\": {\"name\": \"room_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"group_id\": {\"name\": \"group_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_one\": {\"name\": \"user_id_one\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_two\": {\"name\": \"user_id_two\", \"type\": TYPE_STRING, \"required\": false}\n\t}\n\n\t# The server-assigned channel ID.\n\tvar channel_id : String\n\n\t# A user-defined code for the chat message.\n\tvar code : int\n\n\t# The UNIX time when the message was created.\n\tvar create_time : String\n\n\t# A unique ID for the chat message.\n\tvar message_id : String\n\n\t# True if the chat message has been stored in history.\n\tvar persistent : bool\n\n\t# The UNIX time when the message was updated.\n\tvar update_time : String\n\n\t# The username of the sender of the message.\n\tvar username : String\n\n\t# The name of the chat room, or an empty string if this message was not sent through a chat room.\n\tvar room_name : String\n\n\t# The ID of the group, or an empty string if this message was not sent through a group channel.\n\tvar group_id : String\n\n\t# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.\n\tvar user_id_one : String\n\n\t# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.\n\tvar user_id_two : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"ChannelMessageAck<channel_id=%s, code=%d, create_time=%s, message_id=%s, persistent=%s, update_time=%s, username=%s room_name=%s, group_id=%s, user_id_one=%s, user_id_two=%s>\" % [\n\t\t\tchannel_id, code, create_time, message_id, persistent, update_time, username, room_name, group_id, user_id_one, user_id_two\n\t\t]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ChannelMessageAck:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ChannelMessageAck\", p_dict), ChannelMessageAck) as ChannelMessageAck\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"channel_message_ack\"\n\n\n# A batch of join and leave presences on a chat channel.\nclass ChannelPresenceEvent extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"channel_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"joins\": {\"name\": \"joins\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t\t\"leaves\": {\"name\": \"leaves\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t\t\"room_name\": {\"name\": \"room_name\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"group_id\": {\"name\": \"group_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_one\": {\"name\": \"user_id_one\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id_two\": {\"name\": \"user_id_two\", \"type\": TYPE_STRING, \"required\": false}\n\t}\n\n\t# The unique identifier of the chat channel.\n\tvar channel_id : String\n\n\t# Presences of the users who joined the channel.\n\tvar joins : Array # UserPresence\n\n\t# Presences of users who left the channel.\n\tvar leaves : Array # UserPresence\n\n\t# The name of the chat room, or an empty string if this message was not sent through a chat room.\n\tvar room_name : String\n\n\t# The ID of the group, or an empty string if this message was not sent through a group channel.\n\tvar group_id : String\n\n\t# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.\n\tvar user_id_one : String\n\n\t# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.\n\tvar user_id_two : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"ChannelPresenceEvent<channel_id=%s, joins=%s, leaves=%s, room_name=%s, group_id=%s, user_id_one=%s, user_id_two=%s>\" % [\n\t\t\tchannel_id, joins, leaves, room_name, group_id, user_id_one, user_id_two\n\t\t]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> ChannelPresenceEvent:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"ChannelPresenceEvent\", p_dict), ChannelPresenceEvent) as ChannelPresenceEvent\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"channel_presence_event\"\n\n\n# Describes an error which occurred on the server.\nclass Error extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"code\": {\"name\": \"code\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"message\": {\"name\": \"message\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"context\": {\"name\": \"context\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# The selection of possible error codes.\n\tenum Code {\n\t\t# An unexpected result from the server.\n\t\tRUNTIME_EXCEPTION = 0,\n\t\t# The server received a message which is not recognised.\n\t\tUNRECOGNIZED_PAYLOAD = 1,\n\t\t# A message was expected but contains no content.\n\t\tMISSING_PAYLOAD = 2,\n\t\t# Fields in the message have an invalid format.\n\t\tBAD_INPUT = 3,\n\t\t# The match id was not found.\n\t\tMATCH_NOT_FOUND = 4,\n\t\t# The match join was rejected.\n\t\tMATCH_JOIN_REJECTED = 5,\n\t\t# The runtime function does not exist on the server.\n\t\tRUNTIME_FUNCTION_NOT_FOUND = 6,\n\t\t#The runtime function executed with an error.\n\t\tRUNTIME_FUNCTION_EXCEPTION = 7,\n\t}\n\n\t# The error code which should be one of \"Error.Code\" enums.\n\tvar code : int\n\n\t# A message in English to help developers debug the response.\n\tvar message : String\n\n\t# Additional error details which may be different for each response.\n\tvar context : Dictionary\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"Error<code=%s, messages=%s, context=%s>\" % [code, message, context]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> Error:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"Error\", p_dict), Error) as Error\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"error\"\n\n\n# A multiplayer match.\nclass Match extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"authoritative\": {\"name\": \"authoritative\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"label\": {\"name\": \"label\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"presences\": {\"name\": \"presences\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t\t\"size\": {\"name\": \"size\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"self\": {\"name\": \"self_user\", \"type\": \"UserPresence\", \"required\": true}\n\t}\n\n\t# If this match has an authoritative handler on the server.\n\tvar authoritative : bool\n\n\t# The unique match identifier.\n\tvar match_id : String\n\n\t# A label for the match which can be filtered on.\n\tvar label : String\n\n\t# The presences already in the match.\n\tvar presences : Array # UserPresence\n\n\t# The number of users currently in the match.\n\tvar size : int\n\n\t# The current user in this match. i.e. Yourself.\n\tvar self_user : UserPresence\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary):\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"Match\", p_dict), Match) as Match\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"Match<authoritative=%s, match_id=%s, label=%s, presences=%s, size=%d, self=%s>\" % [authoritative, match_id, label, presences, size, self_user]\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"match\"\n\n\n# Some game state update in a match.\nclass MatchData extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": false},\n\t\t\"op_code\": {\"name\": \"op_code\", \"type\": TYPE_INT, \"required\": false},\n\t\t\"data\": {\"name\": \"data\", \"type\": TYPE_STRING, \"required\": false}\n\t}\n\n\t# The unique match identifier.\n\tvar match_id : String\n\n\t# The operation code for the state change.\n\t# This value can be used to mark the type of the contents of the state.\n\tvar op_code : int = 0\n\n\t# The user that sent this game state update.\n\tvar presence : UserPresence\n\n\t# The raw base64-encoded contents of the state change.\n\tvar base64_data : String\n\n\t# The contents of the state change decoded as a UTF-8 string.\n\tvar _data\n\tvar data : String:\n\t\tget:\n\t\t\tif _data == null and base64_data != '':\n\t\t\t\t_data = Marshalls.base64_to_utf8(base64_data)\n\t\t\treturn _data if _data != null else ''\n\t\tset(v):\n\t\t\t_data = v\n\n\t# The contents of the state change decoded as binary data.\n\tvar _binary_data\n\tvar binary_data : PackedByteArray:\n\t\tget:\n\t\t\tif _binary_data == null and base64_data != '':\n\t\t\t\t_binary_data = Marshalls.base64_to_raw(base64_data)\n\t\t\treturn _binary_data\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"MatchData<match_id=%s, op_code=%s, presence=%s, data=%s>\" % [match_id, op_code, presence, data]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> MatchData:\n\t\tvar out = _safe_ret(NakamaSerializer.deserialize(p_ns, \"MatchData\", p_dict), MatchData) as MatchData\n\t\t# Store the base64 data, ready to be decoded when the developer requests it.\n\t\tif out._data != null:\n\t\t\tout.base64_data = out._data\n\t\t\tout._data = null\n\t\treturn out\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"match_data\"\n\n\n# A batch of join and leave presences for a match.\nclass MatchPresenceEvent extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"joins\": {\"name\": \"joins\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t\t\"leaves\": {\"name\": \"leaves\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t}\n\n\t# Presences of users who joined the match.\n\tvar joins : Array\n\n\t# Presences of users who left the match.\n\tvar leaves : Array\n\n\t# The unique match identifier.\n\tvar match_id : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"MatchPresenceEvent<match_id=%s, joins=%s, leaves=%s>\" % [match_id, joins, leaves]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> MatchPresenceEvent:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"MatchPresenceEvent\", p_dict), MatchPresenceEvent) as MatchPresenceEvent\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"match_presence_event\"\n\n\n# The result of a successful matchmaker operation sent to the server.\nclass MatchmakerMatched extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"ticket\": {\"name\": \"ticket\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"token\": {\"name\": \"token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"users\": {\"name\": \"users\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"MatchmakerUser\"},\n\t\t\"self\": {\"name\": \"self_user\", \"type\": \"MatchmakerUser\", \"required\": true}\n\t}\n\n\t# The id used to join the match.\n\t# A match ID used to join the match.\n\tvar match_id : String\n\n\t# The ticket sent by the server when the user requested to matchmake for other players.\n\tvar ticket : String\n\n\t# The token used to join a match.\n\tvar token : String\n\n\t# The other users matched with this user and the parameters they sent.\n\tvar users : Array # MatchmakerUser\n\n\t# The current user who matched with opponents.\n\tvar self_user : MatchmakerUser\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"<MatchmakerMatched match_id=%s, ticket=%s, token=%s, users=%s, self=%s>\" % [\n\t\t\tmatch_id, ticket, token, users, self_user\n\t\t]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> MatchmakerMatched:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"MatchmakerMatched\", p_dict), MatchmakerMatched) as MatchmakerMatched\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"matchmaker_matched\"\n\n\n# The matchmaker ticket received from the server.\nclass MatchmakerTicket extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"ticket\": {\"name\": \"ticket\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\n\t# The ticket generated by the matchmaker.\n\tvar ticket : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> MatchmakerTicket:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"MatchmakerTicket\", p_dict), MatchmakerTicket) as MatchmakerTicket\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"<MatchmakerTicket ticket=%s>\" % ticket\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"matchmaker_ticket\"\n\n\n# The user with the parameters they sent to the server when asking for opponents.\nclass MatchmakerUser extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": true},\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"string_properties\": {\"name\": \"string_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"numeric_properties\": {\"name\": \"numeric_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_FLOAT},\n\t}\n\n\t# The presence of the user.\n\tvar presence : UserPresence\n\n\t# Party identifier, if this user was matched as a party member.\n\tvar party_id : String\n\n\t# The numeric properties which this user asked to matchmake with.\n\tvar numeric_properties : Dictionary\n\n\t# The string properties which this user asked to matchmake with.\n\tvar string_properties : Dictionary\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"<MatchmakerUser presence=%s, numeric_properties=%s, string_properties=%s>\" % [\n\t\t\tpresence, numeric_properties, string_properties]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> MatchmakerUser:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"MatchmakerUser\", p_dict), MatchmakerUser) as MatchmakerUser\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"matchmaker_user\"\n\n\n# Receive status updates for users.\nclass Status extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"presences\": {\"name\": \"presences\", \"type\": TYPE_ARRAY, \"required\": true, \"content\": \"UserPresence\"},\n\t}\n\n\t# The status events for the users followed.\n\tvar presences := Array()\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> Status:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"Status\", p_dict), Status) as Status\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"<Status presences=%s>\" % [presences]\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"status\"\n\n\n# A status update event about other users who've come online or gone offline.\nclass StatusPresenceEvent extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"joins\": {\"name\": \"joins\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t\t\"leaves\": {\"name\": \"leaves\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t}\n\n\t# Presences of users who joined the server.\n\t# This join information is in response to a subscription made to be notified when a user comes online.\n\tvar joins : Array\n\n\t# Presences of users who left the server.\n\t# This leave information is in response to a subscription made to be notified when a user goes offline.\n\tvar leaves : Array\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"StatusPresenceEvent<joins=%s, leaves=%s>\" % [joins, leaves]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> StatusPresenceEvent:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"StatusPresenceEvent\", p_dict), StatusPresenceEvent) as StatusPresenceEvent\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"status_presence_event\"\n\n\n# A realtime socket stream on the server.\nclass Stream extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"mode\": {\"name\": \"mode\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"subject\": {\"name\": \"subject\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"subcontext\": {\"name\": \"subcontext\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"label\": {\"name\": \"label\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\t# The mode of the stream.\n\tvar mode : int\n\n\t# The subject of the stream. This is usually a user id.\n\tvar subject : String\n\n\t# The descriptor of the stream. Used with direct chat messages and contains a second user id.\n\tvar subcontext : String\n\n\t# Identifies streams which have a context across users like a chat channel room.\n\tvar label : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"Stream<mode=%s, subject=%s, subcontext=%s, label=%s>\" % [mode, subject, subcontext, label]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> Stream:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"Stream\", p_dict), Stream) as Stream\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"stream\"\n\n\n# A batch of joins and leaves on the low level stream.\n# Streams are built on to provide abstractions for matches, chat channels, etc. In most cases you'll never need to\n# interact with the low level stream itself.\nclass StreamPresenceEvent extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"stream\": {\"name\": \"stream\", \"type\": \"Stream\", \"required\": true},\n\t\t\"joins\": {\"name\": \"joins\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t\t\"leaves\": {\"name\": \"leaves\", \"type\": TYPE_ARRAY, \"required\": false, \"content\" : \"UserPresence\"},\n\t}\n\n\t# Presences of users who left the stream.\n\tvar joins : Array\n\n\t# Presences of users who joined the stream.\n\tvar leaves : Array\n\n\t# The identifier for the stream.\n\tvar stream : Stream = null\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"StreamPresenceEvent<stream=%s, joins=%s, leaves=%s>\" % [stream, joins, leaves]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> StreamPresenceEvent:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"StreamPresenceEvent\", p_dict), StreamPresenceEvent) as StreamPresenceEvent\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"stream_presence_event\"\n\n\n# A state change received from a stream.\nclass StreamData extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"stream\": {\"name\": \"stream\", \"type\": \"Stream\", \"required\": true},\n\t\t\"sender\": {\"name\": \"sender\", \"type\": \"UserPresence\", \"required\": false},\n\t\t\"data\": {\"name\": \"state\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"reliable\": {\"name\": \"reliable\", \"type\": TYPE_BOOL, \"required\": false},\n\t}\n\n\t# The user who sent the state change. May be `null`.\n\tvar sender : UserPresence = null\n\n\t# The contents of the state change.\n\tvar state : String\n\n\t# The identifier for the stream.\n\tvar stream : Stream\n\n\t# True if this data was delivered reliably, false otherwise.\n\tvar reliable : bool\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"StreamData<sender=%s, state=%s, stream=%s>\" % [sender, state, stream]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> StreamData:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"StreamData\", p_dict), StreamData) as StreamData\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"stream_data\"\n\n\n# An object which represents a connected user in the server.\n# The server allows the same user to be connected with multiple sessions. To uniquely identify them a tuple of\n# `{ node_id, user_id, session_id }` is used which is exposed as this object.\nclass UserPresence extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"persistence\": {\"name\": \"persistence\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"session_id\": {\"name\": \"session_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"status\": {\"name\": \"status\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"username\": {\"name\": \"username\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"user_id\": {\"name\": \"user_id\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\n\t# If this presence generates stored events like persistent chat messages or notifications.\n\tvar persistence : bool\n\n\t# The session id of the user.\n\tvar session_id : String\n\n\t# The status of the user with the presence on the server.\n\tvar status : String\n\n\t# The username for the user.\n\tvar username : String\n\n\t# The id of the user.\n\tvar user_id : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"UserPresence<persistence=%s, session_id=%s, status=%s, username=%s, user_id=%s>\" % [\n\t\t\tpersistence, session_id, status, username, user_id]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> UserPresence:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"UserPresence\", p_dict), UserPresence) as UserPresence\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"user_presence\"\n\n\nclass Party extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"open\": {\"name\": \"open\", \"type\": TYPE_BOOL, \"required\": false},\n\t\t\"max_size\": {\"name\": \"max_size\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"self\": {\"name\": \"self_presence\", \"type\": \"UserPresence\", \"required\": true},\n\t\t\"leader\": {\"name\": \"leader\", \"type\": \"UserPresence\", \"required\": true},\n\t\t\"presences\": {\"name\": \"presences\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t}\n\n\t# Unique party identifier.\n\tvar party_id : String\n\n\t# Open flag.\n\tvar open : bool = false\n\n\t# Maximum number of party members.\n\tvar max_size : int\n\n\t# The presence of the current user. i.e. Your self.\n\tvar self_presence : NakamaRTAPI.UserPresence\n\n\t# Leader.\n\tvar leader : NakamaRTAPI.UserPresence\n\n\t# All current party members.\n\tvar presences : Array # of objects NakamaUserPresence\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"Party<party_id=%s, open=%s, max_size=%d, self=%s, leader=%s, presences=%s>\" % [\n\t\t\tparty_id, open, max_size, self_presence, leader, presences]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> Party:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"Party\", p_dict), Party) as Party\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party\"\n\n\n# Presence update for a particular party.\nclass PartyPresenceEvent extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"joins\": {\"name\": \"joins\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t\t\"leaves\": {\"name\": \"leaves\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t}\n\t# The party ID.\n\tvar party_id : String\n\t# User presences that have just joined the party.\n\tvar joins : Array\n\t# User presences that have just left the party.\n\tvar leaves : Array\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"PartyPresenceEvent<party_id=%s, joins=%s, leaves=%s>\" % [party_id, joins, leaves]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> PartyPresenceEvent:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"PartyPresenceEvent\", p_dict), PartyPresenceEvent) as PartyPresenceEvent\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party_presence_event\"\n\n\n# Announcement of a new party leader.\nclass PartyLeader extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": true},\n\t}\n\t# Party ID to promote a new leader for.\n\tvar party_id : String\n\t# The presence of an existing party member to promote as the new leader.\n\tvar presence : NakamaRTAPI.UserPresence\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"PartyLeader<party_id=%s, presence=%s>\" % [party_id, presence]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> PartyLeader:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"PartyLeader\", p_dict), PartyLeader) as PartyLeader\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party_leader\"\n\n\n# Incoming notification for one or more new presences attempting to join the party.\nclass PartyJoinRequest extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presences\": {\"name\": \"presences\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t}\n\t# Party ID these presences are attempting to join.\n\tvar party_id : String\n\t# Presences attempting to join.\n\tvar presences : Array\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"PartyJoinRequest<party_id=%s, presences=%s>\" % [party_id, presences]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> PartyJoinRequest:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"PartyJoinRequest\", p_dict), PartyJoinRequest) as PartyJoinRequest\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party_join_request\"\n\n\n# A response from starting a new party matchmaking process.\nclass PartyMatchmakerTicket extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"ticket\": {\"name\": \"ticket\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\t# Party ID.\n\tvar party_id : String\n\t# The ticket that can be used to cancel matchmaking.\n\tvar ticket : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"PartyMatchmakerTicket<party_id=%s, ticket=%s>\" % [party_id, ticket]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> PartyMatchmakerTicket:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"PartyMatchmakerTicket\", p_dict), PartyMatchmakerTicket) as PartyMatchmakerTicket\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party_matchmaker_ticket\"\n\n\n# Incoming party data delivered from the server.\nclass PartyData extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": false},\n\t\t\"op_code\": {\"name\": \"op_code\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"data\": {\"name\": \"data\", \"type\": TYPE_STRING, \"required\": false}\n\t}\n\t# The party ID.\n\tvar party_id : String\n\t# A reference to the user presence that sent this data, if any.\n\tvar presence : NakamaRTAPI.UserPresence\n\t# Op code value.\n\tvar op_code : int\n\n\t# The raw base64-encoded contents of the state change.\n\tvar base64_data : String\n\n\t# The contents of the state change decoded as a UTF-8 string.\n\tvar _data\n\tvar data : String:\n\t\tget:\n\t\t\tif _data == null and base64_data != '':\n\t\t\t\t_data = Marshalls.base64_to_utf8(base64_data)\n\t\t\treturn _data if _data != null else ''\n\t\tset(v):\n\t\t\t_data = v\n\n\t# The contents of the state change decoded as binary data.\n\tvar _binary_data\n\tvar binary_data : PackedByteArray:\n\t\tget:\n\t\t\tif _binary_data == null and base64_data != '':\n\t\t\t\t_binary_data = Marshalls.base64_to_raw(base64_data)\n\t\t\treturn _binary_data\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"PartyData<party_id=%s, presence=%s, op_code=%d, data%s>\" % [party_id, presence, op_code, data]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> PartyData:\n\t\tvar out := _safe_ret(NakamaSerializer.deserialize(p_ns, \"PartyData\", p_dict), PartyData) as PartyData\n\t\t# Store the base64 data, ready to be decoded when the developer requests it.\n\t\tif out._data != null:\n\t\t\tout.base64_data = out._data\n\t\t\tout._data = null\n\t\treturn out\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party_data\"\n\n# End a party, kicking all party members and closing it. (this is both a message and a result)\nclass PartyClose extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\t# Party ID to close.\n\tvar party_id : String\n\n\tfunc _init(p_ex = null):\n\t\tsuper(p_ex)\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_close\"\n\n\tfunc _to_string():\n\t\tif is_exception(): return get_exception()._to_string()\n\t\treturn \"PartyClose<party_id=%s>\" % [party_id]\n\n\tstatic func create(p_ns : GDScript, p_dict : Dictionary) -> PartyClose:\n\t\treturn _safe_ret(NakamaSerializer.deserialize(p_ns, \"PartyClose\", p_dict), PartyClose) as PartyClose\n\n\tstatic func get_result_key() -> String:\n\t\treturn \"party_close\"\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/api/NakamaRTMessage.gd",
    "content": "extends RefCounted\nclass_name NakamaRTMessage\n\n# Send a channel join message to the server.\nclass ChannelJoin:\n\n\tconst _SCHEMA = {\n\t\t\"persistence\": {\"name\": \"persistence\", \"type\": TYPE_BOOL, \"required\": true},\n\t\t\"hidden\": {\"name\": \"hidden\", \"type\": TYPE_BOOL, \"required\": true},\n\t\t\"target\": {\"name\": \"target\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"type\": {\"name\": \"type\", \"type\": TYPE_INT, \"required\": true},\n\t}\n\n\tenum ChannelType {\n\t\t# A chat room which can be created dynamically with a name.\n\t\tRoom = 1,\n\t\t# A private chat between two users.\n\t\tDirectMessage = 2,\n\t\t# A chat within a group on the server.\n\t\tGroup = 3\n\t}\n\n\tvar persistence : bool\n\tvar hidden : bool\n\tvar target : String\n\tvar type : int\n\n\tfunc _init(p_target : String, p_type : int, p_persistence : bool, p_hidden : bool):\n\t\tpersistence = p_persistence\n\t\thidden = p_hidden\n\t\ttarget = p_target\n\t\ttype = p_type if p_type >= ChannelType.Room and p_type <= ChannelType.Group else 0 # Will cause error server side\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"channel_join\"\n\n\tfunc _to_string():\n\t\treturn \"ChannelJoin<persistence=%s, hidden=%s, target=%s, type=%d>\" % [persistence, hidden, target, type]\n\n\n# A leave message for a match on the server.\nclass ChannelLeave extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"channel_id\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\tvar channel_id : String\n\n\tfunc _init(p_channel_id : String):\n\t\tchannel_id = p_channel_id\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"channel_leave\"\n\n\tfunc _to_string():\n\t\treturn \"ChannelLeave<channel_id=%s>\" % [channel_id]\n\n\nclass ChannelMessageRemove extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"channel_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"message_id\": {\"name\": \"message_id\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\n\tvar channel_id : String\n\tvar message_id : String\n\n\tfunc _init(p_channel_id : String, p_message_id):\n\t\tchannel_id = p_channel_id\n\t\tmessage_id = p_message_id\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"channel_message_remove\"\n\n\tfunc _to_string():\n\t\treturn \"ChannelMessageRemove<channel_id=%s, message_id=%s>\" % [channel_id, message_id]\n\n\n# Send a chat message to a channel on the server.\nclass ChannelMessageSend extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"channel_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"content\": {\"name\": \"content\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\n\tvar channel_id : String\n\tvar content : String\n\n\tfunc _init(p_channel_id : String, p_content):\n\t\tchannel_id = p_channel_id\n\t\tcontent = p_content\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"channel_message_send\"\n\n\tfunc _to_string():\n\t\treturn \"ChannelMessageSend<channel_id=%s, content=%s>\" % [channel_id, content]\n\n\nclass ChannelMessageUpdate extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"channel_id\": {\"name\": \"channel_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"message_id\": {\"name\": \"message_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"content\": {\"name\": \"content\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\n\tvar channel_id : String\n\tvar message_id : String\n\tvar content : String\n\n\tfunc _init(p_channel_id : String, p_message_id, p_content : String):\n\t\tchannel_id = p_channel_id\n\t\tmessage_id = p_message_id\n\t\tcontent = p_content\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"channel_message_update\"\n\n\tfunc _to_string():\n\t\treturn \"ChannelMessageUpdate<channel_id=%s, message_id=%s, content=%s>\" % [channel_id, message_id, content]\n\n\n# A create message for a match on the server.\nclass MatchCreate extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"name\": {\"name\": \"name\", \"type\": TYPE_STRING, \"required\": false},\n\t}\n\n\tvar name = null\n\n\tfunc _init(p_name = null):\n\t\tname = p_name if p_name else null\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"match_create\"\n\n\tfunc _to_string():\n\t\treturn \"MatchCreate<name=%s>\" % [name]\n\n\n# A join message for a match on the server.\nclass MatchJoin extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"token\": {\"name\": \"token\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"metadata\": {\"name\": \"metadata\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\t# These two are mutually exclusive and set manually by socket for now, so use null.\n\tvar match_id = null\n\tvar token = null\n\tvar metadata = null\n\n\tfunc _init(p_ex=null):\n\t\tsuper(p_ex)\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"match_join\"\n\n\tfunc _to_string():\n\t\treturn \"MatchJoin<match_id=%s, token=%s, metadata=%s>\" % [match_id, token, metadata]\n\n\n# A leave message for a match on the server.\nclass MatchLeave extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\tvar match_id : String\n\n\tfunc _init(p_match_id : String):\n\t\tmatch_id = p_match_id\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"match_leave\"\n\n\tfunc _to_string():\n\t\treturn \"MatchLeave<match_id=%s>\" % [match_id]\n\n\n# Send new state to a match on the server.\nclass MatchDataSend extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"match_id\": {\"name\": \"match_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"op_code\": {\"name\": \"op_code\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"presences\": {\"name\": \"presences\", \"type\": TYPE_ARRAY, \"required\": false, \"content\": \"UserPresence\"},\n\t\t\"data\": {\"name\": \"data\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\n\tvar match_id : String\n\tvar presences = null\n\tvar op_code : int\n\tvar data : String\n\n\tfunc _init(p_match_id : String, p_op_code : int, p_data : String, p_presences):\n\t\tmatch_id = p_match_id\n\t\tpresences = p_presences\n\t\top_code = p_op_code\n\t\tdata = p_data\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key():\n\t\treturn \"match_data_send\"\n\n\tfunc _to_string():\n\t\treturn \"MatchDataSend<match_id=%s, op_code=%s, presences=%s, data=%s>\" % [match_id, op_code, presences, data]\n\n\n# Add the user to the matchmaker pool with properties.\nclass MatchmakerAdd extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"query\": {\"name\": \"query\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"max_count\": {\"name\": \"max_count\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"min_count\": {\"name\": \"min_count\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"numeric_properties\": {\"name\": \"numeric_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_FLOAT},\n\t\t\"string_properties\": {\"name\": \"string_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"count_multiple\": {\"name\": \"count_multiple\", \"type\": TYPE_INT, \"required\": false},\n\t}\n\n\tvar query : String = \"*\"\n\tvar max_count : int = 8\n\tvar min_count : int = 2\n\tvar string_properties : Dictionary\n\tvar numeric_properties : Dictionary\n\tvar count_multiple\n\n\tfunc _init(p_query : String = \"*\", p_min_count : int = 2, p_max_count : int = 8,\n\t\t\tp_string_props : Dictionary = Dictionary(), p_numeric_props : Dictionary = Dictionary(),\n\t\t\tp_count_multiple : int = 0):\n\t\tquery = p_query\n\t\tmin_count = p_min_count\n\t\tmax_count = p_max_count\n\t\tstring_properties = p_string_props\n\t\tnumeric_properties = p_numeric_props\n\t\tcount_multiple = p_count_multiple if p_count_multiple > 0 else null\n\n\tfunc serialize() -> Dictionary:\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"matchmaker_add\"\n\n\tfunc _to_string():\n\t\treturn \"MatchmakerAdd<query=%s, max_count=%d, min_count=%d, numeric_properties=%s, string_properties=%s, count_multiple=%s>\" % [query, max_count, min_count, numeric_properties, string_properties, count_multiple]\n\n\n# Remove the user from the matchmaker pool by ticket.\nclass MatchmakerRemove extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"ticket\": {\"name\": \"ticket\", \"type\": TYPE_STRING, \"required\": true}\n\t}\n\n\tvar ticket : String\n\n\tfunc _init(p_ticket : String):\n\t\tticket = p_ticket\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"matchmaker_remove\"\n\n\tfunc _to_string():\n\t\treturn \"MatchmakerRemove<ticket=%s>\" % [ticket]\n\n\n# Follow one or more other users for status updates.\nclass StatusFollow extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"user_ids\": {\"name\": \"user_ids\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"usernames\": {\"name\": \"usernames\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\tvar user_ids := PackedStringArray()\n\tvar usernames := PackedStringArray()\n\n\tfunc _init(p_ids : PackedStringArray, p_usernames : PackedStringArray):\n\t\tuser_ids = p_ids\n\t\tusernames = p_usernames\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"status_follow\"\n\n\tfunc _to_string():\n\t\treturn \"StatusFollow<user_ids=%s, usernames=%s>\" % [user_ids, usernames]\n\n\n# Unfollow one or more users on the server.\nclass StatusUnfollow extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"user_ids\": {\"name\": \"user_ids\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t}\n\n\tvar user_ids := PackedStringArray()\n\n\tfunc _init(p_ids : PackedStringArray):\n\t\tuser_ids = p_ids\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"status_unfollow\"\n\n\tfunc _to_string():\n\t\treturn \"StatusUnfollow<user_ids=%s>\" % [user_ids]\n\n\n# Unfollow one or more users on the server.\nclass StatusUpdate extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"status\": {\"name\": \"status\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\n\tvar status : String\n\n\tfunc _init(p_status : String):\n\t\tstatus = p_status\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"status_update\"\n\n\tfunc _to_string():\n\t\treturn \"StatusUpdate<status=%s>\" % [status]\n\n# Create a party.\nclass PartyCreate extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"open\": {\"name\": \"open\", \"type\": TYPE_BOOL, \"required\": true},\n\t\t\"max_size\": {\"name\": \"max_size\", \"type\": TYPE_INT, \"required\": true},\n\t}\n\t# Whether or not the party will require join requests to be approved by the party leader.\n\tvar open : bool\n\t# Maximum number of party members.\n\tvar max_size : int\n\n\tfunc _init(p_open : bool, p_max_size : int):\n\t\topen = p_open\n\t\tmax_size = p_max_size\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_create\"\n\n\tfunc _to_string():\n\t\treturn \"PartyCreate<open=%s, max_size=%d>\" % [open, max_size]\n\n\n# Join a party, or request to join if the party is not open.\nclass PartyJoin extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\t# Party ID to join.\n\tvar party_id : String\n\n\tfunc _init(p_id : String):\n\t\tparty_id = p_id\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_join\"\n\n\tfunc _to_string():\n\t\treturn \"PartyJoin<party_id=%s>\" % [party_id]\n\n\n# Leave a party.\nclass PartyLeave extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\t# Party ID to leave.\n\tvar party_id : String\n\n\tfunc _init(p_id : String):\n\t\tparty_id = p_id\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_leave\"\n\n\tfunc _to_string():\n\t\treturn \"PartyLeave<party_id=%s>\" % [party_id]\n\n\n# Promote a new party leader.\nclass PartyPromote extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": true},\n\t}\n\t# Party ID to promote a new leader for.\n\tvar party_id : String\n\t# The presence of an existing party member to promote as the new leader.\n\tvar presence : NakamaRTAPI.UserPresence\n\n\tfunc _init(p_id : String, p_presence : NakamaRTAPI.UserPresence):\n\t\tparty_id = p_id\n\t\tpresence = p_presence\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_promote\"\n\n\tfunc _to_string():\n\t\treturn \"PartyPromote<party_id=%s, presence=%s>\" % [party_id, presence]\n\n\n# Accept a request to join.\nclass PartyAccept extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": true},\n\t}\n\t# Party ID to accept a join request for.\n\tvar party_id : String\n\t# The presence to accept as a party member.\n\tvar presence : NakamaRTAPI.UserPresence\n\n\tfunc _init(p_id : String, p_presence : NakamaRTAPI.UserPresence):\n\t\tparty_id = p_id\n\t\tpresence = p_presence\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_accept\"\n\n\tfunc _to_string():\n\t\treturn \"PartyAccept<party_id=%s, presence=%s>\" % [party_id, presence]\n\n\n# Kick a party member, or decline a request to join.\nclass PartyRemove extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"presence\": {\"name\": \"presence\", \"type\": \"UserPresence\", \"required\": true},\n\t}\n\t# Party ID to remove/reject from.\n\tvar party_id : String\n\t# The presence to remove or reject.\n\tvar presence : NakamaRTAPI.UserPresence\n\n\tfunc _init(p_id : String, p_presence : NakamaRTAPI.UserPresence):\n\t\tparty_id = p_id\n\t\tpresence = p_presence\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_remove\"\n\n\tfunc _to_string():\n\t\treturn \"PartyRemove<party_id=%s, presence=%s>\" % [party_id, presence]\n\n\n# Request a list of pending join requests for a party.\nclass PartyJoinRequestList extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\t# Party ID to get a list of join requests for.\n\tvar party_id : String\n\n\tfunc _init(p_id : String):\n\t\tparty_id = p_id\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_join_request_list\"\n\n\tfunc _to_string():\n\t\treturn \"PartyJoinRequestList<party_id=%s>\" % [party_id]\n\n\n# Begin matchmaking as a party.\nclass PartyMatchmakerAdd extends NakamaAsyncResult:\n\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"min_count\": {\"name\": \"min_count\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"max_count\": {\"name\": \"max_count\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"query\": {\"name\": \"query\", \"type\": TYPE_STRING, \"required\": false},\n\t\t\"string_properties\": {\"name\": \"string_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_STRING},\n\t\t\"numeric_properties\": {\"name\": \"numeric_properties\", \"type\": TYPE_DICTIONARY, \"required\": false, \"content\": TYPE_FLOAT},\n\t}\n\n\t# Party ID.\n\tvar party_id : String\n\t# Minimum total user count to match together.\n\tvar min_count : int\n\t# Maximum total user count to match together.\n\tvar max_count : int\n\t# Filter query used to identify suitable users.\n\tvar query : String\n\t# String properties.\n\tvar string_properties : Dictionary\n\t# Numeric properties.\n\tvar numeric_properties : Dictionary\n\t# Optional multiple of the count that must be satisfied.\n\tvar count_multiple\n\n\tfunc _init(p_id : String, p_min_count : int, p_max_count : int, p_query : String, p_string_properties = null, p_numeric_properties = null, p_count_multiple = null):\n\t\tparty_id = p_id\n\t\tmin_count = p_min_count\n\t\tmax_count = p_max_count\n\t\tquery = p_query\n\t\tstring_properties = p_string_properties\n\t\tnumeric_properties = p_numeric_properties\n\t\tcount_multiple = p_count_multiple\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_matchmaker_add\"\n\n\tfunc _to_string():\n\t\treturn \"PartyMatchmakerAdd<party_id=%s, min_count=%d, max_count=%d, query=%s, string_properties=%s, numeric_properties=%s, count_multiple=%s>\" % [party_id, min_count, max_count, query, string_properties, numeric_properties, count_multiple]\n\n\n# Cancel a party matchmaking process using a ticket.\nclass PartyMatchmakerRemove extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"ticket\": {\"name\": \"ticket\", \"type\": TYPE_STRING, \"required\": true},\n\t}\n\t# Party ID.\n\tvar party_id : String\n\t# The ticket to cancel.\n\tvar ticket : String\n\n\tfunc _init(p_id : String, p_ticket : String):\n\t\tparty_id = p_id\n\t\tticket = p_ticket\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_matchmaker_remove\"\n\n\tfunc _to_string():\n\t\treturn \"PartyMatchmakerRemove<party_id=%s, ticket=%s>\" % [party_id, ticket]\n\n\n# Send data to a party.\nclass PartyDataSend extends NakamaAsyncResult:\n\tconst _SCHEMA = {\n\t\t\"party_id\": {\"name\": \"party_id\", \"type\": TYPE_STRING, \"required\": true},\n\t\t\"op_code\": {\"name\": \"op_code\", \"type\": TYPE_INT, \"required\": true},\n\t\t\"data\": {\"name\": \"data\", \"type\": TYPE_STRING, \"required\": false}\n\t}\n\t# Party ID to send to.\n\tvar party_id : String\n\t# Op code value.\n\tvar op_code : int\n\t# Data payload, if any.\n\tvar data = null\n\n\tfunc _init(p_id : String, p_op_code : int, p_data = null):\n\t\tparty_id = p_id\n\t\top_code = p_op_code\n\t\tdata = p_data\n\n\tfunc serialize():\n\t\treturn NakamaSerializer.serialize(self)\n\n\tfunc get_msg_key() -> String:\n\t\treturn \"party_data_send\"\n\n\tfunc _to_string():\n\t\treturn \"PartyDataSend<party_id=%s, op_code=%d, data=%s>\" % [party_id, op_code, data]\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/api/NakamaSession.gd",
    "content": "extends NakamaAsyncResult\nclass_name NakamaSession\n\nvar _created : bool = false\nvar created : bool:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _created\n\nvar _token : String = \"\"\nvar token : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _token\n\nvar _create_time : int = 0\nvar create_time : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _create_time\n\nvar _expire_time : int = 0\nvar expire_time : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _expire_time\n\nvar expired : bool:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn is_expired()\n\nvar _vars : Dictionary = {}\nvar vars : Dictionary:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _vars\n\nvar _username : String = \"\"\nvar username : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _username\n\nvar _user_id : String = \"\"\nvar user_id : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _user_id\n\nvar _refresh_token : String = \"\"\nvar refresh_token : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _refresh_token\n\nvar _refresh_expire_time : int = 0\nvar refresh_expire_time : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _refresh_expire_time\n\nvar _valid : bool = false\nvar valid : bool:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _valid\n\nfunc is_expired() -> bool:\n\treturn _expire_time < Time.get_unix_time_from_system()\n\nfunc would_expire_in(p_secs : int) -> bool:\n\treturn _expire_time < Time.get_unix_time_from_system() + p_secs\n\nfunc is_refresh_expired() -> bool:\n\treturn _refresh_expire_time < Time.get_unix_time_from_system()\n\nfunc is_valid():\n\treturn _valid\n\nfunc _init(p_token = null, p_created : bool = false, p_refresh_token = null, p_exception = null):\n\tsuper(p_exception)\n\t\n\tif p_token:\n\t\t_created = p_created\n\t\t_parse_token(p_token)\n\tif p_refresh_token:\n\t\t_parse_refresh_token(p_refresh_token)\n\nfunc refresh(p_session):\n\tif p_session.token:\n\t\t_parse_token(p_session.token)\n\tif p_session.refresh_token:\n\t\t_parse_refresh_token(p_session.refresh_token)\n\nfunc _parse_token(p_token):\n\tvar decoded = _jwt_unpack(p_token)\n\tif decoded.is_empty():\n\t\t_valid = false\n\t\treturn\n\t_valid = true\n\t_token = p_token\n\t_create_time = Time.get_unix_time_from_system()\n\t_expire_time = int(decoded.get(\"exp\", 0))\n\t_username = str(decoded.get(\"usn\", \"\"))\n\t_user_id = str(decoded.get(\"uid\", \"\"))\n\t_vars = {}\n\tif decoded.has(\"vrs\") and typeof(decoded[\"vrs\"]) == TYPE_DICTIONARY:\n\t\tfor k in decoded[\"vrs\"]:\n\t\t\t_vars[k] = decoded[\"vrs\"][k]\n\nfunc _parse_refresh_token(p_refresh_token):\n\tvar decoded = _jwt_unpack(p_refresh_token)\n\tif decoded.is_empty():\n\t\treturn\n\t_refresh_expire_time = int(decoded.get(\"exp\", 0))\n\t_refresh_token = p_refresh_token\n\nfunc _to_string():\n\tif is_exception():\n\t\treturn get_exception()._to_string()\n\treturn \"Session<created=%s, token=%s, create_time=%d, username=%s, user_id=%s, vars=%s, expire_time=%d, refresh_token=%s refresh_expire_time=%d>\" % [\n\t\t_created, _token, _create_time, _username, _user_id, str(_vars), _expire_time, _refresh_token, _refresh_expire_time]\n\nfunc _jwt_unpack(p_token : String) -> Dictionary:\n\t# Hack decode JSON payload from JWT.\n\tif p_token.find(\".\") == -1:\n\t\t_ex = NakamaException.new(\"Missing payload: %s\" % p_token)\n\t\treturn {}\n\tvar payload = p_token.split('.')[1];\n\tvar pad_length = ceil(payload.length() / 4.0) * 4;\n\t# Pad base64\n\tfor i in range(0, pad_length - payload.length()):\n\t\tpayload += \"=\"\n\tpayload = payload.replace(\"-\", \"+\").replace(\"_\", \"/\")\n\tvar unpacked = Marshalls.base64_to_utf8(payload)\n\t\n\tvar json = JSON.new()\n\tvar error = json.parse(unpacked)\n\n\tif error == OK:\n\t\tvar decoded = json.get_data()\n\t\tif typeof(decoded) == TYPE_DICTIONARY:\n\t\t\treturn decoded\n\t_ex = NakamaException.new(\"Unable to unpack token: %s\" % p_token)\n\treturn {}\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/api/NakamaStorageObjectId.gd",
    "content": "extends RefCounted\nclass_name NakamaStorageObjectId\n\n# The collection which stores the object.\nvar collection : String\n\n# The key of the object within the collection.\nvar key : String\n\n# The user owner of the object.\nvar user_id : String\n\n# The version hash of the object.\nvar version : String\n\nfunc _init(p_collection, p_key, p_user_id = \"\", p_version = \"\"):\n\tcollection = p_collection\n\tkey = p_key\n\tuser_id = p_user_id\n\tversion = p_version\n\nfunc as_delete():\n\treturn NakamaAPI.ApiDeleteStorageObjectId.create(NakamaAPI, {\n\t\t\"collection\": collection,\n\t\t\"key\": key,\n\t\t\"version\": version\n\t})\n\nfunc as_read():\n\treturn NakamaAPI.ApiReadStorageObjectId.create(NakamaAPI, {\n\t\t\"collection\": collection,\n\t\t\"key\": key,\n\t\t\"user_id\": user_id\n\t})\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/api/NakamaWriteStorageObject.gd",
    "content": "extends RefCounted\nclass_name NakamaWriteStorageObject\n\nvar collection : String\nvar key : String\nvar permission_read : int = 0\nvar permission_write : int = 0\nvar value : String\nvar version : String\n\nfunc _init(p_collection : String, p_key : String, p_permission_read : int,\n\t\tp_permission_write : int, p_value : String, p_version : String):\n\tcollection = p_collection\n\tkey = p_key\n\tpermission_read = p_permission_read\n\tpermission_write = p_permission_write\n\tvalue = p_value\n\tversion = p_version\n\nfunc as_write():\n\treturn NakamaAPI.ApiWriteStorageObject.create(NakamaAPI, {\n\t\t\"collection\": collection,\n\t\t\"key\": key,\n\t\t\"permission_read\": permission_read,\n\t\t\"permission_write\": permission_write,\n\t\t\"value\": value,\n\t\t\"version\": version\n\t})\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/client/NakamaClient.gd",
    "content": "extends RefCounted\n\n# A client for the API in Nakama server.\nclass_name NakamaClient\n\nconst ChannelType = NakamaRTMessage.ChannelJoin.ChannelType\n\n# The host address of the server. Defaults to \"127.0.0.1\".\nvar _host\nvar host : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _host\n\n# The port number of the server. Defaults to 7350.\nvar _port\nvar port : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _port\n\n# The protocol scheme used to connect with the server. Must be either \"http\" or \"https\".\nvar _scheme\nvar scheme : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _scheme\n\n# The key used to authenticate with the server without a session. Defaults to \"defaultkey\".\nvar _server_key : String = \"defaultkey\"\nvar server_key:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _server_key\n\n# Set the timeout in seconds on requests sent to the server.\nvar timeout : int\n\nvar logger : NakamaLogger = null\n\nvar _api_client : NakamaAPI.ApiClient\n\nvar auto_refresh : bool = true:\n\tset(v):\n\t\tset_auto_refresh(v)\n\tget:\n\t\treturn get_auto_refresh()\n\nvar auto_refresh_seconds : int = true:\n\tset(v):\n\t\tset_auto_refresh_seconds(v)\n\tget:\n\t\treturn get_auto_refresh_seconds()\n\nvar auto_retry : bool = true:\n\tset(v):\n\t\tset_auto_retry(v)\n\tget:\n\t\treturn get_auto_retry()\n\nvar auto_retry_count:\n\tset(v):\n\t\tset_auto_retry_count(v)\n\tget:\n\t\treturn get_auto_retry_count()\n\nvar auto_retry_backoff_base:\n\tset(v):\n\t\tset_auto_retry_backoff_base(v)\n\tget:\n\t\treturn get_auto_retry_backoff_base()\n\nvar last_cancel_token:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn get_last_cancel_token()\n\nfunc get_auto_refresh():\n\treturn _api_client.auto_refresh\n\nfunc set_auto_refresh(p_value):\n\t_api_client.auto_refresh = p_value\n\nfunc get_auto_refresh_seconds():\n\treturn _api_client.auto_refresh_time\n\nfunc set_auto_refresh_seconds(p_value):\n\t_api_client.auto_refresh_time = p_value\n\nfunc get_last_cancel_token():\n\treturn _api_client.last_cancel_token\n\nfunc get_auto_retry():\n\treturn _api_client.auto_retry\n\nfunc set_auto_retry(p_value):\n\t_api_client.auto_retry = p_value\n\nfunc get_auto_retry_count():\n\treturn _api_client.auto_retry_count\n\nfunc set_auto_retry_count(p_value):\n\t_api_client.auto_retry_count = p_value\n\nfunc get_auto_retry_backoff_base():\n\treturn _api_client.auto_retry_backoff_base\n\nfunc set_auto_retry_backoff_base(p_value):\n\t_api_client.auto_retry_backoff_base = p_value\n\nfunc cancel_request(p_token):\n\t_api_client.cancel_request(p_token)\n\nfunc _init(p_adapter : NakamaHTTPAdapter,\n\t\tp_server_key : String,\n\t\tp_scheme : String,\n\t\tp_host : String,\n\t\tp_port : int,\n\t\tp_timeout : int):\n\n\t_server_key = p_server_key\n\t_scheme = p_scheme\n\t_host = p_host\n\t_port = p_port\n\ttimeout = p_timeout\n\tlogger = p_adapter.logger\n\t_api_client = NakamaAPI.ApiClient.new(_scheme + \"://\" + _host + \":\" + str(_port), p_adapter, NakamaAPI, _server_key, p_timeout)\n\n# Restore a session from the auth token.\n# A `null` or empty authentication token will return `null`.\n# @param authToken - The authentication token to restore as a session.\n# Returns a session.\nstatic func restore_session(auth_token : String):\n\treturn NakamaSession.new(auth_token, false)\n\nfunc _to_string():\n\treturn \"Client(Host='%s', Port=%s, Scheme='%s', ServerKey='%s', Timeout=%s)\" % [\n\t\thost, port, scheme, server_key, timeout\n\t]\n\nfunc _parse_auth(p_session) -> NakamaSession:\n\tif p_session.is_exception():\n\t\treturn NakamaSession.new(null, false, null, p_session.get_exception())\n\treturn NakamaSession.new(p_session.token, p_session.created, p_session.refresh_token)\n\n# Add one or more friends by id or username.\n# @param p_session - The session of the user.\n# @param p_ids - The ids of the users to add or invite as friends.\n# @param p_usernames - The usernames of the users to add as friends.\n# Returns a task which represents the asynchronous operation.\nfunc add_friends_async(p_session : NakamaSession, p_ids = null, p_usernames = null) -> NakamaAsyncResult:\n\treturn await _api_client.add_friends_async(p_session, p_ids, p_usernames)\n\n# Add one or more users to the group.\n# @param p_session - The session of the user.\n# @param p_group_id - The id of the group to add users into.\n# @param p_ids - The ids of the users to add or invite to the group.\n# Returns a task which represents the asynchronous operation.\nfunc add_group_users_async(p_session : NakamaSession, p_group_id : String, p_ids : PackedStringArray) -> NakamaAsyncResult:\n\treturn await _api_client.add_group_users_async(p_session, p_group_id, p_ids);\n\n# Authenticate a user with an Apple ID against the server.\n# @param p_username - A username used to create the user.</param>\n# @param p_token - The ID token received from Apple to validate.</param>\n# @param p_vars - Extra information that will be bundled in the session token.</param>\n# Returns a task which resolves to a session object.\nfunc authenticate_apple_async(p_token : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_apple_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountApple.create(NakamaAPI, {\n\t\t\t\"token\": p_token,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username))\n\n# Authenticate a user with a custom id.\n# @param p_id - A custom identifier usually obtained from an external authentication service.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_custom_async(p_id : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_custom_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountCustom.create(NakamaAPI, {\n\t\t\t\"id\": p_id,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username))\n\n# Authenticate a user with a device id.\n# @param p_id - A device identifier usually obtained from a platform API.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_device_async(p_id : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_device_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountDevice.create(NakamaAPI, {\n\t\t\t\"id\": p_id,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username))\n\n# Authenticate a user with an email and password.\n# @param p_email - The email address of the user.\n# @param p_password - The password for the user.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_email_async(p_email : String, p_password : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_email_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountEmail.create(NakamaAPI, {\n\t\t\t\"email\": p_email,\n\t\t\t\"password\": p_password,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username))\n\n# Authenticate a user with a Facebook auth token.\n# @param p_token - An OAuth access token from the Facebook SDK.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_import - If the Facebook friends should be imported.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_facebook_async(p_token : String, p_username = null, p_create : bool = true, p_import : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_facebook_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountFacebook.create(NakamaAPI, {\n\t\t\t\"token\": p_token,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username, p_import))\n\n# Authenticate a user with a Facebook Instant Game token against the server.\n# @param p_signed_player_info - Facebook Instant Game signed info from Facebook SDK.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_import - If the Facebook friends should be imported.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_facebook_instant_game_async(p_signed_player_info : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\t\treturn _parse_auth(await _api_client.authenticate_facebook_instant_game_async(server_key, \"\",\n\t\t\t\tNakamaAPI.ApiAccountFacebookInstantGame.create(NakamaAPI, {\n\t\t\t\t\t\t\"signed_player_info\": p_signed_player_info,\n\t\t\t\t\t\t\"vars\": p_vars\n\t\t\t\t}), p_create, p_username))\n\n# Authenticate a user with Apple Game Center.\n# @param p_bundle_id - The bundle id of the Game Center application.\n# @param p_player_id - The player id of the user in Game Center.\n# @param p_public_key_url - The URL for the public encryption key.\n# @param p_salt - A random `NSString` used to compute the hash and keep it randomized.\n# @param p_signature - The verification signature data generated.\n# @param p_timestamp_seconds - The date and time that the signature was created.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_game_center_async(p_bundle_id : String, p_player_id : String, p_public_key_url : String,\n\t\tp_salt : String, p_signature : String, p_timestamp_seconds : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_game_center_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountGameCenter.create(NakamaAPI, {\n\t\t\t\"bundle_id\": p_bundle_id,\n\t\t\t\"player_id\": p_player_id,\n\t\t\t\"public_key_url\": p_public_key_url,\n\t\t\t\"salt\": p_salt,\n\t\t\t\"signature\": p_signature,\n\t\t\t\"timestamp_seconds\": p_timestamp_seconds,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username))\n\n# Authenticate a user with a Google auth token.\n# @param p_token - An OAuth access token from the Google SDK.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_google_async(p_token : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_google_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountGoogle.create(NakamaAPI, {\n\t\t\t\"token\": p_token,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username))\n\n# Authenticate a user with a Steam auth token.\n# @param p_token - An authentication token from the Steam network.\n# @param p_username - A username used to create the user. May be `null`.\n# @param p_create - If the user should be created when authenticated.\n# @param p_vars - Extra information that will be bundled in the session token.\n# Returns a task which resolves to a session object.\nfunc authenticate_steam_async(p_token : String, p_username = null, p_create : bool = true, p_vars = null, p_sync : bool = false) -> NakamaSession:\n\treturn _parse_auth(await _api_client.authenticate_steam_async(server_key, \"\",\n\t\tNakamaAPI.ApiAccountSteam.create(NakamaAPI, {\n\t\t\t\"token\": p_token,\n\t\t\t\"vars\": p_vars\n\t\t}), p_create, p_username, p_sync))\n\n# Block one or more friends by id or username.\n# @param p_session - The session of the user.\n# @param p_ids - The ids of the users to block.\n# @param p_usernames - The usernames of the users to block.\n# Returns a task which represents the asynchronous operation.\nfunc block_friends_async(p_session : NakamaSession, p_ids : PackedStringArray, p_usernames = null) -> NakamaAsyncResult:\n\treturn await _api_client.block_friends_async(p_session, p_ids, p_usernames);\n\n# Create a group.\n# @param p_session - The session of the user.\n# @param p_name - The name for the group.\n# @param p_description - A description for the group.\n# @param p_avatar_url - An avatar url for the group.\n# @param p_lang_tag - A language tag in BCP-47 format for the group.\n# @param p_open - If the group should have open membership.\n# @param p_max_count - The maximum number of members allowed.\n# Returns a task which resolves to a new group object.\nfunc create_group_async(p_session : NakamaSession, p_name : String, p_description : String = \"\",\n\t\tp_avatar_url = null, p_lang_tag = null, p_open : bool = true, p_max_count : int = 100): # -> NakamaAPI.ApiGroup:\n\treturn await _api_client.create_group_async(p_session,\n\t\tNakamaAPI.ApiCreateGroupRequest.create(NakamaAPI, {\n\t\t\t\"avatar_url\": p_avatar_url,\n\t\t\t\"description\": p_description,\n\t\t\t\"lang_tag\": p_lang_tag,\n\t\t\t\"max_count\": p_max_count,\n\t\t\t\"name\": p_name,\n\t\t\t\"open\": p_open\n\t\t}))\n\n# Delete the current user's account on the server.\n# @param p_session - The session of the user.\n# Returns a task which represents the asynchronous operation.\nfunc delete_account_async(p_session : NakamaSession) -> NakamaAsyncResult:\n\treturn await _api_client.delete_account_async(p_session)\n\n# Delete one more or users by id or username from friends.\n# @param p_session - The session of the user.\n# @param p_ids - The user ids to remove as friends.\n# @param p_usernames - The usernames to remove as friends.\n# Returns a task which represents the asynchronous operation.\nfunc delete_friends_async(p_session : NakamaSession, p_ids : PackedStringArray, p_usernames = null) -> NakamaAsyncResult:\n\treturn await _api_client.delete_friends_async(p_session, p_ids, p_usernames)\n\n# Delete a group by id.\n# @param p_session - The session of the user.\n# @param p_group_id - The group id to to remove.\n# Returns a task which represents the asynchronous operation.\nfunc delete_group_async(p_session : NakamaSession, p_group_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.delete_group_async(p_session, p_group_id)\n\n# Delete a leaderboard record.\n# @param p_session - The session of the user.\n# @param p_leaderboard_id - The id of the leaderboard with the record to be deleted.\n# Returns a task which represents the asynchronous operation.\nfunc delete_leaderboard_record_async(p_session : NakamaSession, p_leaderboard_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.delete_leaderboard_record_async(p_session, p_leaderboard_id)\n\n# Delete one or more notifications by id.\n# @param p_session - The session of the user.\n# @param p_ids - The notification ids to remove.\n# Returns a task which represents the asynchronous operation.\nfunc delete_notifications_async(p_session : NakamaSession, p_ids : PackedStringArray) -> NakamaAsyncResult:\n\treturn await _api_client.delete_notifications_async(p_session, p_ids)\n\n# Delete one or more storage objects.\n# @param p_session - The session of the user.\n# @param p_ids - The ids of the objects to delete.\n# Returns a task which represents the asynchronous operation.\nfunc delete_storage_objects_async(p_session : NakamaSession, p_ids : Array) -> NakamaAsyncResult:\n\tvar ids : Array = []\n\tfor id in p_ids:\n\t\tif not id is NakamaStorageObjectId:\n\t\t\tcontinue # TODO Exceptions\n\t\tvar obj_id : NakamaStorageObjectId = id\n\t\tids.append(obj_id.as_delete().serialize())\n\treturn await _api_client.delete_storage_objects_async(p_session,\n\t\tNakamaAPI.ApiDeleteStorageObjectsRequest.create(NakamaAPI, {\n\t\t\t\"object_ids\": ids\n\t\t}))\n\n# Demote a set of users in a group to the next role down.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group to demote users into.\n# @param p_ids - The IDs of the users to demote.\n# Returns a task which represents the asynchronous operation.\nfunc demote_group_users_async(p_session : NakamaSession, p_group_id : String, p_user_ids : Array):\n\treturn await _api_client.demote_group_users_async(p_session, p_group_id, p_user_ids)\n\n# Submit an event for processing in the server's registered runtime custom events handler.\n# @param p_session - The session of the user.\n# @param p_name - The name of the event.\n# @param p_properties - The properties of the event.\n# Returns a task which represents the asynchronous operation.\nfunc event_async(p_session : NakamaSession, p_name : String, p_properties : Dictionary = {}) -> NakamaAsyncResult:\n\treturn await _api_client.event_async(p_session, NakamaAPI.ApiEvent.create(\n\t\tNakamaAPI,\n\t\t{\n\t\t\t\"name\": p_name,\n\t\t\t\"properties\": p_properties,\n\t\t\t\"external\": true,\n\t\t}\n\t))\n\n# Fetch the user account owned by the session.\n# @param p_session - The session of the user.\n# Returns a task which resolves to the account object.\nfunc get_account_async(p_session : NakamaSession): # -> NakamaAPI.ApiAccount:\n\treturn await _api_client.get_account_async(p_session)\n\n# Get subscription by product id.\n# @param p_session - The session of the user.\n# @param p_product_id - The product id.\n# Returns a task which resolves to the subscription object.\nfunc get_subscription_async(p_session : NakamaSession, p_product_id : String): # -> ApiValidatedSubscription:\n\treturn await _api_client.get_subscription_async(p_session, p_product_id)\n\n# Fetch one or more users by id, usernames, and Facebook ids.\n# @param p_session - The session of the user.\n# @param p_ids - The IDs of the users to retrieve.\n# @param p_usernames - The usernames of the users to retrieve.\n# @param p_facebook_ids - The facebook IDs of the users to retrieve.\n# Returns a task which resolves to a collection of user objects.\nfunc get_users_async(p_session : NakamaSession, p_ids : PackedStringArray, p_usernames = null, p_facebook_ids = null): # -> NakamaAPI.ApiUsers:\n\treturn await _api_client.get_users_async(p_session, p_ids, p_usernames, p_facebook_ids)\n\n# Import Facebook friends and add them to the user's account.\n# The server will import friends when the user authenticates with Facebook. This function can be used to be\n# explicit with the import operation.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Facebook SDK.\n# @param p_reset - If the Facebook friend import for the user should be reset.\n# Returns a task which represents the asynchronous operation.\nfunc import_facebook_friends_async(p_session : NakamaSession, p_token : String, p_reset = null) -> NakamaAsyncResult:\n\treturn await _api_client.import_facebook_friends_async(p_session,\n\t\tNakamaAPI.ApiAccountFacebook.create(NakamaAPI, {\n\t\t\t\"token\": p_token\n\t\t}), p_reset)\n\n# Import Steam friends and add them to the user's account.\n# The server will import friends when the user authenticates with Steam. This function can be used to be\n# explicit with the import operation.\n# @param p_session - The session of the user.\n# @param p_token - An access token from Steam.\n# @param p_reset - If the Steam friend import for the user should be reset.\n# Returns a task which represents the asynchronous operation.\nfunc import_steam_friends_async(p_session : NakamaSession, p_token : String, p_reset = null):\n\treturn await _api_client.import_steam_friends_async(p_session,\n\t\tNakamaAPI.ApiAccountSteam.create(NakamaAPI, {\n\t\t\t\"token\": p_token\n\t\t}), p_reset)\n\n# Join a group if it has open membership or request to join it.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group to join.\n# Returns a task which represents the asynchronous operation.\nfunc join_group_async(p_session : NakamaSession, p_group_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.join_group_async(p_session, p_group_id)\n\n# Join a tournament by ID.\n# @param p_session - The session of the user.\n# @param p_tournament_id - The ID of the tournament to join.\n# Returns a task which represents the asynchronous operation.\nfunc join_tournament_async(p_session : NakamaSession, p_tournament_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.join_tournament_async(p_session, p_tournament_id)\n\n# Kick one or more users from the group.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group.\n# @param p_ids - The IDs of the users to kick.\n# Returns a task which represents the asynchronous operation.\nfunc kick_group_users_async(p_session : NakamaSession, p_group_id : String, p_ids : PackedStringArray) -> NakamaAsyncResult:\n\treturn await _api_client.kick_group_users_async(p_session, p_group_id, p_ids)\n\n# Leave a group by ID.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group to leave.\n# Returns a task which represents the asynchronous operation.\nfunc leave_group_async(p_session : NakamaSession, p_group_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.leave_group_async(p_session, p_group_id)\n\n# Link an Apple ID to the social profiles on the current user's account.\n# @param p_session - The session of the user.\n# @param p_token - The ID token received from Apple to validate.\n# Returns a task which represents the asynchronous operation.\nfunc link_apple_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_apple_async(p_session, NakamaAPI.ApiAccountApple.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Link a custom ID to the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_id - A custom identifier usually obtained from an external authentication service.\n# Returns a task which represents the asynchronous operation.\nfunc link_custom_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_custom_async(p_session, NakamaAPI.ApiAccountCustom.create(NakamaAPI, {\n\t\t\"id\": p_id\n\t}))\n\n# Link a device ID to the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_id - A device identifier usually obtained from a platform API.\n# Returns a task which represents the asynchronous operation.\nfunc link_device_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_device_async(p_session, NakamaAPI.ApiAccountDevice.create(NakamaAPI, {\n\t\t\"id\": p_id\n\t}))\n\n# Link an email with password to the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_email - The email address of the user.\n# @param p_password - The password for the user.\n# Returns a task which represents the asynchronous operation.\nfunc link_email_async(p_session : NakamaSession, p_email : String, p_password : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_email_async(p_session, NakamaAPI.ApiAccountEmail.create(NakamaAPI, {\n\t\t\"email\": p_email,\n\t\t\"password\": p_password\n\t}))\n\n# Link a Facebook profile to a user account.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Facebook SDK.\n# @param p_import - If the Facebook friends should be imported.\n# Returns a task which represents the asynchronous operation.\nfunc link_facebook_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_facebook_async(p_session, NakamaAPI.ApiAccountFacebook.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Add Facebook Instant Game to the social profiles on the current user's account.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Facebook SDK.\n# @param p_import - If the Facebook friends should be imported.\n# Returns a task which represents the asynchronous operation.\nfunc link_facebook_instant_game_async(p_session : NakamaSession, p_signed_player_info : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_facebook_instant_game_async(\n\t\tp_session,\n\t\tNakamaAPI.ApiAccountFacebookInstantGame.create(\n\t\t\tNakamaAPI, {\n\t\t\t\t\"signed_player_info\": p_signed_player_info\n\t\t\t})\n\t\t)\n\n# Link a Game Center profile to a user account.\n# @param p_session - The session of the user.\n# @param p_bundle_id - The bundle ID of the Game Center application.\n# @param p_player_id - The player ID of the user in Game Center.\n# @param p_public_key_url - The URL for the public encryption key.\n# @param p_salt - A random `NSString` used to compute the hash and keep it randomized.\n# @param p_signature - The verification signature data generated.\n# @param p_timestamp_seconds - The date and time that the signature was created.\n# Returns a task which represents the asynchronous operation.\nfunc link_game_center_async(p_session : NakamaSession,\n\t\tp_bundle_id : String, p_player_id : String, p_public_key_url : String, p_salt : String, p_signature : String, p_timestamp_seconds) -> NakamaAsyncResult:\n\treturn await _api_client.link_game_center_async(p_session,\n\t\tNakamaAPI.ApiAccountGameCenter.create(NakamaAPI, {\n\t\t\t\"bundle_id\": p_bundle_id,\n\t\t\t\"player_id\": p_player_id,\n\t\t\t\"public_key_url\": p_public_key_url,\n\t\t\t\"salt\": p_salt,\n\t\t\t\"signature\": p_signature,\n\t\t\t\"timestamp_seconds\": p_timestamp_seconds,\n\t\t}))\n\n# Link a Google profile to a user account.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Google SDK.\n# Returns a task which represents the asynchronous operation.\nfunc link_google_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.link_google_async(p_session, NakamaAPI.ApiAccountGoogle.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Link a Steam profile to a user account.\n# @param p_session - The session of the user.\n# @param p_token - An authentication token from the Steam network.\n# Returns a task which represents the asynchronous operation.\nfunc link_steam_async(p_session : NakamaSession, p_token : String, p_sync : bool = false) -> NakamaAsyncResult:\n\treturn await _api_client.link_steam_async(p_session, NakamaAPI.ApiLinkSteamRequest.create(\n\t\tNakamaAPI,\n\t\t{\n\t\t\t\"account\": NakamaAPI.ApiAccountSteam.create(NakamaAPI, {\n\t\t\t\t\"token\": p_token\n\t\t\t}).serialize(),\n\t\t\t\"sync\": p_sync\n\t\t}\n\n\t))\n\n# List messages from a chat channel.\n# @param p_session - The session of the user.\n# @param p_channel_id - The id of the chat channel.\n# @param p_limit - The number of chat messages to list.\n# @param forward - Fetch messages forward from the current cursor (or the start).\n# @param p_cursor - A cursor for the current position in the messages history to list.\n# Returns a task which resolves to the channel message list object.\nfunc list_channel_messages_async(p_session : NakamaSession, p_channel_id : String, limit : int = 1,\n\t\tforward : bool = true, cursor = null): # -> NakamaAPI.ApiChannelMessageList:\n\treturn await _api_client.list_channel_messages_async(p_session, p_channel_id, limit, forward, cursor)\n\n# List of friends of the current user.\n# @param p_session - The session of the user.\n# @param p_state - Filter by friendship state.\n# @param p_limit - The number of friends to list.\n# @param p_cursor - A cursor for the current position in the friends list.\n# Returns a task which resolves to the friend objects.\nfunc list_friends_async(p_session : NakamaSession, p_state = null, p_limit = null, p_cursor = null): # -> NakamaAPI.ApiFriendList:\n\treturn await _api_client.list_friends_async(p_session, p_limit, p_state, p_cursor)\n\n# List all users part of the group.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group.\n# @param p_state - Filter by group membership state.\n# @param p_limit - The number of groups to list.\n# @param p_cursor - A cursor for the current position in the group listing.\n# Returns a task which resolves to the group user objects.\nfunc list_group_users_async(p_session : NakamaSession, p_group_id : String, p_state = null, p_limit = null, p_cursor = null): # -> NakamaAPI.ApiGroupUserList:\n\treturn await _api_client.list_group_users_async(p_session, p_group_id, p_limit, p_state, p_cursor)\n\n# List groups on the server.\n# @param p_session - The session of the user.\n# @param p_name - The name filter to apply to the group list.\n# @param p_limit - The number of groups to list.\n# @param p_cursor - A cursor for the current position in the groups to list.\n# @param p_lang_tag - The language tag filter.\n# @param p_members - The number of group members filter.\n# @param p_open - Optional open/closed filter.\n# Returns a task to resolve group objects.\nfunc list_groups_async(p_session : NakamaSession, p_name = null, p_limit : int = 10, p_cursor = null, p_lang_tag = null, p_members = null, p_open = null): # -> NakamaAPI.ApiGroupList:\n\treturn await _api_client.list_groups_async(p_session, p_name, p_cursor, p_limit, p_lang_tag, p_members, p_open)\n\n# List records from a leaderboard.\n# @param p_session - The session of the user.\n# @param p_leaderboard_id - The ID of the leaderboard to list.\n# @param p_owner_ids - Record owners to fetch with the list of records.\n# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from. Optional. 0 means from current time.\n# @param p_limit - The number of records to list.\n# @param p_cursor - A cursor for the current position in the leaderboard records to list.\n# Returns a task which resolves to the leaderboard record objects.\nfunc list_leaderboard_records_async(p_session : NakamaSession,\n\t\tp_leaderboard_id : String, p_owner_ids = null, p_expiry = null, p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiLeaderboardRecordList:\n\treturn await _api_client.list_leaderboard_records_async(p_session,\n\t\tp_leaderboard_id, p_owner_ids, p_limit, p_cursor, p_expiry)\n\n# List leaderboard records that belong to a user.\n# @param p_session - The session for the user.\n# @param p_leaderboard_id - The ID of the leaderboard to list.\n# @param p_owner_id - The ID of the user to list around.\n# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from. Optional. 0 means from current time.\n# @param p_limit - The limit of the listings.\n# @param p_cursor - A cursor for the current position in the leaderboard records to list.\n# Returns a task which resolves to the leaderboard record objects.\nfunc list_leaderboard_records_around_owner_async(p_session : NakamaSession,\n\t\tp_leaderboar_id : String, p_owner_id : String, p_expiry = null, p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiLeaderboardRecordList:\n\treturn await _api_client.list_leaderboard_records_around_owner_async(p_session,\n\t\tp_leaderboar_id, p_owner_id, p_limit, p_expiry, p_cursor)\n\n# Fetch a list of matches active on the server.\n# @param p_session - The session of the user.\n# @param p_min - The minimum number of match participants.\n# @param p_max - The maximum number of match participants.\n# @param p_limit - The number of matches to list.\n# @param p_authoritative - If authoritative matches should be included.\n# @param p_label - The label to filter the match list on.\n# @param p_query - A query for the matches to filter.\n# Returns a task which resolves to the match list object.\nfunc list_matches_async(p_session : NakamaSession, p_min : int, p_max : int, p_limit : int, p_authoritative : bool,\n\t\tp_label : String, p_query : String): # -> NakamaAPI.ApiMatchList:\n\treturn await _api_client.list_matches_async(p_session, p_limit, p_authoritative, p_label if p_label else null, p_min, p_max, p_query if p_query else null)\n\n# List notifications for the user with an optional cursor.\n# @param p_session - The session of the user.\n# @param p_limit - The number of notifications to list.\n# @param p_cacheable_cursor - A cursor for the current position in notifications to list.\n# Returns a task to resolve notifications objects.\nfunc list_notifications_async(p_session : NakamaSession, p_limit : int = 10, p_cacheable_cursor = null): # -> NakamaAPI.ApiNotificationList:\n\treturn await _api_client.list_notifications_async(p_session, p_limit, p_cacheable_cursor)\n\n# List storage objects in a collection which have public read access.\n# @param p_session - The session of the user.\n# @param p_collection - The collection to list over.\n# @param p_user_id - The id of the user that owns the objects.\n# @param p_limit - The number of objects to list.\n# @param p_cursor - A cursor to paginate over the collection.\n# Returns a task which resolves to the storage object list.\nfunc list_storage_objects_async(p_session : NakamaSession, p_collection : String, p_user_id : String = \"\", p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiStorageObjectList:\n\treturn await _api_client.list_storage_objects_async(p_session, p_collection, p_user_id, p_limit, p_cursor)\n\n# List user's subscriptions.\n# @param p_session - The session of the user.\n# @param p_limit - The number of objects to list.\n# @param p_cursor - A cursor to paginate over the collection.\n# Returns a task which resolves to the subscription list.\nfunc list_subscriptions_async(p_session : NakamaSession, p_limit: int = 10, p_cursor = null): # -> NakamaAPI.ApiSubscriptionList:\n\treturn await _api_client.list_subscriptions_async(p_session, NakamaAPI.ApiListSubscriptionsRequest.create(\n\t\tNakamaAPI,\n\t\t{\n\t\t\t\"cursor\": p_cursor,\n\t\t\t\"limit\": p_limit,\n\t\t}\n\t))\n\n# List tournament records around the owner.\n# @param p_session - The session of the user.\n# @param p_tournament_id - The ID of the tournament.\n# @param p_owner_id - The ID of the owner to pivot around.\n# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from.\n# @param p_limit - The number of records to list.\n# @param p_cursor - An optional cursor for the next page of tournament records.\n# Returns a task which resolves to the tournament record list object.\nfunc list_tournament_records_around_owner_async(p_session : NakamaSession,\n\t\tp_tournament_id : String, p_owner_id : String, p_limit : int = 10, p_cursor = null, p_expiry = null): # -> NakamaAPI.ApiTournamentRecordList:\n\treturn await _api_client.list_tournament_records_around_owner_async(p_session, p_tournament_id, p_owner_id, p_limit, p_expiry, p_cursor)\n\n# List records from a tournament.\n# @param p_session - The session of the user.\n# @param p_tournament_id - The ID of the tournament.\n# @param p_owner_ids - The IDs of the record owners to return in the result.\n# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from.\n# @param p_limit - The number of records to list.\n# @param p_cursor - An optional cursor for the next page of tournament records.\n# Returns a task which resolves to the list of tournament records.\nfunc list_tournament_records_async(p_session : NakamaSession, p_tournament_id : String,\n\t\tp_owner_ids = null, p_limit : int = 10, p_cursor = null, p_expiry = null): # -> NakamaAPI.ApiTournamentRecordList:\n\treturn await _api_client.list_tournament_records_async(p_session, p_tournament_id, p_owner_ids, p_limit, p_cursor, p_expiry)\n\n# List current or upcoming tournaments.\n# @param p_session - The session of the user.\n# @param p_category_start - The start of the category of tournaments to include.\n# @param p_category_end - The end of the category of tournaments to include.\n# @param p_start_time - The start time of the tournaments. (UNIX timestamp)\n# @param p_end_time - The end time of the tournaments. (UNIX timestamp)\n# @param p_limit - The number of tournaments to list.\n# @param p_cursor - An optional cursor for the next page of tournaments.\n# Returns a task which resolves to the list of tournament objects.\nfunc list_tournaments_async(p_session : NakamaSession, p_category_start : int, p_category_end : int,\n\t\tp_start_time : int, p_end_time : int, p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiTournamentList:\n\treturn await _api_client.list_tournaments_async(p_session,\n\t\tp_category_start, p_category_end, p_start_time, p_end_time, p_limit, p_cursor)\n\n# List of groups the current user is a member of.\n# @param p_session - The session of the user.\n# @param p_user_id - The ID of the user whose groups to list.\n# @param p_state - Filter by group membership state.\n# @param p_limit - The number of records to list.\n# @param p_cursor - A cursor for the current position in the listing.\n# Returns a task which resolves to the group list object.\nfunc list_user_groups_async(p_session : NakamaSession, p_user_id : String, p_state = null, p_limit = null, p_cursor = null): # -> NakamaAPI.ApiUserGroupList:\n\treturn await _api_client.list_user_groups_async(p_session, p_user_id, p_limit, p_state, p_cursor)\n\n# List storage objects in a collection which belong to a specific user and have public read access.\n# @param p_session - The session of the user.\n# @param p_collection - The collection to list over.\n# @param p_user_id - The user ID of the user to list objects for.\n# @param p_limit - The number of objects to list.\n# @param p_cursor - A cursor to paginate over the collection.\n# Returns a task which resolves to the storage object list.\nfunc list_users_storage_objects_async(p_session : NakamaSession,\n\t\tp_collection : String, p_user_id : String, p_limit : int, p_cursor : String): # -> NakamaAPI.ApiStorageObjectList:\n\treturn await _api_client.list_storage_objects2_async(p_session, p_collection, p_user_id, p_limit, p_cursor)\n\n# Promote one or more users in the group.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group to promote users into.\n# @param p_ids - The IDs of the users to promote.\n# Returns a task which represents the asynchronous operation.\nfunc promote_group_users_async(p_session : NakamaSession, p_group_id : String, p_ids : PackedStringArray) -> NakamaAsyncResult:\n\treturn await _api_client.promote_group_users_async(p_session, p_group_id, p_ids)\n\n# Read one or more objects from the storage engine.\n# @param p_session - The session of the user.\n# @param p_ids - The objects to read.\n# Returns a task which resolves to the storage batch object.\nfunc read_storage_objects_async(p_session : NakamaSession, p_ids : Array): # -> NakamaAPI.ApiStorageObjects:\n\tvar ids = []\n\tfor id in p_ids:\n\t\tif not id is NakamaStorageObjectId:\n\t\t\tcontinue # TODO Exceptions\n\t\tvar obj_id : NakamaStorageObjectId = id\n\t\tids.append(obj_id.as_read().serialize())\n\treturn await _api_client.read_storage_objects_async(p_session,\n\t\tNakamaAPI.ApiReadStorageObjectsRequest.create(NakamaAPI, {\n\t\t\t\"object_ids\": ids\n\t\t}))\n\n# Execute a function with an input payload on the server.\n# @param p_session - The session of the user.\n# @param p_id - The ID of the function to execute on the server.\n# @param p_payload - The payload to send with the function call.\n# Returns a task which resolves to the RPC response.\nfunc rpc_async(p_session : NakamaSession, p_id : String, p_payload = null): # -> NakamaAPI.ApiRpc:\n\tif p_payload == null:\n\t\treturn await _api_client.rpc_func2_async(p_session.token, p_id)\n\treturn await _api_client.rpc_func_async(p_session.token, p_id, p_payload)\n\n# Execute a function on the server without a session.\n# This function is usually used with server side code. DO NOT USE client side.\n# @param p_http_key - The secure HTTP key used to authenticate.\n# @param p_id - The id of the function to execute on the server.\n# @param p_payload - A payload to send with the function call.\n# Returns a task to resolve an RPC response.\nfunc rpc_async_with_key(p_http_key : String, p_id : String, p_payload = null): # -> NakamaAPI.ApiRpc:\n\tif p_payload == null:\n\t\treturn await _api_client.rpc_func2_async(\"\", p_id, null, p_http_key)\n\treturn await _api_client.rpc_func_async(\"\", p_id, p_payload, p_http_key)\n\n# Log out a session which optionally invalidates the authorization and/or refresh tokens.\n# @param p_session - The session of the user.\n# Returns a task which represents the asynchronous operation.\nfunc session_logout_async(p_session : NakamaSession) -> NakamaAsyncResult:\n\treturn await _api_client.session_logout_async(p_session,\n\t\tNakamaAPI.ApiSessionLogoutRequest.create(NakamaAPI, {\n\t\t\t\"refresh_token\": p_session.refresh_token,\n\t\t\t\"token\": p_session.token\n\t\t}))\n\n# Refresh the session unless the current refresh token has expired. If vars are specified they will replace\n# what is currently stored inside the session token.\n# @param p_session - The session of the user.\n# @param p_vars - Extra information which should be bundled inside the session token.\n# Returns a task which resolves to a new session object.\nfunc session_refresh_async(p_sesison : NakamaSession, p_vars = null) -> NakamaSession:\n\treturn _parse_auth(await _api_client.session_refresh_async(server_key, \"\",\n\t\tNakamaAPI.ApiSessionRefreshRequest.create(NakamaAPI, {\n\t\t\t\"token\": p_sesison.refresh_token,\n\t\t\t\"vars\": p_vars\n\t\t})))\n\n# Remove the Apple ID from the social profiles on the current user's account.\n# @param p_session - The session of the user.\n# @param p_token - The ID token received from Apple.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_apple_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_apple_async(p_session, NakamaAPI.ApiAccountApple.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Unlink a custom ID from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_id - A custom identifier usually obtained from an external authentication service.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_custom_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_custom_async(p_session, NakamaAPI.ApiAccountCustom.create(NakamaAPI, {\n\t\t\"id\": p_id\n\t}))\n\n# Unlink a device ID from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_id - A device identifier usually obtained from a platform API.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_device_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_device_async(p_session, NakamaAPI.ApiAccountDevice.create(NakamaAPI, {\n\t\t\"id\": p_id\n\t}))\n\n# Unlink an email with password from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_email - The email address of the user.\n# @param p_password - The password for the user.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_email_async(p_session : NakamaSession, p_email : String, p_password : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_email_async(p_session, NakamaAPI.ApiAccountEmail.create(NakamaAPI, {\n\t\t\"email\": p_email,\n\t\t\"password\": p_password\n\t}))\n\n# Unlink a Facebook profile from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Facebook SDK.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_facebook_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_facebook_async(p_session, NakamaAPI.ApiAccountFacebook.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Unlink a Facebook profile from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Facebook SDK.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_facebook_instant_game_async(p_session : NakamaSession, p_signed_player_info : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_facebook_instant_game_async(\n\t\tp_session,\n\t\tNakamaAPI.ApiAccountFacebookInstantGame.create(NakamaAPI, {\n\t\t\t\"signed_player_info\": p_signed_player_info\n\t\t})\n\t)\n\n# Unlink a Game Center profile from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_bundle_id - The bundle ID of the Game Center application.\n# @param p_player_id - The player ID of the user in Game Center.\n# @param p_public_key_url - The URL for the public encryption key.\n# @param p_salt - A random `NSString` used to compute the hash and keep it randomized.\n# @param p_signature - The verification signature data generated.\n# @param p_timestamp_seconds - The date and time that the signature was created.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_game_center_async(p_session : NakamaSession,\n\t\tp_bundle_id : String, p_player_id : String, p_public_key_url : String, p_salt : String, p_signature : String, p_timestamp_seconds) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_game_center_async(p_session,\n\t\tNakamaAPI.ApiAccountGameCenter.create(NakamaAPI, {\n\t\t\t\"bundle_id\": p_bundle_id,\n\t\t\t\"player_id\": p_player_id,\n\t\t\t\"public_key_url\": p_public_key_url,\n\t\t\t\"salt\": p_salt,\n\t\t\t\"signature\": p_signature,\n\t\t\t\"timestamp_seconds\": p_timestamp_seconds,\n\t\t}))\n\n# Unlink a Google profile from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_token - An OAuth access token from the Google SDK.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_google_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_google_async(p_session, NakamaAPI.ApiAccountGoogle.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Unlink a Steam profile from the user account owned by the session.\n# @param p_session - The session of the user.\n# @param p_token - An authentication token from the Steam network.\n# Returns a task which represents the asynchronous operation.\nfunc unlink_steam_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:\n\treturn await _api_client.unlink_steam_async(p_session, NakamaAPI.ApiAccountSteam.create(NakamaAPI, {\n\t\t\"token\": p_token\n\t}))\n\n# Update the current user's account on the server.\n# @param p_session - The session for the user.\n# @param p_username - The new username for the user.\n# @param p_display_name - A new display name for the user.\n# @param p_avatar_url - A new avatar url for the user.\n# @param p_lang_tag - A new language tag in BCP-47 format for the user.\n# @param p_location - A new location for the user.\n# @param p_timezone - New timezone information for the user.\n# Returns a task which represents the asynchronous operation.\nfunc update_account_async(p_session : NakamaSession, p_username = null, p_display_name = null,\n\t\tp_avatar_url = null, p_lang_tag = null, p_location = null, p_timezone = null) -> NakamaAsyncResult:\n\treturn await _api_client.update_account_async(p_session,\n\t\tNakamaAPI.ApiUpdateAccountRequest.create(NakamaAPI, {\n\t\t\t\"avatar_url\": p_avatar_url,\n\t\t\t\"display_name\": p_display_name,\n\t\t\t\"lang_tag\": p_lang_tag,\n\t\t\t\"location\": p_location,\n\t\t\t\"timezone\": p_timezone,\n\t\t\t\"username\": p_username\n\t\t}))\n\n# Update a group.\n# The user must have the correct access permissions for the group.\n# @param p_session - The session of the user.\n# @param p_group_id - The ID of the group to update.\n# @param p_name - A new name for the group.\n# @param p_open - If the group should have open membership.\n# @param p_description - A new description for the group.\n# @param p_avatar_url - A new avatar url for the group.\n# @param p_lang_tag - A new language tag in BCP-47 format for the group.\n# Returns a task which represents the asynchronous operation.\nfunc update_group_async(p_session : NakamaSession,\n\t\tp_group_id : String, p_name = null, p_description = null, p_avatar_url = null, p_lang_tag = null, p_open = null) -> NakamaAsyncResult:\n\treturn await _api_client.update_group_async(p_session, p_group_id,\n\t\tNakamaAPI.ApiUpdateGroupRequest.create(NakamaAPI, {\n\t\t\t\"name\": p_name,\n\t\t\t\"open\": p_open,\n\t\t\t\"avatar_url\": p_avatar_url,\n\t\t\t\"description\": p_description,\n\t\t\t\"lang_tag\": p_lang_tag\n\t\t}))\n\n# Validate a purchase receipt against the Apple App Store.\n# @param p_session - The session of the user.\n# @param p_receipt - The purchase receipt to be validated.\n# Returns a task which resolves to the validated list of purchase receipts.\nfunc validate_purchase_apple_async(p_session : NakamaSession, p_receipt : String): # -> NakamaAPI.ApiValidatePurchaseResponse\n\treturn await _api_client.validate_purchase_apple_async(p_session,\n\t\tNakamaAPI.ApiValidatePurchaseAppleRequest.create(NakamaAPI, {\n\t\t\t\"receipt\": p_receipt\n\t\t}))\n\n# Validate a purchase receipt against the Google Play Store.\n# @param p_session - The session of the user.\n# @param p_receipt - The purchase receipt to be validated.\n# Returns a task which resolves to the validated list of purchase receipts.\nfunc validate_purchase_google_async(p_session : NakamaSession, p_receipt : String): # -> NakamaAPI.ApiValidatePurchaseResponse\n\treturn await _api_client.validate_purchase_google_async(p_session,\n\t\tNakamaAPI.ApiValidatePurchaseGoogleRequest.create(NakamaAPI, {\n\t\t\t\"purchase\": p_receipt\n\t\t}))\n\n# Validate a purchase receipt against the Huawei AppGallery.\n# @param p_session - The session of the user.\n# @param p_receipt - The purchase receipt to be validated.\n# @param p_signature - The signature of the purchase receipt.\n# Returns a task which resolves to the validated list of purchase receipts.\nfunc validate_purchase_huawei_async(p_session : NakamaSession, p_receipt : String, p_signature : String): # -> NakamaAPI.ApiValidatePurchaseResponse\n\treturn await _api_client.validate_purchase_huawei_async(p_session,\n\t\tNakamaAPI.ApiValidatePurchaseHuaweiRequest.create(NakamaAPI, {\n\t\t\t\"purchase\": p_receipt,\n\t\t\t\"signature\": p_signature\n\t\t}))\n\n# Validate Apple Subscription Receipt\n# @param p_session - The session of the user.\n# @param p_receipt - The purchase receipt to be validated.\n# @param p_persist - Whether or not to track the receipt in the Nakama database.\n# Returns a task which resolves to the validated subscription response.\nfunc validate_subscription_apple_async(p_session : NakamaSession, p_receipt : String, p_persist : bool = true): # -> NakamaAPI.ApiValidateSubscriptionResponse:\n\treturn await _api_client.validate_subscription_apple_async(p_session,\n\t\tNakamaAPI.ApiValidateSubscriptionAppleRequest.create(NakamaAPI, {\n\t\t\t\"receipt\": p_receipt,\n\t\t\t\"persist\": p_persist,\n\t\t}))\n\n# Validate Google Subscription Receipt\n# @param p_session - The session of the user.\n# @param p_receipt - The purchase receipt to be validated.\n# @param p_persist - Whether or not to track the receipt in the Nakama database.\n# Returns a task which resolves to the validated subscription response.\nfunc validate_subscription_google_async(p_session : NakamaSession, p_receipt : String, p_persist : bool = true): # -> NakamaAPI.ApiValidateSubscriptionResponse:\n\treturn await _api_client.validate_subscription_google_async(p_session,\n\t\tNakamaAPI.ApiValidateSubscriptionGoogleRequest.create(NakamaAPI, {\n\t\t\t\"receipt\": p_receipt,\n\t\t\t\"persist\": p_persist,\n\t\t}))\n\n# Write a record to a leaderboard.\n# @param p_session - The session for the user.\n# @param p_leaderboard_id - The ID of the leaderboard to write.\n# @param p_score - The score for the leaderboard record.\n# @param p_subscore - The subscore for the leaderboard record.\n# @param p_metadata - The metadata for the leaderboard record.\n# Returns a task which resolves to the leaderboard record object written.\nfunc write_leaderboard_record_async(p_session : NakamaSession,\n\t\tp_leaderboard_id : String, p_score : int, p_subscore : int = 0, p_metadata = null): # -> NakamaAPI.ApiLeaderboardRecord:\n\treturn await _api_client.write_leaderboard_record_async(p_session, p_leaderboard_id,\n\t\tNakamaAPI.WriteLeaderboardRecordRequestLeaderboardRecordWrite.create(NakamaAPI, {\n\t\t\t\"metadata\": p_metadata,\n\t\t\t\"score\": str(p_score),\n\t\t\t\"subscore\": str(p_subscore)\n\t\t}))\n\n# Write objects to the storage engine.\n# @param p_session - The session of the user.\n# @param p_objects - The objects to write.\n# Returns a task which resolves to the storage write acknowledgements.\nfunc write_storage_objects_async(p_session : NakamaSession, p_objects : Array): # -> NakamaAPI.ApiStorageObjectAcks:\n\tvar writes : Array = []\n\tfor obj in p_objects:\n\t\tif not obj is NakamaWriteStorageObject:\n\t\t\tcontinue # TODO Exceptions\n\t\tvar write_obj : NakamaWriteStorageObject = obj\n\t\twrites.append(write_obj.as_write().serialize())\n\treturn await _api_client.write_storage_objects_async(p_session,\n\t\tNakamaAPI.ApiWriteStorageObjectsRequest.create(NakamaAPI, {\n\t\t\t\"objects\": writes\n\t\t}))\n\n# Write a record to a tournament.\n# @param p_session - The session of the user.\n# @param p_tournament_id - The ID of the tournament to write.\n# @param p_score - The score of the tournament record.\n# @param p_subscore - The subscore for the tournament record.\n# @param p_metadata - The metadata for the tournament record.\n# Returns a task which resolves to the tournament record object written.\nfunc write_tournament_record_async(p_session : NakamaSession,\n\t\tp_tournament_id : String, p_score : int, p_subscore : int = 0, p_metadata = null): # -> NakamaAPI.ApiLeaderboardRecord:\n\treturn await _api_client.write_tournament_record_async(p_session, p_tournament_id,\n\t\tNakamaAPI.WriteTournamentRecordRequestTournamentRecordWrite.create(NakamaAPI, {\n\t\t\t\"metadata\": p_metadata,\n\t\t\t\"score\": str(p_score),\n\t\t\t\"subscore\": str(p_subscore)\n\t\t}))\n\n# Write a record to a tournament.\n# @param p_session - The session of the user.\n# @param p_tournament_id - The ID of the tournament to write.\n# @param p_score - The score of the tournament record.\n# @param p_subscore - The subscore for the tournament record.\n# @param p_metadata - The metadata for the tournament record.\n# Returns a task which resolves to the tournament record object written.\nfunc write_tournament_record2_async(p_session : NakamaSession,\n\t\tp_tournament_id : String, p_score : int, p_subscore : int = 0, p_metadata = null): # -> NakamaAPI.ApiLeaderboardRecord:\n\treturn await _api_client.write_tournament_record2_async(p_session, p_tournament_id,\n\t\tNakamaAPI.WriteTournamentRecordRequestTournamentRecordWrite.create(NakamaAPI, {\n\t\t\t\"metadata\": p_metadata,\n\t\t\t\"score\": str(p_score),\n\t\t\t\"subscore\": str(p_subscore)\n\t\t}))\n\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/client/NakamaHTTPAdapter.gd",
    "content": "@tool\nextends Node\n\n# An adapter which implements the HTTP protocol.\nclass_name NakamaHTTPAdapter\n\n# The logger to use with the adapter.\nvar logger : RefCounted = NakamaLogger.new()\n\n# The timeout for requests\nvar timeout : int = 3\n# If request should be automatically retried when a network error occurs.\nvar auto_retry : bool = true\n# The maximum number of time a request will be retried when auto_retry is true\nvar auto_retry_count : int = 3\nvar auto_retry_backoff_base : int = 10\n# Whether or not to use threads when making HTTP requests.\nvar use_threads : bool = true\n\nvar _pending = {}\nvar id : int = 0\n\nclass AsyncRequest:\n\tvar id : int\n\tvar request : HTTPRequest\n\tvar uri : String\n\tvar method : int\n\tvar headers : PackedStringArray\n\tvar body : PackedByteArray\n\tvar retry_count := 3\n\tvar backoff_time := 10\n\tvar logger : NakamaLogger\n\n\tvar cancelled = false\n\tvar result : int = HTTPRequest.RESULT_NO_RESPONSE\n\tvar response_code : int = -1\n\tvar response_body : PackedByteArray\n\tvar timer : SceneTreeTimer = null\n\tvar cur_try : int = 1\n\tvar rng = RandomNumberGenerator.new()\n\n\tfunc _init(p_id : int, p_request : HTTPRequest, p_uri : String,\n\t\t\tp_method : int, p_headers : PackedStringArray, p_body : PackedByteArray,\n\t\t\tp_retry_count : int, p_backoff_time : int, p_logger : NakamaLogger):\n\t\trng.seed = Time.get_ticks_usec()\n\t\tid = p_id\n\t\trequest = p_request\n\t\turi = p_uri\n\t\tmethod = p_method\n\t\theaders = p_headers\n\t\tbody = p_body\n\t\tretry_count = p_retry_count\n\t\tbackoff_time = p_backoff_time\n\t\tlogger = p_logger\n\n\tfunc should_retry():\n\t\treturn cur_try < retry_count and not cancelled\n\n\tfunc retry():\n\t\tvar time = pow(backoff_time, cur_try) * rng.randf_range(0.5, 1)\n\t\tlogger.debug(\"Retrying request %d. Tries left: %d. Backoff: %d ms\" % [\n\t\t\tid, retry_count - cur_try, time\n\t\t])\n\t\tcur_try += 1\n\t\tawait backoff(time)\n\t\tif cancelled:\n\t\t\treturn\n\t\treturn await make_request()\n\n\tfunc make_request():\n\t\tvar err = request.request(uri, headers, method, body.get_string_from_utf8())\n\t\tif err != OK:\n\t\t\tawait request.get_tree().process_frame\n\t\t\tresult = HTTPRequest.RESULT_CANT_CONNECT\n\t\t\tlogger.debug(\"Request %d failed to start, error: %d\" % [id, err])\n\t\t\treturn\n\n\t\tvar args = await request.request_completed\n\t\tresult = args[0]\n\t\tresponse_code = args[1]\n\t\tresponse_body = args[3]\n\n\tfunc backoff(p_time : int):\n\t\ttimer = request.get_tree().create_timer(p_time / 1000)\n\t\tawait timer.timeout\n\t\ttimer = null\n\n\tfunc cancel():\n\t\tcancelled = true\n\t\trequest.cancel_request()\n\t\tif timer:\n\t\t\ttimer.time_left = 0\n\t\telse:\n\t\t\trequest.call_deferred(\"emit_signal\", \"request_completed\", HTTPRequest.RESULT_REQUEST_FAILED, 0, [], [])\n\n\tfunc parse_result():\n\t\tif cancelled:\n\t\t\treturn NakamaException.new(\"Request cancelled\", -1, -1, true)\n\t\telif result != HTTPRequest.RESULT_SUCCESS:\n\t\t\tif result == null:\n\t\t\t\tresult = 0\n\t\t\treturn NakamaException.new(\"HTTPRequest failed!\", result)\n\n\t\tvar json = JSON.new()\n\n\t\tvar json_error = json.parse(response_body.get_string_from_utf8())\n\t\tif json_error != OK:\n\t\t\tlogger.debug(\"Unable to parse request %d response. JSON error: %d, JSON error message: %s, response code: %d\" % [\n\t\t\t\tid, json_error, json.get_error_message(), response_code\n\t\t\t])\n\t\t\treturn NakamaException.new(\"Failed to decode JSON response\", response_code)\n\n\t\tvar parsed = json.get_data()\n\n\t\tif response_code != HTTPClient.RESPONSE_OK:\n\t\t\tvar error = \"\"\n\t\t\tvar code = -1\n\t\t\tif typeof(parsed) == TYPE_DICTIONARY:\n\t\t\t\tif \"message\" in parsed:\n\t\t\t\t\terror = parsed[\"message\"]\n\t\t\t\telif \"error\" in parsed:\n\t\t\t\t\terror = parsed[\"error\"]\n\t\t\t\telse:\n\t\t\t\t\terror = str(parsed)\n\t\t\t\tcode = parsed[\"code\"] if \"code\" in parsed else -1\n\t\t\telse:\n\t\t\t\terror = str(parsed)\n\t\t\tif typeof(error) == TYPE_DICTIONARY:\n\t\t\t\terror = JSON.stringify(error)\n\t\t\tlogger.debug(\"Request %d returned response code: %d, RPC code: %d, error: %s\" % [\n\t\t\t\tid, response_code, code, error\n\t\t\t])\n\t\t\treturn NakamaException.new(error, response_code, code)\n\n\t\treturn parsed\n\n\n# Send a HTTP request.\n# @param method - HTTP method to use for this request.\n# @param uri - The fully qualified URI to use.\n# @param headers - Request headers to set.\n# @param body - Request content body to set.\n# @param timeoutSec - Request timeout.\n# Returns a task which resolves to the contents of the response.\nfunc send_async(p_method : String, p_uri : String, p_headers : Dictionary, p_body : PackedByteArray):\n\tvar req = HTTPRequest.new()\n\treq.timeout = timeout\n\tif use_threads and OS.get_name() != 'Web':\n\t\treq.use_threads = true # Threads not available nor needed on the web.\n\n\t# Parse method\n\tvar method = HTTPClient.METHOD_GET\n\tif p_method == \"POST\":\n\t\tmethod = HTTPClient.METHOD_POST\n\telif p_method == \"PUT\":\n\t\tmethod = HTTPClient.METHOD_PUT\n\telif p_method == \"DELETE\":\n\t\tmethod = HTTPClient.METHOD_DELETE\n\telif p_method == \"HEAD\":\n\t\tmethod = HTTPClient.METHOD_HEAD\n\tvar headers = PackedStringArray()\n\n\t# Parse headers\n\theaders.append(\"Accept: application/json\")\n\tfor k in p_headers:\n\t\theaders.append(\"%s: %s\" % [k, p_headers[k]])\n\n\tid += 1\n\tvar retry = auto_retry_count if auto_retry else 0\n\tvar backoff = auto_retry_backoff_base\n\t_pending[id] = AsyncRequest.new(id, req, p_uri, method, headers, p_body, retry, backoff, logger)\n\n\tlogger.debug(\"Sending request [ID: %d, Method: %s, Uri: %s, Headers: %s, Body: %s, Timeout: %d, Retries: %d, Backoff base: %d ms]\" % [\n\t\tid, p_method, p_uri, p_headers, p_body.get_string_from_utf8(), timeout, retry, backoff\n\t])\n\n\tadd_child(req)\n\n\treturn await _send_async(id, _pending)\n\nfunc get_last_token():\n\treturn id\n\nfunc cancel_request(p_token):\n\tif _pending.has(p_token):\n\t\t_pending[p_token].cancel()\n\nstatic func _clear_request(p_request : AsyncRequest, p_pending : Dictionary, p_id : int):\n\tif not p_request.request.is_queued_for_deletion():\n\t\tp_request.logger.debug(\"Freeing request %d\" % p_id)\n\t\tp_request.request.queue_free()\n\t\tp_pending.erase(p_id)\n\nstatic func _send_async(p_id : int, p_pending : Dictionary):\n\n\tvar req : AsyncRequest = p_pending[p_id]\n\tawait req.make_request()\n\n\twhile req.result != HTTPRequest.RESULT_SUCCESS:\n\t\treq.logger.debug(\"Request %d failed with result: %d, response code: %d\" % [\n\t\t\tp_id, req.result, req.response_code\n\t\t])\n\t\tif not req.should_retry():\n\t\t\tbreak\n\t\tawait req.retry()\n\n\t_clear_request(req, p_pending, p_id)\n\treturn req.parse_result()\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs",
    "content": "// Copyright 2022 The Nakama Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Nakama.TinyJson;\nusing Godot;\n\nnamespace Nakama {\n\n    /// <summary>\n    /// An Http adapter which uses Godot's HttpRequest node.\n    /// </summary>\n    /// <remarks>\n    /// Note Content-Type header is always set as 'application/json'.\n    /// </remarks>\n    public partial class GodotHttpAdapter : Node, IHttpAdapter {\n\n        /// <inheritdoc cref=\"IHttpAdapter.Logger\"/>\n        public ILogger Logger { get; set; }\n\n        /// <inheritdoc cref=\"IHttpAdapter.TransientExceptionDelegate\"/>\n        public TransientExceptionDelegate TransientExceptionDelegate => IsTransientException;\n\n        /// <inheritdoc cref=\"IHttpAdapter\"/>\n        public async Task<string> SendAsync(string method, Uri uri, IDictionary<string, string> headers,\n            byte[] body, int timeout, CancellationToken? cancellationToken)\n        {\n            var req = new HttpRequest();\n            req.Timeout = timeout;\n\n            if (OS.GetName() != \"HTML5\") {\n                req.UseThreads = true;\n            }\n\n            var godot_method = HttpClient.Method.Get;\n            if (method == \"POST\") {\n                godot_method = HttpClient.Method.Post;\n            }\n            else if (method == \"PUT\") {\n                godot_method = HttpClient.Method.Put;\n            }\n            else if (method == \"DELETE\") {\n                godot_method = HttpClient.Method.Delete;\n            }\n            else if (method == \"HEAD\") {\n                godot_method = HttpClient.Method.Head;\n            }\n\n            var headers_array = new String[headers.Count + 1];\n            headers_array[0] = \"Accept: application/json\";\n            int index = 1;\n            foreach (var item in headers) {\n                headers_array[index] = item.Key + \": \" + item.Value;\n                index++;\n            }\n\n            string body_string = body != null ? System.Text.Encoding.UTF8.GetString(body) : \"\";\n\n            AddChild(req);\n            req.Request(uri.ToString(), headers_array, godot_method, body_string);\n\n            Logger?.InfoFormat(\"Send: method='{0}', uri='{1}', body='{2}'\", method, uri, body_string);\n\n            Variant[] resultObjects = await ToSignal(req, \"request_completed\");\n\n            HttpRequest.Result result = (HttpRequest.Result)(long)resultObjects[0];\n            long response_code = (long)resultObjects[1];\n            string response_body = System.Text.Encoding.UTF8.GetString((byte[])resultObjects[3]);\n\n            req.QueueFree();\n\n            Logger?.InfoFormat(\"Received: status={0}, contents='{1}'\", response_code, response_body);\n\n            if (result == HttpRequest.Result.Success && response_code >= 200 && response_code <= 299) {\n                return response_body;\n            }\n\n            var decoded = response_body.FromJson<Dictionary<string, object>>();\n            string message = decoded.ContainsKey(\"message\") ? decoded[\"message\"].ToString() : string.Empty;\n            int grpcCode = decoded.ContainsKey(\"code\") ? (int) decoded[\"code\"] : -1;\n\n            var exception = new ApiResponseException(response_code, message, grpcCode);\n\n            if (decoded.ContainsKey(\"error\"))\n            {\n                IHttpAdapterUtil.CopyResponseError(this, decoded[\"error\"], exception);\n            }\n\n            throw exception;\n        }\n\n        private static bool IsTransientException(Exception e) {\n            return e is ApiResponseException apiException && (apiException.StatusCode >= 500 || apiException.StatusCode == -1);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs",
    "content": "// Copyright 2022 The Nakama Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nusing System;\nusing Godot;\n\nnamespace Nakama {\n\n    /// <summary>\n    /// A logger which prints to the Godot console.\n    /// </summary>\n    public class GodotLogger : ILogger {\n\n        /// <summary>\n        /// The log level.\n        /// </summary>\n        public enum LogLevel {\n            NONE,\n            ERROR,\n            WARNING,\n            INFO,\n            DEBUG,\n        }\n\n        private string module;\n        private LogLevel level;\n\n        /// <summary>\n        /// Constructs a GodotLogger.\n        /// </summary>\n        /// <param name=\"p_module\">The label to use for log entries.</param>\n        /// <param name=\"p_level\">The log level (or lower) to print to the console.</param>\n        public GodotLogger(string p_module = \"Nakama\", LogLevel p_level = LogLevel.ERROR) {\n            module = p_module;\n            level = p_level;\n        }\n\n        /// <inheritdoc cref=\"ILogger\"/>\n        public void ErrorFormat(string format, params object[] args) {\n            if (level >= LogLevel.ERROR) {\n                GD.PrintErr(\"=== \" + module + \" : ERROR === \" + String.Format(format, args));\n            }\n        }\n\n        /// <inheritdoc cref=\"ILogger\"/>\n        public void WarnFormat(string format, params object[] args) {\n            if (level >= LogLevel.WARNING) {\n                GD.Print(\"=== \" + module + \" : WARN === \" + String.Format(format, args));\n            }\n        }\n\n        /// <inheritdoc cref=\"ILogger\"/>\n        public void InfoFormat(string format, params object[] args) {\n            if (level >= LogLevel.INFO) {\n                GD.Print(\"=== \" + module + \" : INFO === \" + String.Format(format, args));\n            }\n        }\n\n        /// <inheritdoc cref=\"ILogger\"/>\n        public void DebugFormat(string format, params object[] args) {\n            if (level >= LogLevel.DEBUG) {\n                GD.Print(\"=== \" + module + \" : DEBUG === \" + String.Format(format, args));\n            }\n        }\n\n    }\n\n}"
  },
  {
    "path": "addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs",
    "content": "// Copyright 2022 The Nakama Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Godot;\n\nnamespace Nakama\n{\n    /// <summary>\n    /// An exception that is thrown when the WebSocket is unable to connect.\n    /// </summary>\n    public class GodotWebSocketConnectionException : Exception {\n        public GodotWebSocketConnectionException(string message = \"WebSocket unable to connect\")\n            : base(message) { }\n    }\n\n    /// <summary>\n    /// An exception that is thrown when the WebSocket is unable to send.\n    /// </summary>\n    public class GodotWebSocketSendException : Exception {\n        public GodotWebSocketSendException() : base(\"Unable to send over WebSocket\") { }\n    }\n\n    /// <summary>\n    /// A socket adapter which uses Godot's WebSocketPeer.\n    /// </summary>\n    public partial class GodotWebSocketAdapter : Node, ISocketAdapter\n    {\n        /// <inheritdoc cref=\"ISocketAdapter.Connected\"/>\n        public event Action Connected;\n\n        /// <inheritdoc cref=\"ISocketAdapter.Closed\"/>\n        public event Action Closed;\n\n        /// <inheritdoc cref=\"ISocketAdapter.ReceivedError\"/>\n        public event Action<Exception> ReceivedError;\n\n        /// <inheritdoc cref=\"ISocketAdapter.Received\"/>\n        public event Action<ArraySegment<byte>> Received;\n\n        /// <inheritdoc cref=\"ISocketAdapter.IsConnected\"/>\n        public new bool IsConnected\n        {\n            get\n            {\n                return ws.GetReadyState() == WebSocketPeer.State.Open;\n            }\n        }\n\n        /// <inheritdoc cref=\"ISocketAdapter.IsConnecting\"/>\n        public bool IsConnecting\n        {\n            get\n            {\n                return ws.GetReadyState() == WebSocketPeer.State.Connecting;\n            }\n        }\n\n        private WebSocketPeer ws;\n        private WebSocketPeer.State wsLastState = WebSocketPeer.State.Closed;\n\n        private TaskCompletionSource<bool> connectionSource;\n        private TaskCompletionSource<bool> closeSource;\n        private int connectionTimeout;\n        private double connectionStart;\n\n        /// <summary>\n        /// Constructs a GodotWebSocketAdapter.\n        /// </summary>\n        public GodotWebSocketAdapter()\n        {\n            ws = new WebSocketPeer();\n        }\n\n        /// <inheritdoc cref=\"ISocketAdaptor.CloseAsync\"/>\n        public Task CloseAsync()\n        {\n            if (closeSource == null)\n            {\n                closeSource = new TaskCompletionSource<bool>();\n            }\n            ws.Close();\n            return closeSource.Task;\n        }\n\n        /// <inheritdoc cref=\"ISocketAdaptor.ConnectAsync\"/>\n        public Task ConnectAsync(Uri uri, int timeout)\n        {\n            if (connectionSource != null)\n            {\n                connectionSource.SetException(new GodotWebSocketConnectionException(\"Connection attempt aborted due to new connection attempt\"));\n                connectionSource = null;\n            }\n\n            if (ws.GetReadyState() != WebSocketPeer.State.Closed)\n            {\n                return Task.FromException(new GodotWebSocketConnectionException(\"Cannot connect until current socket is closed\"));\n            }\n\n            connectionTimeout = timeout;\n            connectionStart = Time.GetUnixTimeFromSystem();\n\n            connectionSource = new TaskCompletionSource<bool>();\n\n            var err = ws.ConnectToUrl(uri.ToString());\n            if (err != Error.Ok)\n            {\n                return Task.FromException(new GodotWebSocketConnectionException(String.Format(\"Error connecting: {0}\", Enum.GetName(typeof(Error), err))));\n            }\n\n            wsLastState = WebSocketPeer.State.Closed;\n\n            return connectionSource.Task;\n        }\n\n        /// <inheritdoc cref=\"ISocketAdaptor.SendAsync\"/>\n        public Task SendAsync(ArraySegment<byte> buffer, bool reliable = true, CancellationToken canceller = default)\n        {\n            byte[] temp;\n\n            if (buffer.Offset != 0 || buffer.Count != buffer.Array.Length)\n            {\n                temp = new byte[buffer.Count];\n                Array.Copy(buffer.Array, buffer.Offset, temp, 0, buffer.Count);\n            }\n            else\n            {\n                temp = buffer.Array;\n            }\n\n            var err = ws.Send(temp, WebSocketPeer.WriteMode.Text);\n            if (err == Error.Ok)\n            {\n                return Task.CompletedTask;\n            }\n\n            return Task.FromException(new GodotWebSocketSendException());\n        }\n\n        public override void _Process(double delta)\n        {\n            if (ws.GetReadyState() != WebSocketPeer.State.Closed)\n            {\n                ws.Poll();\n            }\n\n            var state = ws.GetReadyState();\n            if (wsLastState != state)\n            {\n                wsLastState = state;\n\n                if (state == WebSocketPeer.State.Open)\n                {\n                    Connected?.Invoke();\n                    connectionSource.SetResult(true);\n                    connectionSource = null;\n                }\n                else if (state == WebSocketPeer.State.Closed)\n                {\n                    if (connectionSource != null)\n                    {\n                        Exception e = new GodotWebSocketConnectionException(\"Failed to connect\");\n                        ReceivedError?.Invoke(e);\n                        connectionSource.SetException(e);\n                        connectionSource = null;\n                    }\n                    else\n                    {\n                        Closed?.Invoke();\n                    }\n\n                    if (closeSource != null)\n                    {\n                        closeSource.SetResult(true);\n                        closeSource = null;\n                    }\n                }\n            }\n\n            if (ws.GetReadyState() == WebSocketPeer.State.Connecting) {\n                if (connectionStart + (double)connectionTimeout < Time.GetUnixTimeFromSystem())\n                {\n                    ws.Close();\n\n                    Exception e = new GodotWebSocketConnectionException(\"Connection timed out\");\n                    ReceivedError?.Invoke(e);\n                    connectionSource.SetException(e);\n                    connectionSource = null;\n                }\n            }\n\n            while (ws.GetReadyState() == WebSocketPeer.State.Open && ws.GetAvailablePacketCount() > 0)\n            {\n                Received?.Invoke(new ArraySegment<byte>(ws.GetPacket()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/socket/NakamaSocket.gd",
    "content": "extends RefCounted\n\n# A socket to interact with Nakama server.\nclass_name NakamaSocket\n\nconst ChannelType = NakamaRTMessage.ChannelJoin.ChannelType\n\n# Emitted when a socket is closed.\nsignal closed()\n\n# Emitted when a socket is connected.\nsignal connected()\n\n# Emitted when an error occurs while connecting.\nsignal connection_error(p_error)\n\n# Emitted when a chat channel message is received\nsignal received_channel_message(p_channel_message) # ApiChannelMessage\n\n# Emitted when receiving a presence change for joins and leaves with users in a chat channel.\nsignal received_channel_presence(p_channel_presence) # ChannelPresenceEvent\n\n# Emitted when an error is received from the server.\nsignal received_error(p_error) # Error\n\n# Emitted when receiving a matchmaker matched message.\nsignal received_matchmaker_matched(p_matchmaker_matched) # MatchmakerMatched\n\n# Emitted when receiving a message from a multiplayer match.\nsignal received_match_state(p_match_state) # MatchData\n\n# Emitted when receiving a presence change for joins and leaves of users in a multiplayer match.\nsignal received_match_presence(p_match_presence_event) # MatchPresenceEvent\n\n# Emitted when receiving a notification for the current user.\nsignal received_notification(p_api_notification) # ApiNotification\n\n# Emitted when receiving a presence change for when a user updated their online status.\nsignal received_status_presence(p_status_presence_event) # StatusPresenceEvent\n\n# Emitted when receiving a presence change for joins and leaves on a realtime stream.\nsignal received_stream_presence(p_stream_presence_event) # StreamPresenceEvent\n\n# Emitted when receiving a message from a realtime stream.\nsignal received_stream_state(p_stream_state) # StreamState\n\n# Received a party event. This will occur when the current user's invitation request is accepted\n# the party leader of a closed party.\nsignal received_party(p_party) # Party\n\n# Received a party close event.\nsignal received_party_close(p_party_close) # PartyClose\n\n# Received custom party data.\nsignal received_party_data(p_party_data) # PartyData\n\n# Received a request to join the party.\nsignal received_party_join_request(p_party_join_request) # PartyJoinRequest\n\n# Received a change in the party leader.\nsignal received_party_leader(p_party_leader) # PartyLeader\n\n# Received a new matchmaker ticket for the party.\nsignal received_party_matchmaker_ticket(p_party_matchmaker_ticket) # PartyMatchmakerTicket\n\n# Received a new presence event in the party.\nsignal received_party_presence(p_party_presence_event) # PartyPresenceEvent\n\nvar _adapter : NakamaSocketAdapter\nvar _free_adapter : bool = false\nvar _weak_ref : WeakRef\nvar _base_uri : String\nvar _requests : Dictionary\nvar _last_id : int = 1\nvar _conn = null\nvar logger : NakamaLogger = null\n\nclass AsyncConnection:\n\tsignal completed(result)\n\n\tfunc resume(result) -> void:\n\t\temit_signal(\"completed\", result)\n\nclass AsyncRequest:\n\tvar id : String\n\tvar type\n\tvar ns\n\tvar result_key : String\n\n\tsignal completed(result)\n\n\tfunc _init(p_id : String, p_type, p_ns, p_result_key = null):\n\t\tid = p_id\n\t\ttype = p_type\n\t\tns = p_ns\n\n\t\tif type != NakamaAsyncResult:\n\t\t\t# Specifically defined key, or default for object.\n\t\t\tresult_key = p_result_key if p_result_key != null else type.get_result_key()\n\n\tfunc resume(data, logger = null) -> void:\n\t\tvar result = _parse_result(data, logger)\n\t\temit_signal(\"completed\", result)\n\n\tfunc _parse_result(data, logger):\n\t\t# We got an exception, maybe the task was cancelled?\n\t\tif data is NakamaException:\n\t\t\treturn type.new(data as NakamaException)\n\n\t\t# Error from server\n\t\tif data.has(\"error\"):\n\t\t\tvar err = data[\"error\"]\n\t\t\tvar code = -1\n\t\t\tvar msg = str(err)\n\t\t\tif typeof(err) == TYPE_DICTIONARY:\n\t\t\t\tmsg = err.get(\"message\", \"\")\n\t\t\t\tcode = err.get(\"code\", -1)\n\t\t\tif logger:\n\t\t\t\tlogger.warning(\"Error response from server: %s\" % err)\n\t\t\treturn type.new(NakamaException.new(msg, code))\n\t\t# Simple ack response\n\t\telif type == NakamaAsyncResult:\n\t\t\treturn NakamaAsyncResult.new()\n\t\t# Missing expected result key\n\t\telif not data.has(result_key):\n\t\t\tif logger:\n\t\t\t\tlogger.warning(\"Missing expected result key: %s\" % result_key)\n\t\t\treturn type.new(NakamaException.new(\"Missing expected result key: %s\" % result_key))\n\t\t# All good, proceed with parsing\n\t\telse:\n\t\t\treturn type.create(ns, data.get(result_key))\n\nfunc _resume_conn(p_err : int):\n\tif _conn:\n\t\tif p_err: # Exception\n\t\t\tlogger.warning(\"Connection error: %d\" % p_err)\n\t\t\t_conn.resume(NakamaAsyncResult.new(NakamaException.new()))\n\t\telse:\n\t\t\tlogger.info(\"Connected!\")\n\t\t\t_conn.resume(NakamaAsyncResult.new())\n\t\t_conn = null\n\nfunc _init(p_adapter : NakamaSocketAdapter,\n\t\tp_host : String,\n\t\tp_port : int,\n\t\tp_scheme : String,\n\t\tp_free_adapter : bool = false):\n\tlogger = p_adapter.logger\n\t_adapter = p_adapter\n\t_weak_ref = weakref(_adapter)\n\tvar port = \"\"\n\tif (p_scheme == \"ws\" and p_port != 80) or (p_scheme == \"wss\" and p_port != 443):\n\t\tport = \":%d\" % p_port\n\t_base_uri = \"%s://%s%s\" % [p_scheme, p_host, port]\n\t_free_adapter = p_free_adapter\n\t_adapter.closed.connect(self._closed)\n\t_adapter.connected.connect(self._connected)\n\t_adapter.received_error.connect(self._connection_error)\n\t_adapter.received.connect(self._received)\n\nfunc _notification(what):\n\tif what == NOTIFICATION_PREDELETE:\n\t\t# Is this a bug? Why can't I call a function? self is null...\n#\t\t_clear_responses()\n#\t\t_resume_conn(ERR_FILE_EOF)\n\t\tvar keys = _requests.keys()\n\t\tfor k in keys:\n\t\t\t_requests[k].resume(NakamaException.new(\"Cancelled!\"))\n\t\tif _conn != null:\n\t\t\t_conn.resume(ERR_FILE_EOF)\n\t\t_conn = null\n\t\tif _weak_ref.get_ref() == null:\n\t\t\treturn\n\t\t_adapter.close()\n\t\tif _free_adapter:\n\t\t\t_adapter.queue_free()\n\nfunc _closed(p_error = null):\n\temit_signal(\"closed\")\n\t_resume_conn(ERR_CANT_CONNECT)\n\t_clear_requests()\n\nfunc _connection_error(p_error):\n\temit_signal(\"connection_error\", p_error)\n\t_resume_conn(p_error)\n\t_clear_requests()\n\nfunc _connected():\n\temit_signal(\"connected\")\n\t_resume_conn(OK)\n\nfunc _received(p_bytes : PackedByteArray):\n\tvar json = JSON.new()\n\tvar json_str = p_bytes.get_string_from_utf8()\n\tvar json_error := json.parse(json_str)\n\tif json_error != OK or typeof(json.get_data()) != TYPE_DICTIONARY:\n\t\tlogger.error(\"Unable to parse response: %s\" % json_str)\n\t\treturn\n\tvar dict : Dictionary = json.get_data()\n\tvar cid = dict.get(\"cid\")\n\tif cid:\n\t\tif _requests.has(cid):\n\t\t\t_resume_request(cid, dict)\n\t\telse:\n\t\t\tlogger.error(\"Invalid call id received %s\" % dict)\n\telse:\n\t\tif dict.has(\"error\"):\n\t\t\tvar res = NakamaRTAPI.Error.create(NakamaRTAPI, dict[\"error\"])\n\t\t\temit_signal(\"received_error\", res)\n\t\telif dict.has(\"channel_message\"):\n\t\t\tvar res = NakamaAPI.ApiChannelMessage.create(NakamaAPI, dict[\"channel_message\"])\n\t\t\temit_signal(\"received_channel_message\", res)\n\t\telif dict.has(\"channel_presence_event\"):\n\t\t\tvar res = NakamaRTAPI.ChannelPresenceEvent.create(NakamaRTAPI, dict[\"channel_presence_event\"])\n\t\t\temit_signal(\"received_channel_presence\", res)\n\t\telif dict.has(\"match_data\"):\n\t\t\tvar res = NakamaRTAPI.MatchData.create(NakamaRTAPI, dict[\"match_data\"])\n\t\t\temit_signal(\"received_match_state\", res)\n\t\telif dict.has(\"match_presence_event\"):\n\t\t\tvar res = NakamaRTAPI.MatchPresenceEvent.create(NakamaRTAPI, dict[\"match_presence_event\"])\n\t\t\temit_signal(\"received_match_presence\", res)\n\t\telif dict.has(\"matchmaker_matched\"):\n\t\t\tvar res = NakamaRTAPI.MatchmakerMatched.create(NakamaRTAPI, dict[\"matchmaker_matched\"])\n\t\t\temit_signal(\"received_matchmaker_matched\", res)\n\t\telif dict.has(\"notifications\"):\n\t\t\tvar res = NakamaAPI.ApiNotificationList.create(NakamaAPI, dict[\"notifications\"])\n\t\t\tfor n in res.notifications:\n\t\t\t\temit_signal(\"received_notification\", n)\n\t\telif dict.has(\"status_presence_event\"):\n\t\t\tvar res = NakamaRTAPI.StatusPresenceEvent.create(NakamaRTAPI, dict[\"status_presence_event\"])\n\t\t\temit_signal(\"received_status_presence\", res)\n\t\telif dict.has(\"stream_presence_event\"):\n\t\t\tvar res = NakamaRTAPI.StreamPresenceEvent.create(NakamaRTAPI, dict[\"stream_presence_event\"])\n\t\t\temit_signal(\"received_stream_presence\", res)\n\t\telif dict.has(\"stream_data\"):\n\t\t\tvar res = NakamaRTAPI.StreamData.create(NakamaRTAPI, dict[\"stream_data\"])\n\t\t\temit_signal(\"received_stream_state\", res)\n\t\telif dict.has(\"party\"):\n\t\t\tvar res = NakamaRTAPI.Party.create(NakamaRTAPI, dict[\"party\"])\n\t\t\temit_signal(\"received_party\", res)\n\t\telif dict.has(\"party_close\"):\n\t\t\tvar res = NakamaRTAPI.PartyClose.create(NakamaRTAPI, dict[\"party_close\"])\n\t\t\temit_signal(\"received_party_close\", res)\n\t\telif dict.has(\"party_data\"):\n\t\t\tvar res = NakamaRTAPI.PartyData.create(NakamaRTAPI, dict[\"party_data\"])\n\t\t\temit_signal(\"received_party_data\", res)\n\t\telif dict.has(\"party_join_request\"):\n\t\t\tvar res = NakamaRTAPI.PartyJoinRequest.create(NakamaRTAPI, dict[\"party_join_request\"])\n\t\t\temit_signal(\"received_party_join_request\", res)\n\t\telif dict.has(\"party_leader\"):\n\t\t\tvar res = NakamaRTAPI.PartyLeader.create(NakamaRTAPI, dict[\"party_leader\"])\n\t\t\temit_signal(\"received_party_leader\", res)\n\t\telif dict.has(\"party_matchmaker_ticket\"):\n\t\t\tvar res = NakamaRTAPI.PartyMatchmakerTicket.create(NakamaRTAPI, dict[\"party_matchmaker_ticket\"])\n\t\t\temit_signal(\"received_party_matchmaker_ticket\", res)\n\t\telif dict.has(\"party_presence_event\"):\n\t\t\tvar res = NakamaRTAPI.PartyPresenceEvent.create(NakamaRTAPI, dict[\"party_presence_event\"])\n\t\t\temit_signal(\"received_party_presence\", res)\n\t\telse:\n\t\t\tlogger.warning(\"Unhandled response: %s\" % dict)\n\nfunc _resume_request(p_id : String, p_data):\n\tif _requests.has(p_id):\n\t\tlogger.debug(\"Resuming request: %s: %s\" % [p_id, p_data])\n\t\t_requests[p_id].resume(p_data, logger)\n\t\t_requests.erase(p_id)\n\telse:\n\t\tlogger.warning(\"Trying to resume missing request: %s: %s\" % [p_id, p_data])\n\nfunc _cancel_request(p_id : String):\n\tlogger.debug(\"Cancelling request: %s\" % [p_id])\n\t_resume_request(p_id, NakamaException.new(\"Request cancelled.\"))\n\nfunc _clear_requests():\n\tvar ids = _requests.keys()\n\tfor id in ids:\n\t\t_cancel_request(id)\n\nfunc _send_async(p_message, p_parse_type = NakamaAsyncResult, p_ns = NakamaRTAPI, p_msg_key = null, p_result_key = null) -> AsyncRequest:\n\tlogger.debug(\"Sending async request: %s\" % p_message)\n\t# For messages coming from the API which does not have a key defined, so we can override it\n\tvar msg = p_msg_key\n\t# For regular RT messages\n\tif msg == null:\n\t\tmsg = p_message.get_msg_key()\n\tvar id = str(_last_id)\n\t_last_id += 1\n\n\t_requests[id] = AsyncRequest.new(id, p_parse_type, p_ns, p_result_key)\n\n\tvar json := JSON.stringify({\n\t\t\"cid\": id,\n\t\tmsg: p_message.serialize()\n\t})\n\tvar err = _adapter.send(json.to_utf8_buffer())\n\tif err != OK:\n\t\tcall_deferred(\"_cancel_request\", id)\n\treturn _requests[id]\n\n# If the socket is connected.\nfunc is_connected_to_host():\n\treturn _adapter.is_connected_to_host()\n\n# If the socket is connecting.\nfunc is_connecting_to_host():\n\treturn _adapter.is_connecting_to_host()\n\n# Close the socket connection to the server.\nfunc close():\n\t_adapter.close()\n\n# Connect to the server.\n# @param p_session - The session of the user.\n# @param p_appear_online - If the user who appear online to other users.\n# @param p_connect_timeout - The time allowed for the socket connection to be established.\n# Returns a task to represent the asynchronous operation.\nfunc connect_async(p_session : NakamaSession, p_appear_online : bool = false, p_connect_timeout : int = 3):\n\tvar uri = \"%s/ws?lang=en&status=%s&token=%s\" % [_base_uri, str(p_appear_online).to_lower(), p_session.token]\n\tlogger.debug(\"Connecting to host: %s\" % uri)\n\t_conn = AsyncConnection.new()\n\t_adapter.connect_to_host(uri, p_connect_timeout)\n\treturn await _conn.completed\n\n# Join the matchmaker pool and search for opponents on the server.\n# @param p_query - The matchmaker query to search for opponents.\n# @param p_min_count - The minimum number of players to compete against in a match.\n# @param p_max_count - The maximum number of players to compete against in a match.\n# @param p_string_properties - A set of key/value properties to provide to searches.\n# @param p_numeric_properties - A set of key/value numeric properties to provide to searches.\n# @param p_count_multiple - Optional multiple of the count that must be satisfied.\n# Returns a task which resolves to a matchmaker ticket object.\nfunc add_matchmaker_async(p_query : String = \"*\", p_min_count : int = 2, p_max_count : int = 8,\n\t\tp_string_props : Dictionary = {}, p_numeric_props : Dictionary = {},\n\t\tp_count_multiple : int = 0) -> NakamaRTAPI.MatchmakerTicket:\n\treturn await _send_async(\n\t\tNakamaRTMessage.MatchmakerAdd.new(p_query, p_min_count, p_max_count, p_string_props, p_numeric_props, p_count_multiple),\n\t\tNakamaRTAPI.MatchmakerTicket\n\t).completed\n\n# Create a multiplayer match on the server.\n# @param p_name - Optional name to use when creating the match.\n# Returns a task to represent the asynchronous operation.\nfunc create_match_async(p_name : String = ''):\n\treturn await _send_async(NakamaRTMessage.MatchCreate.new(p_name), NakamaRTAPI.Match).completed\n\n# Subscribe to one or more users for their status updates.\n# @param p_user_ids - The IDs of users.\n# @param p_usernames - The usernames of the users.\n# Returns a task which resolves to the current statuses for the users.\nfunc follow_users_async(p_ids : PackedStringArray, p_usernames : PackedStringArray) -> NakamaRTAPI.Status:\n\treturn await _send_async(NakamaRTMessage.StatusFollow.new(p_ids, p_usernames), NakamaRTAPI.Status).completed\n\n# Join a chat channel on the server.\n# @param p_target - The target channel to join.\n# @param p_type - The type of channel to join.\n# @param p_persistence - If chat messages should be stored.\n# @param p_hidden - If the current user should be hidden on the channel.\n# Returns a task which resolves to a chat channel object.\nfunc join_chat_async(p_target : String, p_type : int, p_persistence : bool = false, p_hidden : bool = false) -> NakamaRTAPI.Channel:\n\treturn await _send_async(\n\t\tNakamaRTMessage.ChannelJoin.new(p_target, p_type, p_persistence, p_hidden),\n\t\tNakamaRTAPI.Channel\n\t).completed\n\n# Join a multiplayer match with the matchmaker matched object.\n# @param p_matched - A matchmaker matched object.\n# Returns a task which resolves to a multiplayer match.\nfunc join_matched_async(p_matched):\n\tvar msg := NakamaRTMessage.MatchJoin.new()\n\tif p_matched.match_id:\n\t\tmsg.match_id = p_matched.match_id\n\telse:\n\t\tmsg.token = p_matched.token\n\treturn await _send_async(msg, NakamaRTAPI.Match).completed\n\n# Join a multiplayer match by ID.\n# @param p_match_id - The ID of the match to attempt to join.\n# @param p_metadata - An optional set of key-value metadata pairs to be passed to the match handler.\n# Returns a task which resolves to a multiplayer match.\nfunc join_match_async(p_match_id : String, p_metadata = null):\n\tvar msg := NakamaRTMessage.MatchJoin.new()\n\tmsg.match_id = p_match_id\n\tmsg.metadata = p_metadata\n\treturn await _send_async(msg, NakamaRTAPI.Match).completed\n\n# Leave a chat channel on the server.\n## @param p_channel_id - The ID of the chat channel to leave.\n# Returns a task which represents the asynchronous operation.\nfunc leave_chat_async(p_channel_id : String) -> NakamaAsyncResult:\n\treturn await _send_async(NakamaRTMessage.ChannelLeave.new(p_channel_id)).completed\n\n# Leave a multiplayer match on the server.\n# @param p_match_id - The multiplayer match to leave.\n# Returns a task which represents the asynchronous operation.\nfunc leave_match_async(p_match_id : String) -> NakamaAsyncResult:\n\treturn await _send_async(NakamaRTMessage.MatchLeave.new(p_match_id)).completed\n\n# Remove a chat message from a chat channel on the server.\n# @param p_channel - The chat channel with the message to remove.\n# @param p_message_id - The ID of the chat message to remove.\n# Returns a task which resolves to an acknowledgement of the removed message.\nfunc remove_chat_message_async(p_channel_id : String, p_message_id : String):\n\treturn await _send_async(\n\t\tNakamaRTMessage.ChannelMessageRemove.new(p_channel_id, p_message_id),\n\t\tNakamaRTAPI.ChannelMessageAck\n\t).completed\n\n# Leave the matchmaker pool with the ticket.\n# @param p_ticket - The ticket returned by the matchmaker on join.\n# Returns a task which represents the asynchronous operation.\nfunc remove_matchmaker_async(p_ticket : String) -> NakamaAsyncResult:\n\treturn await _send_async(NakamaRTMessage.MatchmakerRemove.new(p_ticket)).completed\n\n# Execute an RPC function to the server.\n# @param p_func_id - The ID of the function to execute.\n# @param p_payload - An (optional) String payload to send to the server.\n# Returns a task which resolves to the RPC function response object.\nfunc rpc_async(p_func_id : String, p_payload = null) -> NakamaAPI.ApiRpc:\n\tvar payload = p_payload\n\tmatch typeof(p_payload):\n\t\tTYPE_NIL, TYPE_STRING:\n\t\t\tpass\n\t\t_:\n\t\t\tpayload = JSON.stringify(p_payload)\n\treturn await _send_async(NakamaAPI.ApiRpc.create(NakamaAPI, {\n\t\t\"id\": p_func_id,\n\t\t\"payload\": payload\n\t}), NakamaAPI.ApiRpc, NakamaAPI, \"rpc\", \"rpc\").completed\n\n# Send input to a multiplayer match on the server.\n# When no presences are supplied the new match state will be sent to all presences.\n# @param p_match_id - The ID of the match.\n# @param p_op_code - An operation code for the input.\n# @param p_data - The input data to send.\n# @param p_presences - The presences in the match who should receive the input.\n# Returns a task which represents the asynchronous operation.\nfunc send_match_state_async(p_match_id, p_op_code : int, p_data : String, p_presences = null):\n\tvar req = _send_async(NakamaRTMessage.MatchDataSend.new(\n\t\tp_match_id,\n\t\tp_op_code,\n\t\tMarshalls.utf8_to_base64(p_data),\n\t\tp_presences\n\t))\n\t# This do not return a response from server, you don't really need to wait for it.\n\treq.call_deferred(\"resume\", {})\n\treturn req.completed\n\n# Send input to a multiplayer match on the server.\n# When no presences are supplied the new match state will be sent to all presences.\n# @param p_match_id - The ID of the match.\n# @param p_op_code - An operation code for the input.\n# @param p_data - The input data to send.\n# @param p_presences - The presences in the match who should receive the input.\n# Returns a task which represents the asynchronous operation.\nfunc send_match_state_raw_async(p_match_id, p_op_code : int, p_data : PackedByteArray, p_presences = null):\n\tvar req = _send_async(NakamaRTMessage.MatchDataSend.new(\n\t\tp_match_id,\n\t\tp_op_code,\n\t\tMarshalls.raw_to_base64(p_data),\n\t\tp_presences\n\t))\n\t# This do not return a response from server, you don't really need to wait for it.\n\treq.call_deferred(\"resume\", {})\n\treturn req.completed\n\n# Unfollow one or more users from their status updates.\n# @param p_user_ids - An array of user ids to unfollow.\n# Returns a task which represents the asynchronous operation.\nfunc unfollow_users_async(p_ids : PackedStringArray):\n\treturn await _send_async(NakamaRTMessage.StatusUnfollow.new(p_ids)).completed\n\n# Update a chat message on a chat channel in the server.\n# @param p_channel_id - The ID of the chat channel with the message to update.\n# @param p_message_id - The ID of the message to update.\n# @param p_content - The new contents of the chat message.\n# Returns a task which resolves to an acknowledgement of the updated message.\nfunc update_chat_message_async(p_channel_id : String, p_message_id : String, p_content : Dictionary):\n\treturn await _send_async(\n\t\tNakamaRTMessage.ChannelMessageUpdate.new(p_channel_id, p_message_id, JSON.stringify(p_content)),\n\t\tNakamaRTAPI.ChannelMessageAck\n\t).completed\n\n# Update the status for the current user online.\n# @param p_status - The new status for the user.\n# Returns a task which represents the asynchronous operation.\nfunc update_status_async(p_status : String):\n\treturn await _send_async(NakamaRTMessage.StatusUpdate.new(p_status)).completed\n\n# Send a chat message to a chat channel on the server.\n# @param p_channel_id - The ID of the chat channel to send onto.\n# @param p_content - The contents of the message to send.\n# Returns a task which resolves to the acknowledgement of the chat message write.\nfunc write_chat_message_async(p_channel_id : String, p_content : Dictionary):\n\treturn await _send_async(\n\t\tNakamaRTMessage.ChannelMessageSend.new(p_channel_id, JSON.stringify(p_content)),\n\t\tNakamaRTAPI.ChannelMessageAck\n\t).completed\n\n# Accept a party member's request to join the party.\n# @param p_party_id - The party ID to accept the join request for.\n# @param p_presence - The presence to accept as a party member.\n# Returns a task to represent the asynchronous operation.\nfunc accept_party_member_async(p_party_id : String, p_presence : NakamaRTAPI.UserPresence):\n\treturn await _send_async(NakamaRTMessage.PartyAccept.new(p_party_id, p_presence)).completed\n\n# Begin matchmaking as a party.\n# @param p_party_id - Party ID.\n# @param p_query - Filter query used to identify suitable users.\n# @param p_min_count - Minimum total user count to match together.\n# @param p_max_count - Maximum total user count to match together.\n# @param p_string_properties - String properties.\n# @param p_numeric_properties - Numeric properties.\n# @param p_count_multiple - Optional multiple of the count that must be satisfied.\n# Returns a task to represent the asynchronous operation.\nfunc add_matchmaker_party_async(p_party_id : String, p_query : String = \"*\", p_min_count : int = 2,\n\tp_max_count : int = 8, p_string_properties = {}, p_numeric_properties = {}, p_count_multiple : int = 0):\n\treturn await _send_async(\n\t\tNakamaRTMessage.PartyMatchmakerAdd.new(p_party_id, p_min_count,\n\t\t\tp_max_count, p_query, p_string_properties, p_numeric_properties,\n\t\t\tp_count_multiple if p_count_multiple > 0 else null),\n\t\tNakamaRTAPI.PartyMatchmakerTicket).completed\n\n# End a party, kicking all party members and closing it.\n# @param p_party_id - The ID of the party.\n# Returns a task to represent the asynchronous operation.\nfunc close_party_async(p_party_id : String):\n\tvar msg := NakamaRTAPI.PartyClose.new()\n\tmsg.party_id = p_party_id\n\treturn await _send_async(msg).completed\n\n# Create a party.\n# @param p_open - Whether or not the party will require join requests to be approved by the party leader.\n# @param p_max_size - Maximum number of party members. This maximum does not include the party leader.\n# Returns a task to represent the asynchronous operation.\nfunc create_party_async(p_open : bool, p_max_size : int) -> NakamaRTAPI.Party:\n\treturn await _send_async(\n\t\tNakamaRTMessage.PartyCreate.new(p_open, p_max_size),\n\t\tNakamaRTAPI.Party\n\t).completed\n\n# Join a party.\n# @param p_party_id - Party ID.\n# Returns a task to represent the asynchronous operation.\nfunc join_party_async(p_party_id : String):\n\treturn await _send_async(NakamaRTMessage.PartyJoin.new(p_party_id)).completed\n\n# Leave the party.\n# @param p_party_id - Party ID.\n# Returns a task to represent the asynchronous operation.\nfunc leave_party_async(p_party_id : String):\n\treturn await _send_async(NakamaRTMessage.PartyLeave.new(p_party_id)).completed\n\n# Request a list of pending join requests for a party.\n# @param p_party_id - Party ID.\n# Returns a task which resolves to a list of all party join requests.\nfunc list_party_join_requests_async(p_party_id : String) -> NakamaRTAPI.PartyJoinRequest:\n\treturn await _send_async(\n\t\tNakamaRTMessage.PartyJoinRequestList.new(p_party_id),\n\t\tNakamaRTAPI.PartyJoinRequest).completed\n\n# Promote a new party leader.\n# @param p_party_id - Party ID.\n# @param p_party_member - The presence of an existing party member to promote as the new leader.\n# Returns a which represents the asynchronous operation.\nfunc promote_party_member(p_party_id : String, p_party_member : NakamaRTAPI.UserPresence):\n\treturn await _send_async(NakamaRTMessage.PartyPromote.new(p_party_id, p_party_member)).completed\n\n# Cancel a party matchmaking process using a ticket.\n# @param p_party_id - Party ID.\n# @param p_ticket - The ticket to cancel.\n# Returns a task which represents the asynchronous operation.\nfunc remove_matchmaker_party_async(p_party_id : String, p_ticket : String):\n\treturn await _send_async(NakamaRTMessage.PartyMatchmakerRemove.new(p_party_id, p_ticket)).completed\n\n# Kick a party member, or decline a request to join.\n# @param p_party_id - Party ID to remove/reject from.\n# @param p_presence - The presence to remove or reject.\n# Returns a task which represents the asynchronous operation.\nfunc remove_party_member_async(p_party_id : String, p_presence : NakamaRTAPI.UserPresence):\n\treturn await _send_async(NakamaRTMessage.PartyRemove.new(p_party_id, p_presence)).completed\n\n# Send data to a party.\n# @param p_party_id - Party ID to send to.\n# @param p_op_code - Op code value.\n# @param data - Data payload, if any.\n# Returns a task which represents the asynchronous operation.\nfunc send_party_data_async(p_party_id : String, p_op_code : int, p_data:String = \"\"):\n\tvar base64_data = null if p_data.is_empty() else Marshalls.utf8_to_base64(p_data)\n\treturn await _send_async(NakamaRTMessage.PartyDataSend.new(p_party_id, p_op_code, base64_data)).completed\n\n# Send data to a party.\n# @param p_party_id - Party ID to send to.\n# @param p_op_code - Op code value.\n# @param data - Data payload, if any.\n# Returns a task which represents the asynchronous operation.\nfunc send_party_data_raw_async(p_party_id : String, p_op_code : int, p_data:PackedByteArray):\n\tvar base64_data = null if p_data.is_empty() else Marshalls.raw_to_base64(p_data)\n\treturn await _send_async(NakamaRTMessage.PartyDataSend.new(p_party_id, p_op_code, base64_data)).completed\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/socket/NakamaSocketAdapter.gd",
    "content": "@tool\nextends Node\n\n# An adapter which implements a socket with a protocol supported by Nakama.\nclass_name NakamaSocketAdapter\n\nvar _ws := WebSocketPeer.new()\nvar _ws_last_state := WebSocketPeer.STATE_CLOSED\nvar _timeout : int = 30\nvar _start : int = 0\nvar logger = NakamaLogger.new()\n\n# A signal emitted when the socket is connected.\nsignal connected()\n\n# A signal emitted when the socket is disconnected.\nsignal closed()\n\n# A signal emitted when the socket has an error when connecting.\nsignal received_error(p_exception)\n\n# A signal emitted when the socket receives a message.\nsignal received(p_bytes) # PackedByteArray\n\n# If the socket is connected.\nfunc is_connected_to_host():\n\treturn _ws.get_ready_state() == WebSocketPeer.STATE_OPEN\n\n# If the socket is connecting.\nfunc is_connecting_to_host():\n\treturn _ws.get_ready_state() == WebSocketPeer.STATE_CONNECTING\n\n# Close the socket with an asynchronous operation.\nfunc close():\n\t_ws.close()\n\n# Connect to the server with an asynchronous operation.\n# @param p_uri - The URI of the server.\n# @param p_timeout - The timeout for the connect attempt on the socket.\nfunc connect_to_host(p_uri : String, p_timeout : int):\n\t_timeout = p_timeout\n\t_start = Time.get_unix_time_from_system()\n\tvar err = _ws.connect_to_url(p_uri)\n\tif err != OK:\n\t\tlogger.debug(\"Error connecting to host %s\" % p_uri)\n\t\tcall_deferred(\"emit_signal\", \"received_error\", err)\n\t\treturn\n\t_ws_last_state = WebSocketPeer.STATE_CLOSED\n\n# Send data to the server with an asynchronous operation.\n# @param p_buffer - The buffer with the message to send.\n# @param p_reliable - If the message should be sent reliably (will be ignored by some protocols).\nfunc send(p_buffer : PackedByteArray, p_reliable : bool = true) -> int:\n\treturn _ws.send(p_buffer, WebSocketPeer.WRITE_MODE_TEXT)\n\nfunc _process(delta):\n\tif _ws.get_ready_state() != WebSocketPeer.STATE_CLOSED:\n\t\t_ws.poll()\n\n\tvar state = _ws.get_ready_state()\n\tif _ws_last_state != state:\n\t\t_ws_last_state = state\n\t\tif state == WebSocketPeer.STATE_OPEN:\n\t\t\tconnected.emit()\n\t\telif state == WebSocketPeer.STATE_CLOSED:\n\t\t\tclosed.emit()\n\n\tif state == WebSocketPeer.STATE_CONNECTING:\n\t\tif _start + _timeout < Time.get_unix_time_from_system():\n\t\t\tlogger.debug(\"Timeout when connecting to socket\")\n\t\t\treceived_error.emit(ERR_TIMEOUT)\n\t\t\t_ws.close()\n\n\twhile _ws.get_ready_state() == WebSocketPeer.STATE_OPEN and _ws.get_available_packet_count():\n\t\treceived.emit(_ws.get_packet())\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd",
    "content": "extends RefCounted\nclass_name NakamaAsyncResult\n\nvar exception : NakamaException:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn get_exception()\n\nvar _ex = null\n\nfunc _init(p_ex = null):\n\t_ex = p_ex\n\nfunc is_exception():\n\treturn get_exception() != null\n\nfunc was_cancelled():\n\treturn is_exception() and get_exception().cancelled\n\nfunc get_exception() -> NakamaException:\n\treturn _ex as NakamaException\n\nfunc _to_string():\n\tif is_exception():\n\t\treturn get_exception()._to_string()\n\treturn \"NakamaAsyncResult<>\"\n\nstatic func _safe_ret(p_obj, p_type : GDScript):\n\tif is_instance_of(p_obj, p_type):\n\t\treturn p_obj # Correct type\n\telif p_obj is NakamaException:\n\t\treturn p_type.new(p_obj) # It's an exception. Incapsulate it\n\treturn p_type.new(NakamaException.new()) # It's something else. generate an exception\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/utils/NakamaException.gd",
    "content": "extends RefCounted\n\n# An exception generated during a request.\n# Usually contains at least an error message.\nclass_name NakamaException\n\nvar _status_code : int = -1\nvar status_code : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _status_code\n\nvar _grpc_status_code : int = -1\nvar grpc_status_code : int:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _grpc_status_code\n\nvar _message : String = \"\"\nvar message : String:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _message\n\nvar _cancelled : bool = false\nvar cancelled : bool:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn _cancelled\n\nfunc _init(p_message : String = \"\", p_status_code : int = -1, p_grpc_status_code : int = -1, p_cancelled : bool = false):\n\t_status_code = p_status_code\n\t_grpc_status_code = p_grpc_status_code\n\t_message = p_message\n\t_cancelled = p_cancelled\n\nfunc _to_string() -> String:\n\treturn \"NakamaException(StatusCode={%s}, Message='{%s}', GrpcStatusCode={%s})\" % [_status_code, _message, _grpc_status_code]\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/utils/NakamaLogger.gd",
    "content": "extends RefCounted\nclass_name NakamaLogger\n\nenum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}\n\nvar _level = LOG_LEVEL.ERROR\nvar _module = \"Nakama\"\n\nfunc _init(p_module : String = \"Nakama\", p_level : int = LOG_LEVEL.ERROR):\n\t_level = p_level\n\t_module = p_module\n\nfunc _log(level : int, msg):\n\tif level <= _level:\n\t\tif level == LOG_LEVEL.ERROR:\n\t\t\tprinterr(\"=== %s : ERROR === %s\" % [_module, str(msg)])\n\t\telse:\n\t\t\tvar what = \"=== UNKNOWN === \"\n\t\t\tfor k in LOG_LEVEL:\n\t\t\t\tif level == LOG_LEVEL[k]:\n\t\t\t\t\twhat = \"=== %s : %s === \" % [_module, k]\n\t\t\t\t\tbreak\n\t\t\tprint(what + str(msg))\n\nfunc error(msg):\n\t_log(LOG_LEVEL.ERROR, msg)\n\nfunc warning(msg):\n\t_log(LOG_LEVEL.WARNING, msg)\n\nfunc info(msg):\n\t_log(LOG_LEVEL.INFO, msg)\n\nfunc verbose(msg):\n\t_log(LOG_LEVEL.VERBOSE, msg)\n\nfunc debug(msg):\n\t_log(LOG_LEVEL.DEBUG, msg)\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/utils/NakamaMultiplayerBridge.gd",
    "content": "extends RefCounted\nclass_name NakamaMultiplayerBridge\n\nenum MatchState {\n\tDISCONNECTED,\n\tJOINING,\n\tCONNECTED,\n\tSOCKET_CLOSED,\n}\n\nenum MetaMessageType {\n\tCLAIM_HOST,\n\tASSIGN_PEER_ID,\n}\n\n# Read-only variables.\nvar _nakama_socket: NakamaSocket\nvar nakama_socket: NakamaSocket:\n\tget: return _nakama_socket\n\tset(_v): pass\nvar _match_state: int = MatchState.DISCONNECTED\nvar match_state: int:\n\tget: return _match_state\n\tset(_v): pass\nvar _match_id := ''\nvar match_id: String:\n\tget: return _match_id\n\tset(_v): pass\nvar _multiplayer_peer: NakamaMultiplayerPeer = NakamaMultiplayerPeer.new()\nvar multiplayer_peer: NakamaMultiplayerPeer:\n\tget: return _multiplayer_peer\n\tset(_v): pass\n\n# Configuration that can be set by the developer.\nvar meta_op_code: int = 9001\nvar rpc_op_code: int = 9002\n\n# Internal variables.\nvar _my_session_id: String\nvar _my_peer_id: int = 0\nvar _id_map := {}\nvar _users := {}\nvar _matchmaker_ticket := ''\n\nclass User extends RefCounted:\n\tvar presence\n\tvar peer_id: int = 0\n\n\tfunc _init(p_presence) -> void:\n\t\tpresence = p_presence\n\nsignal match_join_error (exception)\nsignal match_joined ()\n\nfunc _set_readonly(_value) -> void:\n\tpass\n\nfunc _init(p_nakama_socket: NakamaSocket) -> void:\n\t_nakama_socket = p_nakama_socket\n\t_nakama_socket.received_match_presence.connect(self._on_nakama_socket_received_match_presence)\n\t_nakama_socket.received_matchmaker_matched.connect(self._on_nakama_socket_received_matchmaker_matched)\n\t_nakama_socket.received_match_state.connect(self._on_nakama_socket_received_match_state)\n\t_nakama_socket.closed.connect(self._on_nakama_socket_closed)\n\n\t_multiplayer_peer.packet_generated.connect(self._on_multiplayer_peer_packet_generated)\n\t_multiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_CONNECTING)\n\nfunc create_match() -> void:\n\tif _match_state != MatchState.DISCONNECTED:\n\t\tpush_error(\"Cannot create match when state is %s\" % MatchState.keys()[_match_state])\n\t\treturn\n\n\t_match_state = MatchState.JOINING\n\tmultiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_CONNECTING)\n\n\tvar res = await _nakama_socket.create_match_async()\n\tif res.is_exception():\n\t\tmatch_join_error.emit(res.get_exception())\n\t\tleave()\n\t\treturn\n\n\t_setup_match(res)\n\t_setup_host()\n\nfunc join_match(p_match_id: String) -> void:\n\tif _match_state != MatchState.DISCONNECTED:\n\t\tpush_error(\"Cannot join match when state is %s\" % MatchState.keys()[_match_state])\n\t\treturn\n\n\t_match_state = MatchState.JOINING\n\tmultiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_CONNECTING)\n\n\tvar res = await _nakama_socket.join_match_async(p_match_id)\n\tif res.is_exception():\n\t\tmatch_join_error.emit(res.get_exception())\n\t\tleave()\n\t\treturn\n\n\t_setup_match(res)\n\nfunc join_named_match(_match_name: String) -> void:\n\tif _match_state != MatchState.DISCONNECTED:\n\t\tpush_error(\"Cannot join match when state is %s\" % MatchState.keys()[_match_state])\n\t\treturn\n\n\t_match_state = MatchState.JOINING\n\tmultiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_CONNECTING)\n\n\tvar res = await _nakama_socket.create_match_async(_match_name)\n\tif res.is_exception():\n\t\tmatch_join_error.emit(res.get_exception())\n\t\tleave()\n\t\treturn\n\n\t_setup_match(res)\n\tif res.size == 0 or (res.size == 1 and res.presences.size() == 0):\n\t\t_setup_host()\n\nfunc start_matchmaking(ticket) -> void:\n\tif _match_state != MatchState.DISCONNECTED:\n\t\tpush_error(\"Cannot start matchmaking when state is %s\" % MatchState.keys()[_match_state])\n\t\treturn\n\tif ticket.is_exception():\n\t\tpush_error(\"Ticket with exception passed into start_matchmaking()\")\n\t\treturn\n\n\t_match_state = MatchState.JOINING\n\tmultiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_CONNECTING)\n\n\t_matchmaker_ticket = ticket.ticket\n\nfunc _on_nakama_socket_received_matchmaker_matched(matchmaker_matched) -> void:\n\tif _matchmaker_ticket != matchmaker_matched.ticket:\n\t\treturn\n\n\t# Get a list of sorted session ids.\n\tvar session_ids := []\n\tfor matchmaker_user in matchmaker_matched.users:\n\t\tsession_ids.append(matchmaker_user.presence.session_id)\n\tsession_ids.sort()\n\n\tvar res = await _nakama_socket.join_matched_async(matchmaker_matched)\n\tif res.is_exception():\n\t\tmatch_join_error.emit(res.get_exception())\n\t\tleave()\n\t\treturn\n\n\t_setup_match(res)\n\n\t# If our session is the first alphabetically, then we'll be the host.\n\tif _my_session_id == session_ids[0]:\n\t\t_setup_host()\n\n\t\t# Add all of the existing peers.\n\t\tfor presence in res.presences:\n\t\t\tif presence.session_id != _my_session_id:\n\t\t\t\t_host_add_peer(presence)\n\nfunc _on_nakama_socket_closed() -> void:\n\tmatch_state = MatchState.SOCKET_CLOSED\n\t_cleanup()\n\nfunc get_user_presence_for_peer(peer_id: int) -> NakamaRTAPI.UserPresence:\n\tvar session_id = _id_map.get(peer_id)\n\tif session_id == null:\n\t\treturn null\n\tvar user = _users.get(session_id)\n\tif user == null:\n\t\treturn null\n\treturn user.presence\n\nfunc leave() -> void:\n\tif _match_state == MatchState.DISCONNECTED:\n\t\treturn\n\t_match_state = MatchState.DISCONNECTED\n\n\tif _match_id:\n\t\tawait _nakama_socket.leave_match_async(_match_id)\n\tif _matchmaker_ticket:\n\t\tawait _nakama_socket.remove_matchmaker_async(_matchmaker_ticket)\n\n\t_cleanup()\n\nfunc _cleanup() -> void:\n\tfor peer_id in _id_map:\n\t\tmultiplayer_peer.peer_disconnected.emit(peer_id)\n\n\t_match_id = ''\n\t_matchmaker_ticket = ''\n\t_my_session_id = ''\n\t_my_peer_id = 0\n\t_id_map.clear()\n\t_users.clear()\n\n\t_multiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_DISCONNECTED)\n\nfunc _setup_match(res) -> void:\n\t_match_id = res.match_id\n\t_my_session_id = res.self_user.session_id\n\n\t_users[_my_session_id] = User.new(res.self_user)\n\n\tfor presence in res.presences:\n\t\tif not _users.has(presence.session_id):\n\t\t\t_users[presence.session_id] = User.new(presence)\n\nfunc _setup_host() -> void:\n\t# Claim id 1 and start the match.\n\t_my_peer_id = 1\n\t_map_id_to_session(1, _my_session_id)\n\t_match_state = MatchState.CONNECTED\n\t_multiplayer_peer.initialize(_my_peer_id)\n\tmatch_joined.emit()\n\nfunc _generate_id(session_id: String) -> int:\n\t# Peer ids can only be positive 32-bit signed integers.\n\tvar peer_id: int = session_id.hash() & 0x7FFFFFFF\n\n\t# If this peer id is already taken, try to find another.\n\twhile peer_id <= 1 or _id_map.has(peer_id):\n\t\tpeer_id += 1\n\t\tif peer_id > 0x7FFFFFFF or peer_id <= 0:\n\t\t\tpeer_id = randi() & 0x7FFFFFFF\n\n\treturn peer_id\n\nfunc _map_id_to_session(peer_id: int, session_id: String) -> void:\n\t_id_map[peer_id] = session_id\n\t_users[session_id].peer_id = peer_id\n\nfunc _host_add_peer(presence) -> void:\n\tvar peer_id = _generate_id(presence.session_id)\n\t_map_id_to_session(peer_id, presence.session_id)\n\n\t# Tell them we are the host.\n\t_nakama_socket.send_match_state_async(_match_id, meta_op_code, JSON.stringify({\n\t\ttype = MetaMessageType.CLAIM_HOST,\n\t}), [presence])\n\n\t# Tell them about all the other connected peers.\n\tfor other_peer_id in _id_map:\n\t\tvar other_session_id = _id_map[other_peer_id]\n\t\tif other_session_id == presence.session_id or other_session_id == _my_session_id:\n\t\t\tcontinue\n\t\t_nakama_socket.send_match_state_async(_match_id, meta_op_code, JSON.stringify({\n\t\t\ttype = MetaMessageType.ASSIGN_PEER_ID,\n\t\t\tsession_id = other_session_id,\n\t\t\tpeer_id = other_peer_id,\n\t\t}), [presence])\n\n\t# Assign them a peer_id (tell everyone about it).\n\t_nakama_socket.send_match_state_async(_match_id, meta_op_code, JSON.stringify({\n\t\ttype = MetaMessageType.ASSIGN_PEER_ID,\n\t\tsession_id = presence.session_id,\n\t\tpeer_id = peer_id,\n\t}))\n\n\t_multiplayer_peer.peer_connected.emit(peer_id)\n\nfunc _on_nakama_socket_received_match_presence(event) -> void:\n\tif _match_state == MatchState.DISCONNECTED:\n\t\treturn\n\tif event.match_id != _match_id:\n\t\treturn\n\n\tfor presence in event.joins:\n\t\tif not _users.has(presence.session_id):\n\t\t\t_users[presence.session_id] = User.new(presence)\n\n\t\t# If we are the host, and they don't yet have a peer id, then let's\n\t\t# generate a new id for them and send all the necessary messages.\n\t\tif _my_peer_id == 1 and _users[presence.session_id].peer_id == 0:\n\t\t\t_host_add_peer(presence)\n\n\tfor presence in event.leaves:\n\t\tif not _users.has(presence.session_id):\n\t\t\tcontinue\n\n\t\tvar peer_id = _users[presence.session_id].peer_id\n\n\t\t_multiplayer_peer.peer_disconnected.emit(peer_id)\n\n\t\t_users.erase(presence.session_id)\n\t\t_id_map.erase(peer_id)\n\nfunc _parse_json(data: String):\n\tvar json = JSON.new()\n\tif json.parse(data) != OK:\n\t\treturn null\n\tvar content = json.get_data()\n\tif not content is Dictionary:\n\t\treturn null\n\treturn content\n\nfunc _on_nakama_socket_received_match_state(data) -> void:\n\tif _match_state == MatchState.DISCONNECTED:\n\t\treturn\n\tif data.match_id != _match_id:\n\t\treturn\n\n\tif data.op_code == meta_op_code:\n\t\tvar content = _parse_json(data.data)\n\t\tif content == null:\n\t\t\treturn\n\t\tvar type = content['type']\n\t\t#print (\"RECEIVED: \", content)\n\n\t\tif type == MetaMessageType.CLAIM_HOST:\n\t\t\tif _id_map.has(1):\n\t\t\t\t# @todo Can we mediate this dispute?\n\t\t\t\tpush_error(\"User %s claiming to be host, when user %s has already claimed it\" % [data.presence.session_id, _id_map[1]])\n\t\t\telse:\n\t\t\t\t_map_id_to_session(1, data.presence.session_id)\n\t\t\treturn\n\n\t\t# Ensure that any meta messages are coming from the host!\n\t\tif data.presence.session_id != _id_map[1]:\n\t\t\tpush_error(\"Received meta message from user %s who isn't the host: %s\" % [data.presence.session_id, content])\n\t\t\treturn\n\n\t\tif type == MetaMessageType.ASSIGN_PEER_ID:\n\t\t\tvar session_id = content['session_id']\n\t\t\tvar peer_id = content['peer_id']\n\n\t\t\tif _users.has(session_id) and _users[session_id].peer_id != 0:\n\t\t\t\tpush_error(\"Attempting to assign peer id %s to %s which already has id %s\" % [\n\t\t\t\t\tpeer_id,\n\t\t\t\t\tsession_id,\n\t\t\t\t\t_users[session_id].peer_id,\n\t\t\t\t])\n\t\t\t\treturn\n\n\t\t\t_map_id_to_session(peer_id, session_id)\n\n\t\t\tif _my_session_id == session_id:\n\t\t\t\t_match_state = MatchState.CONNECTED\n\t\t\t\t_multiplayer_peer.initialize(peer_id)\n\t\t\t\t_multiplayer_peer.set_connection_status(MultiplayerPeer.CONNECTION_CONNECTED)\n\t\t\t\tmatch_joined.emit()\n\t\t\t\t_multiplayer_peer.peer_connected.emit(1)\n\t\t\telse:\n\t\t\t\t_multiplayer_peer.peer_connected.emit(peer_id)\n\t\telse:\n\t\t\t_nakama_socket.logger.error(\"Received meta message with unknown type: %s\" % type)\n\telif data.op_code == rpc_op_code:\n\t\tvar from_session_id: String = data.presence.session_id\n\t\tif not _users.has(from_session_id) or _users[from_session_id].peer_id == 0:\n\t\t\tpush_error(\"Received RPC from %s which isn't assigned a peer id\" % data.presence.session_id)\n\t\t\treturn\n\t\tvar from_peer_id = _users[from_session_id].peer_id\n\t\t_multiplayer_peer.deliver_packet(data.binary_data, from_peer_id)\n\nfunc _on_multiplayer_peer_packet_generated(peer_id: int, buffer: PackedByteArray) -> void:\n\tif match_state == MatchState.CONNECTED:\n\t\tvar target_presences = null\n\t\tif peer_id > 0:\n\t\t\tif not _id_map.has(peer_id):\n\t\t\t\tpush_error(\"Attempting to send RPC to unknown peer id: %s\" % peer_id)\n\t\t\t\treturn\n\t\t\ttarget_presences = [ _users[_id_map[peer_id]].presence ]\n\t\t_nakama_socket.send_match_state_raw_async(_match_id, rpc_op_code, buffer, target_presences)\n\telse:\n\t\tpush_error(\"RPC sent while the NakamaMultiplayerBridge isn't connected!\")\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/utils/NakamaMultiplayerPeer.gd",
    "content": "extends MultiplayerPeerExtension\nclass_name NakamaMultiplayerPeer\n\nconst MAX_PACKET_SIZE := 1 << 24\n\nvar _self_id := 0\nvar _connection_status: ConnectionStatus = CONNECTION_DISCONNECTED\nvar _refusing_new_connections := false\nvar _target_id := 0\n\nclass Packet extends RefCounted:\n\tvar data: PackedByteArray\n\tvar from: int\n\n\tfunc _init(p_data: PackedByteArray, p_from: int) -> void:\n\t\tdata = p_data\n\t\tfrom = p_from\n\nvar _incoming_packets := []\n\nsignal packet_generated (peer_id, buffer)\n\nfunc _get_packet_script() -> PackedByteArray:\n\tif _incoming_packets.size() == 0:\n\t\treturn PackedByteArray()\n\treturn _incoming_packets.pop_front().data\n\nfunc _get_packet_mode() -> TransferMode:\n\treturn TRANSFER_MODE_RELIABLE\n\nfunc _get_packet_channel() -> int:\n\treturn 0\n\nfunc _put_packet_script(p_buffer: PackedByteArray) -> Error:\n\tpacket_generated.emit(_target_id, p_buffer)\n\treturn OK\n\nfunc _get_available_packet_count() -> int:\n\treturn _incoming_packets.size()\n\nfunc _get_max_packet_size() -> int:\n\treturn MAX_PACKET_SIZE\n\nfunc _set_transfer_channel(p_channel) -> void:\n\tpass\n\nfunc _get_transfer_channel() -> int:\n\treturn 0\n\nfunc _set_transfer_mode(p_mode: TransferMode) -> void:\n\tpass\n\nfunc _get_transfer_mode() -> TransferMode:\n\treturn TRANSFER_MODE_RELIABLE\n\nfunc _set_target_peer(p_peer_id: int) -> void:\n\t_target_id = p_peer_id\n\nfunc _get_packet_peer() -> int:\n\tif _connection_status != CONNECTION_CONNECTED:\n\t\treturn 1\n\tif _incoming_packets.size() == 0:\n\t\treturn 1\n\n\treturn _incoming_packets[0].from\n\nfunc _is_server() -> bool:\n\treturn _self_id == 1\n\nfunc _poll() -> void:\n\tpass\n\nfunc _get_unique_id() -> int:\n\treturn _self_id\n\nfunc _set_refuse_new_connections(p_enable: bool) -> void:\n\t_refusing_new_connections = p_enable\n\nfunc _is_refusing_new_connections() -> bool:\n\treturn _refusing_new_connections\n\nfunc _get_connection_status() -> ConnectionStatus:\n\treturn _connection_status\n\nfunc initialize(p_self_id: int) -> void:\n\tif _connection_status != CONNECTION_CONNECTING:\n\t\treturn\n\t_self_id = p_self_id\n\tif _self_id == 1:\n\t\t_connection_status = CONNECTION_CONNECTED\n\nfunc set_connection_status(p_connection_status: int) -> void:\n\t_connection_status = p_connection_status\n\nfunc deliver_packet(p_data: PackedByteArray, p_from_peer_id: int) -> void:\n\tvar packet = Packet.new(p_data, p_from_peer_id);\n\t_incoming_packets.push_back(packet)\n"
  },
  {
    "path": "addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd",
    "content": "extends RefCounted\nclass_name NakamaSerializer\n\nstatic func serialize(p_obj : Object) -> Dictionary:\n\tvar out = {}\n\tvar schema = p_obj.get(\"_SCHEMA\")\n\tif schema == null:\n\t\treturn {} # No schema defined\n\tfor k in schema:\n\t\tvar prop = schema[k]\n\t\tvar val = p_obj.get(prop[\"name\"])\n\t\tif val == null:\n\t\t\tcontinue\n\t\tvar type = prop[\"type\"]\n\t\tvar content = prop.get(\"content\", TYPE_NIL)\n\t\tif typeof(content) == TYPE_STRING:\n\t\t\tcontent = TYPE_OBJECT\n\t\tvar val_type = typeof(val)\n\t\tmatch val_type:\n\t\t\tTYPE_OBJECT: # Simple objects\n\t\t\t\tout[k] = serialize(val)\n\t\t\tTYPE_ARRAY: # Array of objects\n\t\t\t\tvar arr = []\n\t\t\t\tfor e in val:\n\t\t\t\t\tif typeof(e) != TYPE_OBJECT:\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tarr.append(serialize(e))\n\t\t\t\tout[k] = arr\n\t\t\tTYPE_PACKED_INT32_ARRAY, TYPE_PACKED_STRING_ARRAY: # Array of ints, bools, or strings\n\t\t\t\tvar arr = []\n\t\t\t\tfor e in val:\n\t\t\t\t\tif content == TYPE_BOOL:\n\t\t\t\t\t\te = bool(e)\n\t\t\t\t\tif typeof(e) != content:\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tarr.append(e)\n\t\t\t\tout[k] = arr\n\t\t\tTYPE_DICTIONARY: # Maps\n\t\t\t\tvar dict = {}\n\t\t\t\tif content == TYPE_OBJECT: # Map of objects\n\t\t\t\t\tfor l in val:\n\t\t\t\t\t\tif typeof(val[l]) != TYPE_OBJECT:\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tdict[l] = serialize(val[l])\n\t\t\t\telse: # Map of simple types\n\t\t\t\t\tfor l in val:\n\t\t\t\t\t\tvar e = val[l]\n\t\t\t\t\t\tif content == TYPE_FLOAT:\n\t\t\t\t\t\t\te = float(e)\n\t\t\t\t\t\telif content == TYPE_INT:\n\t\t\t\t\t\t\te = int(e)\n\t\t\t\t\t\telif content == TYPE_BOOL:\n\t\t\t\t\t\t\te = bool(e)\n\t\t\t\t\t\tif typeof(e) != content:\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tdict[l] = e\n\t\t\t\tout[k] = dict\n\t\t\t_:\n\t\t\t\tout[k] = val\n\treturn out\n\nstatic func deserialize(p_ns : GDScript, p_cls_name : String, p_dict : Dictionary) -> Object:\n\tvar cls : GDScript = p_ns.get(p_cls_name)\n\tvar schema = cls.get(\"_SCHEMA\")\n\tif schema == null:\n\t\treturn NakamaException.new() # No schema defined\n\tvar obj = cls.new()\n\tfor k in schema:\n\t\tvar prop = schema[k]\n\t\tvar pname = prop[\"name\"]\n\t\tvar type = prop[\"type\"]\n\t\tvar required = prop[\"required\"]\n\t\tvar content = prop.get(\"content\", TYPE_NIL)\n\t\tvar type_cmp = type\n\t\tif typeof(type) == TYPE_STRING: # A class\n\t\t\ttype_cmp = TYPE_DICTIONARY\n\t\tif type_cmp == TYPE_PACKED_STRING_ARRAY or type_cmp == TYPE_PACKED_INT32_ARRAY: # A specialized array\n\t\t\ttype_cmp = TYPE_ARRAY\n\n\t\tvar content_cmp = content\n\t\tif typeof(content) == TYPE_STRING: # A dictionary or array of classes\n\t\t\tcontent_cmp = TYPE_DICTIONARY\n\n\t\tvar val = p_dict.get(k, null)\n\n\t\t# Ints might and up being recognized as floats. Change that if needed\n\t\tif type_cmp == TYPE_INT:\n\t\t\tif typeof(val) == TYPE_FLOAT:\n\t\t\t\tval = int(val)\n\t\t\telif typeof(val) == TYPE_STRING and val.is_valid_int():\n\t\t\t\tval = val.to_int()\n\n\t\tif typeof(val) == type_cmp:\n\t\t\tif typeof(type) == TYPE_STRING:\n\t\t\t\tobj.set(pname, deserialize(p_ns, type, val))\n\t\t\telif type_cmp == TYPE_DICTIONARY:\n\t\t\t\tvar v = {}\n\t\t\t\tfor l in val:\n\t\t\t\t\tif typeof(content) == TYPE_STRING:\n\t\t\t\t\t\tv[l] = deserialize(p_ns, content, val[l])\n\t\t\t\t\telif content == TYPE_FLOAT:\n\t\t\t\t\t\tv[l] = float(val[l])\n\t\t\t\t\telif content == TYPE_INT:\n\t\t\t\t\t\tv[l] = int(val[l])\n\t\t\t\t\telif content == TYPE_BOOL:\n\t\t\t\t\t\tv[l] = bool(val[l])\n\t\t\t\t\telse:\n\t\t\t\t\t\tv[l] = str(val[l])\n\t\t\t\tobj.set(pname, v)\n\t\t\telif type_cmp == TYPE_ARRAY:\n\t\t\t\tvar v\n\t\t\t\tmatch content:\n\t\t\t\t\tTYPE_INT, TYPE_BOOL: v = PackedInt32Array()\n\t\t\t\t\tTYPE_STRING: v = PackedStringArray()\n\t\t\t\t\t_: v = Array()\n\t\t\t\tfor e in val:\n\t\t\t\t\tif typeof(content) == TYPE_STRING:\n\t\t\t\t\t\tv.append(deserialize(p_ns, content, e))\n\t\t\t\t\telif content == TYPE_FLOAT:\n\t\t\t\t\t\tv.append(float(e))\n\t\t\t\t\telif content == TYPE_INT:\n\t\t\t\t\t\tv.append(int(e))\n\t\t\t\t\telif content == TYPE_BOOL:\n\t\t\t\t\t\tv.append(bool(e))\n\t\t\t\t\telse:\n\t\t\t\t\t\tv.append(str(e))\n\t\t\t\tobj.set(pname, v)\n\t\t\telse:\n\t\t\t\tobj.set(pname, val)\n\t\telif required:\n\t\t\tobj._ex = NakamaException.new(\"ERROR [%s]: Missing or invalid required prop %s = %s:\\n\\t%s\" % [p_cls_name, prop, p_dict.get(k), p_dict])\n\t\t\treturn obj\n\treturn obj\n\n\n###\n# Compatibility with Godot 3.1 which does not expose String.http_escape\n###\nconst HEX = [\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"A\",\"B\",\"C\",\"D\",\"E\",\"F\"]\n\nstatic func escape_http(p_str : String) -> String:\n\tvar out : String = \"\"\n\tfor o in p_str:\n\t\tif (o == '.' or o == '-' or o == '_' or o == '~' or\n\t\t\t(o >= 'a' and o <= 'z') or\n\t\t\t(o >= 'A' and o <= 'Z') or\n\t\t\t(o >= '0' and o <= '9')):\n\t\t\tout += o\n\t\telse:\n\t\t\tfor b in o.to_utf8_buffer():\n\t\t\t\tout += \"%%%s\" % to_hex(b)\n\treturn out\n\nstatic func to_hex(p_val : int) -> String:\n\tvar v := p_val\n\tvar o := \"\"\n\twhile v != 0:\n\t\to = HEX[v % 16] + o\n\t\tv /= 16\n\treturn o\n"
  },
  {
    "path": "addons/nakama-webrtc/LICENSE.txt",
    "content": "Copyright (c) 2019-2021 David Snopek\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "addons/nakama-webrtc/OnlineMatch.gd",
    "content": "extends Node\n\n# For developers to set from the outside, for example:\n#   OnlineMatch.max_players = 8\n#   OnlineMatch.client_version = 'v1.2'\n#   OnlineMatch.ice_servers = [ ... ]\n#   OnlineMatch.use_network_relay = OnlineMatch.NetworkRelay.FORCED\nvar min_players := 2\nvar max_players := 8\nvar client_version := 'dev'\nvar ice_servers = [\n\t{\n\t\"urls\": \"stun:161.35.244.122:3478\",\n\t},\n\t{\n\t\"urls\": \"turn:161.35.244.122:3478\",\n\t\"username\": \"placeholder\",\n\t\"credential\": \"placeholder\",\n\t},\n\t{\n\t\"urls\": \"turn:161.35.244.122:3478?transport=tcp\",\n\t\"username\": \"placeholder\",\n\t\"credential\": \"placeholder\",\n\t},\n\t{\n\t\"urls\": \"turns:161.35.244.122:3478?transport=tcp\",\n\t\"username\": \"placeholder\",\n\t\"credential\": \"placeholder\",\n\t},\n]\n\nenum NetworkRelay {\n\tAUTO,\n\tFORCED,\n\tDISABLED\n}\nvar use_network_relay: int = NetworkRelay.AUTO\n\n#\n# Nakama variables:\n#\n\nvar _nakama_socket: NakamaSocket\nvar nakama_socket: NakamaSocket:\n\tset (value):\n\t\tpass\n\tget:\n\t\treturn _nakama_socket\n\nvar _my_session_id: String\nvar my_session_id: String:\n\tset (value):\n\t\tpass\n\tget:\n\t\treturn get_my_session_id()\n\nvar _match_id: String\nvar match_id: String:\n\tset (value):\n\t\tpass\n\tget:\n\t\treturn get_match_id()\n\nvar _matchmaker_ticket: String\nvar matchmaker_ticket: String:\n\tset (value):\n\t\tpass\n\tget:\n\t\treturn get_matchmaker_ticket()\n\n# WebRTC variables:\nvar _webrtc_multiplayer: WebRTCMultiplayerPeer\nvar _webrtc_peers: Dictionary\nvar _webrtc_peers_connected: Dictionary\n\nvar players: Dictionary\nvar _next_peer_id: int\n\nenum MatchState {\n\tLOBBY = 0,\n\tMATCHING = 1,\n\tCONNECTING = 2,\n\tWAITING_FOR_ENOUGH_PLAYERS = 3,\n\tREADY = 4,\n\tPLAYING = 5,\n}\nvar _match_state: int = MatchState.LOBBY\nvar match_state: int:\n\tset (value):\n\t\tpass\n\tget:\n\t\treturn get_match_state()\n\nenum MatchMode {\n\tNONE = 0,\n\tCREATE = 1,\n\tJOIN = 2,\n\tMATCHMAKER = 3,\n}\nvar _match_mode: int = MatchMode.NONE\nvar match_mode: int:\n\tset (value):\n\t\tpass\n\tget:\n\t\treturn get_match_mode()\n\nenum WebrtcPlayerStatus {\n\tCONNECTING = 0,\n\tCONNECTED = 1,\n}\n\nenum MatchOpCode {\n\tWEBRTC_PEER_METHOD = 9001,\n\tJOIN_SUCCESS = 9002,\n\tJOIN_ERROR = 9003,\n}\n\nsignal error (message)\nsignal disconnected ()\n\nsignal match_created (match_id)\nsignal match_joined (match_id)\nsignal matchmaker_matched (players)\nsignal match_left ()\n\nsignal player_joined (player)\nsignal player_left (player)\nsignal player_status_changed (player, status)\n\nsignal match_ready (players)\nsignal match_not_ready ()\n\nsignal webrtc_peer_added (webrtc_peer, player)\nsignal webrtc_peer_removed (webrtc_peer, player)\n\nclass WebrtcPlayer:\n\tvar session_id: String\n\tvar user_id: String\n\tvar peer_id: int\n\tvar username: String\n\n\tfunc _init(_session_id: String, _user_id: String, _username: String, _peer_id: int) -> void:\n\t\tsession_id = _session_id\n\t\tuser_id = _user_id\n\t\tusername = _username\n\t\tpeer_id = _peer_id\n\n\tstatic func from_presence(presence, _peer_id: int) -> WebrtcPlayer:\n\t\treturn WebrtcPlayer.new(presence.session_id, presence.user_id, presence.username, _peer_id)\n\n\tstatic func from_dict(data: Dictionary) -> WebrtcPlayer:\n\t\treturn WebrtcPlayer.new(data['session_id'], data['user_id'], data['username'], int(data['peer_id']))\n\n\tfunc to_dict() -> Dictionary:\n\t\treturn {\n\t\t\tsession_id = session_id,\n\t\t\tuser_id = user_id,\n\t\t\tusername = username,\n\t\t\tpeer_id = peer_id,\n\t\t}\n\nstatic func serialize_players(_players: Dictionary) -> Dictionary:\n\tvar result := {}\n\tfor key in _players:\n\t\tresult[key] = _players[key].to_dict()\n\treturn result\n\nstatic func unserialize_players(_players: Dictionary) -> Dictionary:\n\tvar result := {}\n\tfor key in _players:\n\t\tresult[key] = WebrtcPlayer.from_dict(_players[key])\n\treturn result\n\n\n# Load username and credentials for ICE server here\nfunc _ready():\n\tvar ice_username: String = Secrets.get_secret(Secrets.Key.ICE_USERNAME)\n\tvar ice_credential: String = Secrets.get_secret(Secrets.Key.ICE_CREDENTIAL)\n\t\n\tfor url_section in ice_servers:\n\t\tif url_section.has(\"username\"):\n\t\t\turl_section[\"username\"] = ice_username\n\t\t\n\t\tif url_section.has(\"credential\"):\n\t\t\turl_section[\"credential\"] = ice_credential\n\n\tclient_version = Config.build_version()\n\n\nfunc _set_readonly_variable(_value) -> void:\n\tpass\n\nfunc _set_nakama_socket(p_nakama_socket: NakamaSocket) -> void:\n\tif _nakama_socket == p_nakama_socket:\n\t\treturn\n\n\tif _nakama_socket:\n\t\t_nakama_socket.closed.disconnect(self._on_nakama_closed)\n\t\t_nakama_socket.received_error.disconnect(self._on_nakama_error)\n\t\t_nakama_socket.received_match_state.disconnect(self._on_nakama_match_state)\n\t\t_nakama_socket.received_match_presence.disconnect(self._on_nakama_match_presence)\n\t\t_nakama_socket.received_matchmaker_matched.disconnect(self._on_nakama_matchmaker_matched)\n\n\t_nakama_socket = p_nakama_socket\n\tif _nakama_socket:\n\t\t_nakama_socket.closed.connect(self._on_nakama_closed)\n\t\t_nakama_socket.received_error.connect(self._on_nakama_error)\n\t\t_nakama_socket.received_match_state.connect(self._on_nakama_match_state)\n\t\t_nakama_socket.received_match_presence.connect(self._on_nakama_match_presence)\n\t\t_nakama_socket.received_matchmaker_matched.connect(self._on_nakama_matchmaker_matched)\n\n\nfunc create_match(p_nakama_socket: NakamaSocket, leave_prev_match: bool = true) -> void:\n\tvar close_socket: bool = false\n\tleave(close_socket, leave_prev_match)\n\t_set_nakama_socket(p_nakama_socket)\n\t_match_mode = MatchMode.CREATE\n\n\tvar data = await _nakama_socket.create_match_async()\n\tif data.is_exception():\n\t\tleave()\n\t\terror.emit(\"Failed to create match: \" + str(data.get_exception().message))\n\telse:\n\t\t_on_nakama_match_created(data)\n\nfunc join_match(p_nakama_socket: NakamaSocket, p_match_id: String) -> void:\n\tleave()\n\t_set_nakama_socket(p_nakama_socket)\n\t_match_mode = MatchMode.JOIN\n\n\tvar data = await _nakama_socket.join_match_async(p_match_id)\n\tif data.is_exception():\n\t\tleave()\n\t\terror.emit(\"Unable to join match\")\n\telse:\n\t\t_on_nakama_match_join(data)\n\nfunc start_matchmaking(p_nakama_socket: NakamaSocket, data: Dictionary = {}) -> void:\n\tleave()\n\t_set_nakama_socket(p_nakama_socket)\n\t_match_mode = MatchMode.MATCHMAKER\n\n\tif data.has('min_count'):\n\t\tdata['min_count'] = max(min_players, data['min_count'])\n\telse:\n\t\tdata['min_count'] = min_players\n\n\tif data.has('max_count'):\n\t\tdata['max_count'] = min(max_players, data['max_count'])\n\telse:\n\t\tdata['max_count'] = max_players\n\n\tif client_version != '':\n\t\tif not data.has('string_properties'):\n\t\t\tdata['string_properties'] = {}\n\t\tdata['string_properties']['client_version'] = client_version\n\n\t\tvar query = '+properties.client_version:' + client_version\n\t\tif data.has('query'):\n\t\t\tdata['query'] += ' ' + query\n\t\telse:\n\t\t\tdata['query'] = query\n\n\t_match_state = MatchState.MATCHING\n\tvar result = await _nakama_socket.add_matchmaker_async(data.get('query', '*'), data['min_count'], data['max_count'], data.get('string_properties', {}), data.get('numeric_properties', {}))\n\tif result.is_exception():\n\t\tleave()\n\t\terror.emit(\"Unable to join match making pool\")\n\telse:\n\t\t_matchmaker_ticket = result.ticket\n\nfunc start_playing() -> void:\n\tassert(_match_state == MatchState.READY)\n\t_match_state = MatchState.PLAYING\n\nfunc leave(close_socket: bool = false, leave_match: bool = true) -> void:\n\t# WebRTC disconnect.\n\tif _webrtc_multiplayer:\n\t\t_webrtc_multiplayer.close()\n\n\t\tvar default_peer: OfflineMultiplayerPeer = OfflineMultiplayerPeer.new()\n\t\tget_tree().get_multiplayer().set_multiplayer_peer(default_peer)\n\n\t# Nakama disconnect.\n\tif _nakama_socket:\n\t\tif _match_id:\n\t\t\tif leave_match:\n\t\t\t\tawait _nakama_socket.leave_match_async(_match_id)\n\t\telif _matchmaker_ticket:\n\t\t\tawait _nakama_socket.remove_matchmaker_async(_matchmaker_ticket)\n\t\tif close_socket:\n\t\t\t_nakama_socket.close()\n\t\t\t_set_nakama_socket(null)\n\n\t# Initialize all the variables to their default state.\n\t_my_session_id = ''\n\t_match_id = ''\n\t_matchmaker_ticket = ''\n\t_create_webrtc_multiplayer()\n\t_webrtc_peers = {}\n\t_webrtc_peers_connected = {}\n\tplayers = {}\n\t_next_peer_id = 1\n\t_match_state = MatchState.LOBBY\n\t_match_mode = MatchMode.NONE\n\n\tmatch_left.emit()\n\nfunc _create_webrtc_multiplayer() -> void:\n\tif _webrtc_multiplayer:\n\t\t_webrtc_multiplayer.peer_connected.disconnect(self._on_webrtc_peer_connected)\n\t\t_webrtc_multiplayer.peer_disconnected.disconnect(self._on_webrtc_peer_disconnected)\n\n\t_webrtc_multiplayer = WebRTCMultiplayerPeer.new()\n\t_webrtc_multiplayer.peer_connected.connect(self._on_webrtc_peer_connected)\n\t_webrtc_multiplayer.peer_disconnected.connect(self._on_webrtc_peer_disconnected)\n\nfunc get_my_session_id() -> String:\n\treturn _my_session_id\n\nfunc get_match_id() -> String:\n\treturn _match_id\n\nfunc get_matchmaker_ticket() -> String:\n\treturn _matchmaker_ticket\n\nfunc get_match_mode() -> int:\n\treturn _match_mode\n\nfunc get_match_state() -> int:\n\treturn _match_state\n\nfunc get_session_id(peer_id: int):\n\tfor session_id in players:\n\t\tif players[session_id]['peer_id'] == peer_id:\n\t\t\treturn session_id\n\treturn null\n\nfunc get_player_by_peer_id(peer_id: int) -> WebrtcPlayer:\n\tvar session_id = get_session_id(peer_id)\n\tif session_id:\n\t\treturn players[session_id]\n\treturn null\n\nfunc get_players_by_peer_id() -> Dictionary:\n\tvar result := {}\n\tfor player in players.values():\n\t\tresult[player.peer_id] = player\n\treturn result\n\nfunc get_player_names_by_peer_id() -> Dictionary:\n\tvar result := {}\n\tfor session_id in players:\n\t\tresult[players[session_id]['peer_id']] = players[session_id]['username']\n\treturn result\n\nfunc get_webrtc_peer(session_id: String) -> WebRTCPeerConnection:\n\treturn _webrtc_peers.get(session_id, null)\n\nfunc get_webrtc_peer_by_peer_id(peer_id: int) -> WebRTCPeerConnection:\n\tvar player = get_player_by_peer_id(peer_id)\n\tif player:\n\t\treturn _webrtc_peers.get(player.session_id, null)\n\treturn null\n\nfunc _on_nakama_error(data) -> void:\n\tprint(\"Nakama error in OnlineMatch.gd:\")\n\tprint(data)\n\tleave()\n\terror.emit(\"Websocket connection error\")\n\nfunc _on_nakama_closed() -> void:\n\tleave()\n\tdisconnected.emit()\n\nfunc _on_nakama_match_created(data) -> void:\n\t_match_id = data.match_id\n\t_my_session_id = data.self_user.session_id\n\tvar my_player = WebrtcPlayer.from_presence(data.self_user, 1)\n\tplayers[_my_session_id] = my_player\n\t_next_peer_id = 2\n\n\t_webrtc_multiplayer.create_mesh(1)\n\tget_tree().get_multiplayer().set_multiplayer_peer(_webrtc_multiplayer)\n\n\tmatch_created.emit(_match_id)\n\tplayer_joined.emit(my_player)\n\tplayer_status_changed.emit(my_player, WebrtcPlayerStatus.CONNECTED)\n\nfunc _on_nakama_match_presence(data) -> void:\n\tfor u in data.joins:\n\t\tif u.session_id == _my_session_id:\n\t\t\tcontinue\n\n\t\tif _match_mode == MatchMode.CREATE:\n\t\t\tif _match_state == MatchState.PLAYING:\n\t\t\t\t# Tell this player that we've already started\n\t\t\t\t_nakama_socket.send_match_state_async(_match_id, MatchOpCode.JOIN_ERROR, JSON.new().stringify({\n\t\t\t\t\ttarget = u['session_id'],\n\t\t\t\t\treason = 'Sorry! The match has already begun.',\n\t\t\t\t}))\n\n\t\t\tif players.size() < max_players:\n\t\t\t\tvar new_player = WebrtcPlayer.from_presence(u, _next_peer_id)\n\t\t\t\t_next_peer_id += 1\n\t\t\t\tplayers[u.session_id] = new_player\n\t\t\t\tplayer_joined.emit(new_player)\n\n\t\t\t\t# Tell this player (and the others) about all the players peer ids.\n\t\t\t\t_nakama_socket.send_match_state_async(_match_id, MatchOpCode.JOIN_SUCCESS, JSON.new().stringify({\n\t\t\t\t\tplayers = serialize_players(players),\n\t\t\t\t\tclient_version = client_version,\n\t\t\t\t}))\n\n\t\t\t\t_webrtc_connect_peer(new_player)\n\t\t\telse:\n\t\t\t\t# Tell this player that we're full up!\n\t\t\t\t_nakama_socket.send_match_state_async(_match_id, MatchOpCode.JOIN_ERROR, JSON.new().stringify({\n\t\t\t\t\ttarget = u['session_id'],\n\t\t\t\t\treason = 'Sorry! The match is full.,',\n\t\t\t\t}))\n\t\telif _match_mode == MatchMode.MATCHMAKER:\n\t\t\tplayer_joined.emit(players[u.session_id])\n\t\t\t_webrtc_connect_peer(players[u.session_id])\n\n\tfor u in data.leaves:\n\t\tif u.session_id == _my_session_id:\n\t\t\tcontinue\n\t\tif not players.has(u.session_id):\n\t\t\tcontinue\n\n\t\tvar player = players[u.session_id]\n\t\t_webrtc_disconnect_peer(player)\n\n\t\t# If the host disconnects, this is the end!\n\t\tif player.peer_id == 1:\n\t\t\tleave()\n\t\t\terror.emit(\"Host has disconnected\")\n\t\telse:\n\t\t\tplayers.erase(u.session_id)\n\t\t\tplayer_left.emit(player)\n\n\t\t\tif players.size() < min_players:\n\t\t\t\t# If state was previously ready, but this brings us below the minimum players,\n\t\t\t\t# then we aren't ready anymore.\n\t\t\t\tif _match_state == MatchState.READY:\n\t\t\t\t\t_match_state = MatchState.WAITING_FOR_ENOUGH_PLAYERS\n\t\t\t\t\tmatch_not_ready.emit()\n\t\t\telse:\n\t\t\t\t# If the remaining players are all fully connected, then set\n\t\t\t\t# the match state to ready.\n\t\t\t\tif _webrtc_peers_connected.size() == players.size() - 1:\n\t\t\t\t\t_match_state = MatchState.READY;\n\t\t\t\t\tmatch_ready.emit(players)\n\nfunc _on_nakama_match_join(data) -> void:\n\t_match_id = data.match_id\n\t_my_session_id = data.self_user.session_id\n\n\tif _match_mode == MatchMode.JOIN:\n\t\tmatch_joined.emit(_match_id)\n\telif _match_mode == MatchMode.MATCHMAKER:\n\t\tfor u in data.presences:\n\t\t\tif u.session_id == _my_session_id:\n\t\t\t\t\tcontinue\n\t\t\t_webrtc_connect_peer(players[u.session_id])\n\nfunc _on_nakama_matchmaker_matched(data) -> void:\n\tif data.is_exception():\n\t\tleave()\n\t\terror.emit(\"Matchmaker error\")\n\t\treturn\n\n\t_my_session_id = data.self_user.presence.session_id\n\n\t# Use the list of users to assign peer ids.\n\tfor u in data.users:\n\t\tplayers[u.presence.session_id] = WebrtcPlayer.from_presence(u.presence, 0)\n\tvar session_ids = players.keys();\n\tsession_ids.sort()\n\tfor session_id in session_ids:\n\t\tplayers[session_id].peer_id = _next_peer_id\n\t\t_next_peer_id += 1\n\n\t# Initialize multiplayer using our peer id\n\t_webrtc_multiplayer.create_mesh(players[_my_session_id].peer_id)\n\tget_tree().get_multiplayer().multiplayer_peer = _webrtc_multiplayer\n\n\tmatchmaker_matched.emit(players)\n\tplayer_status_changed.emit(players[_my_session_id], WebrtcPlayerStatus.CONNECTED)\n\n\t# Join the match.\n\tvar result = await _nakama_socket.join_matched_async(data)\n\tif result.is_exception():\n\t\tleave()\n\t\terror.emit(\"Unable to join match\")\n\telse:\n\t\t_on_nakama_match_join(result)\n\nfunc _on_nakama_match_state(data) -> void:\n\tvar json = JSON.new()\n\tif json.parse(data.data) != OK:\n\t\treturn\n\n\tvar content = json.get_data()\n\tif data.op_code == MatchOpCode.WEBRTC_PEER_METHOD:\n\t\tif content['target'] == _my_session_id:\n\t\t\tvar session_id = data.presence.session_id\n\t\t\tif not _webrtc_peers.has(session_id):\n\t\t\t\treturn\n\t\t\tvar webrtc_peer = _webrtc_peers[session_id]\n\t\t\tmatch content['method']:\n\t\t\t\t'set_remote_description':\n\t\t\t\t\twebrtc_peer.set_remote_description(content['type'], content['sdp'])\n\n\t\t\t\t'add_ice_candidate':\n\t\t\t\t\tif _webrtc_check_ice_candidate(content['name']):\n\t\t\t\t\t\t#print (\"Receiving ice candidate: %s\" % content['name'])\n\t\t\t\t\t\twebrtc_peer.add_ice_candidate(content['media'], content['index'], content['name'])\n\n\t\t\t\t'reconnect':\n\t\t\t\t\t_webrtc_multiplayer.remove_peer(players[session_id]['peer_id'])\n\t\t\t\t\t_webrtc_reconnect_peer(players[session_id])\n\tif data.op_code == MatchOpCode.JOIN_SUCCESS && _match_mode == MatchMode.JOIN:\n\t\tvar host_client_version = content.get('client_version', '')\n\t\tif client_version != host_client_version:\n\t\t\tleave()\n\t\t\terror.emit(\"Client version doesn't match host\")\n\t\t\treturn\n\n\t\tvar content_players = unserialize_players(content['players'])\n\n\t\t_webrtc_multiplayer.create_mesh(content_players[_my_session_id].peer_id)\n\t\tget_tree().get_multiplayer().set_multiplayer_peer(_webrtc_multiplayer)\n\n\t\tfor session_id in content_players:\n\t\t\tif not players.has(session_id):\n\t\t\t\tplayers[session_id] = content_players[session_id]\n\t\t\t\t_webrtc_connect_peer(players[session_id])\n\t\t\t\tplayer_joined.emit(players[session_id])\n\t\t\t\tif session_id == _my_session_id:\n\t\t\t\t\tplayer_status_changed.emit(players[session_id], WebrtcPlayerStatus.CONNECTED)\n\tif data.op_code == MatchOpCode.JOIN_ERROR:\n\t\tif content['target'] == _my_session_id:\n\t\t\tleave()\n\t\t\terror.emit(content['reason'])\n\t\t\treturn\n\nfunc _webrtc_connect_peer(player: WebrtcPlayer) -> void:\n\t# Don't add the same peer twice!\n\tif _webrtc_peers.has(player.session_id):\n\t\treturn\n\n\t# If the match was previously ready, then we need to switch back to not ready.\n\tif _match_state == MatchState.READY:\n\t\tmatch_not_ready.emit()\n\n\t# If we're already PLAYING, then this is a reconnect attempt, so don't mess with the state.\n\t# Otherwise, change state to CONNECTING because we're trying to connect to all peers.\n\tif _match_state != MatchState.PLAYING:\n\t\t_match_state = MatchState.CONNECTING\n\n\tvar webrtc_peer := WebRTCPeerConnection.new()\n\twebrtc_peer.initialize({\n\t\t\"iceServers\": ice_servers,\n\t})\n\twebrtc_peer.session_description_created.connect(self._on_webrtc_peer_session_description_created.bind(player.session_id))\n\twebrtc_peer.ice_candidate_created.connect(self._on_webrtc_peer_ice_candidate_created.bind(player.session_id))\n\n\t_webrtc_peers[player.session_id] = webrtc_peer\n\n\t#get_tree().multiplayer._del_peer(u['peer_id'])\n\t_webrtc_multiplayer.add_peer(webrtc_peer, player.peer_id, 0)\n\n\twebrtc_peer_added.emit(webrtc_peer, player)\n\n\tif _my_session_id.casecmp_to(player.session_id) < 0:\n\t\tvar result = webrtc_peer.create_offer()\n\t\tif result != OK:\n\t\t\terror.emit(\"Unable to create WebRTC offer\")\n\nfunc _webrtc_disconnect_peer(player: WebrtcPlayer) -> void:\n\tvar webrtc_peer = _webrtc_peers[player.session_id]\n\twebrtc_peer_removed.emit(webrtc_peer, player)\n\twebrtc_peer.close()\n\t_webrtc_peers.erase(player.session_id)\n\t_webrtc_peers_connected.erase(player.session_id)\n\nfunc _webrtc_reconnect_peer(player: WebrtcPlayer) -> void:\n\tvar old_webrtc_peer = _webrtc_peers[player.session_id]\n\tif old_webrtc_peer:\n\t\twebrtc_peer_removed.emit(old_webrtc_peer, player)\n\t\told_webrtc_peer.close()\n\n\t_webrtc_peers_connected.erase(player.session_id)\n\t_webrtc_peers.erase(player.session_id)\n\n\tprint (\"Starting WebRTC reconnect...\")\n\n\t_webrtc_connect_peer(player)\n\n\tplayer_status_changed.emit(player, WebrtcPlayerStatus.CONNECTING)\n\n\tif _match_state == MatchState.READY:\n\t\t_match_state = MatchState.CONNECTING\n\t\tmatch_not_ready.emit()\n\nfunc _webrtc_check_ice_candidate(name: String) -> bool:\n\tif use_network_relay == NetworkRelay.AUTO:\n\t\treturn true\n\n\tvar is_relay: bool = \"typ relay\" in name\n\n\tif use_network_relay == NetworkRelay.FORCED:\n\t\treturn is_relay\n\treturn !is_relay\n\nfunc _on_webrtc_peer_session_description_created(type: String, sdp: String, session_id: String) -> void:\n\tvar webrtc_peer = _webrtc_peers[session_id]\n\twebrtc_peer.set_local_description(type, sdp)\n\n\t# Send this data to the peer so they can call call .set_remote_description().\n\t_nakama_socket.send_match_state_async(_match_id, MatchOpCode.WEBRTC_PEER_METHOD, JSON.new().stringify({\n\t\tmethod = \"set_remote_description\",\n\t\ttarget = session_id,\n\t\ttype = type,\n\t\tsdp = sdp,\n\t}))\n\nfunc _on_webrtc_peer_ice_candidate_created(media: String, index: int, name: String, session_id: String) -> void:\n\tif not _webrtc_check_ice_candidate(name):\n\t\treturn\n\n\t#print (\"Sending ice candidate: %s\" % name)\n\n\t# Send this data to the peer so they can call .add_ice_candidate()\n\t_nakama_socket.send_match_state_async(_match_id, MatchOpCode.WEBRTC_PEER_METHOD, JSON.new().stringify({\n\t\tmethod = \"add_ice_candidate\",\n\t\ttarget = session_id,\n\t\tmedia = media,\n\t\tindex = index,\n\t\tname = name,\n\t}))\n\nfunc _on_webrtc_peer_connected(peer_id: int) -> void:\n\tfor session_id in players:\n\t\tif players[session_id]['peer_id'] == peer_id:\n\t\t\t_webrtc_peers_connected[session_id] = true\n\t\t\tprint (\"WebRTC peer connected: \" + str(peer_id))\n\t\t\tplayer_status_changed.emit(players[session_id], WebrtcPlayerStatus.CONNECTED)\n\n\t# We have a WebRTC peer for each connection to another player, so we'll have one less than\n\t# the number of players (ie. no peer connection to ourselves).\n\tif _webrtc_peers_connected.size() == players.size() - 1:\n\t\tif players.size() >= min_players:\n\t\t\t# All our peers are good, so we can assume RPC will work now.\n\t\t\t_match_state = MatchState.READY;\n\t\t\temit_signal(\"match_ready\", players)\n\t\telse:\n\t\t\t_match_state = MatchState.WAITING_FOR_ENOUGH_PLAYERS\n\nfunc _on_webrtc_peer_disconnected(peer_id: int) -> void:\n\tprint (\"WebRTC peer disconnected: \" + str(peer_id))\n\n\tfor session_id in players:\n\t\tif players[session_id]['peer_id'] == peer_id:\n\t\t\t# We initiate the reconnection process from only one side (the offer side).\n\t\t\tif _my_session_id.casecmp_to(session_id) < 0:\n\t\t\t\t# Tell the remote peer to restart their connection.\n\t\t\t\t_nakama_socket.send_match_state_async(_match_id, MatchOpCode.WEBRTC_PEER_METHOD, JSON.new().stringify({\n\t\t\t\t\tmethod = \"reconnect\",\n\t\t\t\t\ttarget = session_id,\n\t\t\t\t}))\n\n\t\t\t\t# Initiate reconnect on our end now (the other end will do it when they receive\n\t\t\t\t# the message above).\n\t\t\t\t_webrtc_reconnect_peer(players[session_id])\n"
  },
  {
    "path": "assets/LICENSE.md",
    "content": "## creative commons\n\n# Attribution-NonCommercial 4.0 International\n\nCreative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.\n\n### Using Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.\n\n* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).\n\n* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).\n\n## Creative Commons Attribution-NonCommercial 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License (\"Public License\"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.\n\n### Section 1 – Definitions.\n\na. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.\n\nb. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.\n\nc. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.\n\nd. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.\n\ne. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.\n\nf. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License.\n\ng. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.\n\nh. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License.\n\ni. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.\n\nj. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.\n\nk. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.\n\nl. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.\n\n### Section 2 – Scope.\n\na. ___License grant.___\n\n    1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:\n\n        A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and\n\n        B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only.\n\n    2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.\n\n    3. __Term.__ The term of this Public License is specified in Section 6(a).\n\n    4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.\n\n    5. __Downstream recipients.__\n\n        A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.\n\n        B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.\n\n    6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).\n\nb. ___Other rights.___\n\n    1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.\n\n    2. Patent and trademark rights are not licensed under this Public License.\n\n    3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.\n\n### Section 3 – License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the following conditions.\n\na. ___Attribution.___\n\n    1. If You Share the Licensed Material (including in modified form), You must:\n\n        A. retain the following if it is supplied by the Licensor with the Licensed Material:\n\n            i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);\n\n            ii. a copyright notice;\n\n            iii. a notice that refers to this Public License;\n\n            iv. a notice that refers to the disclaimer of warranties;\n\n            v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;\n\n        B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and\n\n        C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.\n\n    2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.\n\n    3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.\n\n    4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.\n\n### Section 4 – Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:\n\na. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only;\n\nb. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and\n\nc. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.\n\n### Section 5 – Disclaimer of Warranties and Limitation of Liability.\n\na. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__\n\nb. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__\n\nc. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.\n\n### Section 6 – Term and Termination.\n\na. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.\n\nb. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:\n\n    1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or\n\n    2. upon express reinstatement by the Licensor.\n\n    For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.\n\nc. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.\n\nd. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.\n\n### Section 7 – Other Terms and Conditions.\n\na. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.\n\nb. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.\n\n### Section 8 – Interpretation.\n\na. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.\n\nb. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.\n\nc. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.\n\nd. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.\n\n```\nCreative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.\n\nCreative Commons may be contacted at creativecommons.org\n``"
  },
  {
    "path": "assets/README.md",
    "content": "This folder contains assets.\n\nNote that only the .import files are checked into git. The actual .png, .mp3 files are stored in a google drive and need to be downloaded separately. See CONTRIBUTING.md for instructions.\n"
  },
  {
    "path": "assets/creeps/README.md",
    "content": "Assets in this folder CANNOT be shared.\nShare placeholders instead. Generate placeholders with generate_censored_assets.gd script.\n\nAssets in this folder are based on 3D models purchased from here:\nhttps://shop.bitgem3d.com/products/human-vs-orcs-rts-mega-pack\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b5se2dom7rt6d\"\npath=\"res://.godot/imported/fly_E.png-d2e1e29bc6a89aaefaee14f277227b3b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_E.png\"\ndest_files=[\"res://.godot/imported/fly_E.png-d2e1e29bc6a89aaefaee14f277227b3b.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dg22ncv2bbgpl\"\npath=\"res://.godot/imported/fly_N.png-d358add11cf12b6bce58a3ac7b09f861.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_N.png\"\ndest_files=[\"res://.godot/imported/fly_N.png-d358add11cf12b6bce58a3ac7b09f861.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_NE.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://lhbh8ncpikea\"\npath=\"res://.godot/imported/fly_NE.png-88d0565f0693e0d3904f89b6c2cbae0e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_NE.png\"\ndest_files=[\"res://.godot/imported/fly_NE.png-88d0565f0693e0d3904f89b6c2cbae0e.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_NW.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://m74fw3s6vh5h\"\npath=\"res://.godot/imported/fly_NW.png-7cb3bd641bc6517fb733ba37e40b019c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_NW.png\"\ndest_files=[\"res://.godot/imported/fly_NW.png-7cb3bd641bc6517fb733ba37e40b019c.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ctrob5r1weymb\"\npath=\"res://.godot/imported/fly_S.png-49be55932789d0a99d19dc3d16782d04.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_S.png\"\ndest_files=[\"res://.godot/imported/fly_S.png-49be55932789d0a99d19dc3d16782d04.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_SE.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dejolx201xt4l\"\npath=\"res://.godot/imported/fly_SE.png-b26775c7b649a7069b2ce8e69bd4441d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_SE.png\"\ndest_files=[\"res://.godot/imported/fly_SE.png-b26775c7b649a7069b2ce8e69bd4441d.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_SW.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://beysr35mknwqu\"\npath=\"res://.godot/imported/fly_SW.png-264f8de2b8874f42ca342e0767e8920f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_SW.png\"\ndest_files=[\"res://.godot/imported/fly_SW.png-264f8de2b8874f42ca342e0767e8920f.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/fly_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ddhb3w0ho041v\"\npath=\"res://.godot/imported/fly_W.png-2e13c8954436c40d5443ff1cb7ed7eba.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/air/fly_W.png\"\ndest_files=[\"res://.godot/imported/fly_W.png-2e13c8954436c40d5443ff1cb7ed7eba.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.8\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/air/metadata.csv",
    "content": "name,row_count,col_count,sprite_count,offset_x,offset_y\nfly_E,7,4,25,0.01201923098415,0.05306122452021\nfly_N,7,4,25,0.0101010100916,0.04105090349913\nfly_NE,7,4,25,0.03070175461471,0.06451612710953\nfly_NW,7,4,25,-0.00588235305622,0.0338733419776\nfly_S,7,4,25,-0.01262626238167,0.05605786666274\nfly_SE,7,4,25,0.00294117652811,0.0537815131247\nfly_SW,7,4,25,-0.03070175461471,0.06493506580591\nfly_W,7,4,25,-0.01201923098415,0.04105090349913\n"
  },
  {
    "path": "assets/creeps/orc/air/metadata.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/creeps/orc/boss/death_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b1s341ilp1g0f\"\npath=\"res://.godot/imported/death_E.png-86eb2523defd990fc501c46d62896084.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/death_E.png\"\ndest_files=[\"res://.godot/imported/death_E.png-86eb2523defd990fc501c46d62896084.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/death_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://kyq50l132wm1\"\npath=\"res://.godot/imported/death_N.png-cc3513993dac81b4027956b7c2898567.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/death_N.png\"\ndest_files=[\"res://.godot/imported/death_N.png-cc3513993dac81b4027956b7c2898567.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/death_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cmytlwkuq6i8q\"\npath=\"res://.godot/imported/death_S.png-285add27a90a0429f04de857bddea74d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/death_S.png\"\ndest_files=[\"res://.godot/imported/death_S.png-285add27a90a0429f04de857bddea74d.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/death_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://pulp58p3vflw\"\npath=\"res://.godot/imported/death_W.png-51f22c1ea00de00f01144f18b14aa38e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/death_W.png\"\ndest_files=[\"res://.godot/imported/death_W.png-51f22c1ea00de00f01144f18b14aa38e.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/metadata.csv",
    "content": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.0024509804789,0.0247104242444\ndeath_N,7,4,28,0.03708791360259,0.01668404601514\ndeath_S,7,4,28,-0.03708791360259,0.02683982625604\ndeath_W,7,4,28,-0.0024509804789,0.00800000037998\nslow_run_E,3,4,12,0.02066115662456,0.03703703731298\nslow_run_N,3,4,12,0.05296610295773,0.03892944008112\nslow_run_S,3,4,12,-0.05296610295773,0.04132231324911\nslow_run_W,3,4,12,-0.0227272734046,0.01975308731198\n"
  },
  {
    "path": "assets/creeps/orc/boss/metadata.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/creeps/orc/boss/slow_run_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4mbacosga5se\"\npath=\"res://.godot/imported/slow_run_E.png-c69c857798ed01fbae52b1ee1ce1bfb7.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/slow_run_E.png\"\ndest_files=[\"res://.godot/imported/slow_run_E.png-c69c857798ed01fbae52b1ee1ce1bfb7.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/slow_run_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dcrmib66n1i1k\"\npath=\"res://.godot/imported/slow_run_N.png-111c32155b5c29d535b778fc4aac8126.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/slow_run_N.png\"\ndest_files=[\"res://.godot/imported/slow_run_N.png-111c32155b5c29d535b778fc4aac8126.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/slow_run_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://be8at5qd2xtfm\"\npath=\"res://.godot/imported/slow_run_S.png-a4db344dfd61f46090e72e5ad01ce65d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/slow_run_S.png\"\ndest_files=[\"res://.godot/imported/slow_run_S.png-a4db344dfd61f46090e72e5ad01ce65d.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/boss/slow_run_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bf8mfmg7jkmv7\"\npath=\"res://.godot/imported/slow_run_W.png-29891121104a457bc9597ed407816504.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/boss/slow_run_W.png\"\ndest_files=[\"res://.godot/imported/slow_run_W.png-29891121104a457bc9597ed407816504.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/death_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://hdtvoqf7jppc\"\npath=\"res://.godot/imported/death_E.png-264e0b3527f43cc9ee2c3d19e5449977.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/death_E.png\"\ndest_files=[\"res://.godot/imported/death_E.png-264e0b3527f43cc9ee2c3d19e5449977.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/death_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bt0fnps8to5c5\"\npath=\"res://.godot/imported/death_N.png-ddb44c0beb23015b85914f1b2b5caca3.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/death_N.png\"\ndest_files=[\"res://.godot/imported/death_N.png-ddb44c0beb23015b85914f1b2b5caca3.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/death_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bn3cfvfeop2ni\"\npath=\"res://.godot/imported/death_S.png-785fc8f045c7836d8e6f69433bfe9a52.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/death_S.png\"\ndest_files=[\"res://.godot/imported/death_S.png-785fc8f045c7836d8e6f69433bfe9a52.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/death_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dvwut2d2wdqo3\"\npath=\"res://.godot/imported/death_W.png-843d4711109521e45ce22d3a8c8b4e4a.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/death_W.png\"\ndest_files=[\"res://.godot/imported/death_W.png-843d4711109521e45ce22d3a8c8b4e4a.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/metadata.csv",
    "content": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.01123595517129,0.02873563207686\ndeath_N,7,4,28,0.03983516618609,0.02857142873108\ndeath_S,7,4,28,-0.03983516618609,0.02562111802399\ndeath_W,7,4,28,-0.01256983261555,0.01769911497831\nslow_run_E,3,4,11,0.02884615398943,0.09278350323439\nslow_run_N,3,4,11,0.0619469024241,0.05309734493494\nslow_run_S,3,4,11,-0.06415928900242,0.09677419066429\nslow_run_W,3,4,11,-0.02884615398943,0.0343915335834\n"
  },
  {
    "path": "assets/creeps/orc/champion/metadata.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/creeps/orc/champion/slow_run_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ch7gt4062eyrj\"\npath=\"res://.godot/imported/slow_run_E.png-5e042dab8e48b6f7f2b686c1d96c96aa.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/slow_run_E.png\"\ndest_files=[\"res://.godot/imported/slow_run_E.png-5e042dab8e48b6f7f2b686c1d96c96aa.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/slow_run_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dxvx01jjvjcye\"\npath=\"res://.godot/imported/slow_run_N.png-908576826d3842ad636b58da3cc2cdba.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/slow_run_N.png\"\ndest_files=[\"res://.godot/imported/slow_run_N.png-908576826d3842ad636b58da3cc2cdba.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/slow_run_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d4cer5fkla46y\"\npath=\"res://.godot/imported/slow_run_S.png-ad8506743f28b251748745f913fe3d99.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/slow_run_S.png\"\ndest_files=[\"res://.godot/imported/slow_run_S.png-ad8506743f28b251748745f913fe3d99.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/champion/slow_run_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bvaegexu3foek\"\npath=\"res://.godot/imported/slow_run_W.png-5e50495e1cadd1e1295662512641b922.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/champion/slow_run_W.png\"\ndest_files=[\"res://.godot/imported/slow_run_W.png-5e50495e1cadd1e1295662512641b922.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/death_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c031gwyl83vsh\"\npath=\"res://.godot/imported/death_E.png-9dc1a44004fe64f399867a8543ccc454.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/death_E.png\"\ndest_files=[\"res://.godot/imported/death_E.png-9dc1a44004fe64f399867a8543ccc454.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/death_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://byqwfls7534ta\"\npath=\"res://.godot/imported/death_N.png-ce55fd128261c9b5e39c63a81fdc467c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/death_N.png\"\ndest_files=[\"res://.godot/imported/death_N.png-ce55fd128261c9b5e39c63a81fdc467c.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/death_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dc3ghqhhglmqi\"\npath=\"res://.godot/imported/death_S.png-2e0cf065ad00cd4bd4ce914f0bd89f62.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/death_S.png\"\ndest_files=[\"res://.godot/imported/death_S.png-2e0cf065ad00cd4bd4ce914f0bd89f62.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/death_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://e7syh2jbikvl\"\npath=\"res://.godot/imported/death_W.png-1482e917dc5941ddc64f7ebd417f3eb5.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/death_W.png\"\ndest_files=[\"res://.godot/imported/death_W.png-1482e917dc5941ddc64f7ebd417f3eb5.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/metadata.csv",
    "content": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.00811688322574,0.03686635941267\ndeath_N,7,4,28,0.04753521084785,0.03641456738114\ndeath_S,7,4,28,-0.04720279574394,0.03296703472733\ndeath_W,7,4,28,-0.00811688322574,0.03273809701204\nslow_run_E,4,4,15,-0.01904761977494,0.09946236759424\nslow_run_N,4,4,15,0.02250000089407,0.06683168560266\nslow_run_S,4,4,15,-0.02250000089407,0.08720929920673\nslow_run_W,4,4,15,0.0166666675359,0.05769230797887\n"
  },
  {
    "path": "assets/creeps/orc/mass/metadata.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/creeps/orc/mass/slow_run_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bd5vg4oke4m70\"\npath=\"res://.godot/imported/slow_run_E.png-00e8d6b22d05adfd5d5b1845c05ef5b9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/slow_run_E.png\"\ndest_files=[\"res://.godot/imported/slow_run_E.png-00e8d6b22d05adfd5d5b1845c05ef5b9.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/slow_run_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://jmweiopkc2gm\"\npath=\"res://.godot/imported/slow_run_N.png-5954a684074e9bb9932a855e111c1bb0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/slow_run_N.png\"\ndest_files=[\"res://.godot/imported/slow_run_N.png-5954a684074e9bb9932a855e111c1bb0.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/slow_run_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://beanme0cwvawx\"\npath=\"res://.godot/imported/slow_run_S.png-ec53181bea00d6ad1212d1f06fa283c2.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/slow_run_S.png\"\ndest_files=[\"res://.godot/imported/slow_run_S.png-ec53181bea00d6ad1212d1f06fa283c2.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/mass/slow_run_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c2kjqefq762mo\"\npath=\"res://.godot/imported/slow_run_W.png-ac846fbc63ff729e2e84fc71d9dade2e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/mass/slow_run_W.png\"\ndest_files=[\"res://.godot/imported/slow_run_W.png-ac846fbc63ff729e2e84fc71d9dade2e.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/death_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://3fls0dd5msho\"\npath=\"res://.godot/imported/death_E.png-dffb1c797eca92932030d3ba3bccd4f9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/death_E.png\"\ndest_files=[\"res://.godot/imported/death_E.png-dffb1c797eca92932030d3ba3bccd4f9.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/death_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ceyrhdt7hrlvb\"\npath=\"res://.godot/imported/death_N.png-bd4ca58a310659f9b742c10d73cde1ab.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/death_N.png\"\ndest_files=[\"res://.godot/imported/death_N.png-bd4ca58a310659f9b742c10d73cde1ab.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/death_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ca3nyf1hqvlca\"\npath=\"res://.godot/imported/death_S.png-e1edaf57585f154647b0323273736eb9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/death_S.png\"\ndest_files=[\"res://.godot/imported/death_S.png-e1edaf57585f154647b0323273736eb9.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/death_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://nh8ulueomejj\"\npath=\"res://.godot/imported/death_W.png-c55084ffb188dd9f834038a1f48b9919.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/death_W.png\"\ndest_files=[\"res://.godot/imported/death_W.png-c55084ffb188dd9f834038a1f48b9919.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/metadata.csv",
    "content": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.0441176481545,0.03763900697231\ndeath_N,7,4,28,0.08673469722271,0.01974448375404\ndeath_S,7,4,28,-0.08843537420034,0.03304178640246\ndeath_W,7,4,28,-0.0441176481545,0.01416765060276\nslow_run_E,3,4,11,0.05163043364882,0.05357142910361\nslow_run_N,3,4,11,0.0625,0.02820512838662\nslow_run_S,3,4,11,-0.0625,0.04927536100149\nslow_run_W,3,4,11,-0.05163043364882,0.01932367123663\n"
  },
  {
    "path": "assets/creeps/orc/normal/metadata.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/creeps/orc/normal/slow_run_E.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dby3igs0d3hvn\"\npath=\"res://.godot/imported/slow_run_E.png-f5e900f710737a553519da7dd216b9ae.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/slow_run_E.png\"\ndest_files=[\"res://.godot/imported/slow_run_E.png-f5e900f710737a553519da7dd216b9ae.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/slow_run_N.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bns6kclfij3yy\"\npath=\"res://.godot/imported/slow_run_N.png-db95e24d49388e97c6eee8932fc80331.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/slow_run_N.png\"\ndest_files=[\"res://.godot/imported/slow_run_N.png-db95e24d49388e97c6eee8932fc80331.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/slow_run_S.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bshgy2yv32i6a\"\npath=\"res://.godot/imported/slow_run_S.png-61a9061ca1e91513fd6ed867377e2ce9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/slow_run_S.png\"\ndest_files=[\"res://.godot/imported/slow_run_S.png-61a9061ca1e91513fd6ed867377e2ce9.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/creeps/orc/normal/slow_run_W.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://5hpj51wwf21h\"\npath=\"res://.godot/imported/slow_run_W.png-e63a404ac4857ba2c5efdc6df2c298dd.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/creeps/orc/normal/slow_run_W.png\"\ndest_files=[\"res://.godot/imported/slow_run_W.png-e63a404ac4857ba2c5efdc6df2c298dd.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.9\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/arrow.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://djotx5jk18gc0\"\npath=\"res://.godot/imported/arrow.png-99cbdffd0587db3a1398feef41169f3f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/arrow.png\"\ndest_files=[\"res://.godot/imported/arrow.png-99cbdffd0587db3a1398feef41169f3f.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/README.md",
    "content": "Assets in this folder CANNOT be shared.\nShare placeholders instead. Generate placeholders with generate_censored_assets.gd script.\n\nAssets in this folder were purchased from here:\nhttps://bdragon1727.itch.io/effect-and-fx-pixel-all\n"
  },
  {
    "path": "assets/effects/bdragon/ancient_protector_missile_293.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dwdvvm6bwoxfw\"\npath=\"res://.godot/imported/ancient_protector_missile_293.png-65c28db2d19ed797706e634a37c507fd.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/ancient_protector_missile_293.png\"\ndest_files=[\"res://.godot/imported/ancient_protector_missile_293.png-65c28db2d19ed797706e634a37c507fd.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/animated_dead_target_102.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4t5ody7wg6wa\"\npath=\"res://.godot/imported/animated_dead_target_102.png-377cf8c904353a46cd89ffb8630bfdd3.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/animated_dead_target_102.png\"\ndest_files=[\"res://.godot/imported/animated_dead_target_102.png-377cf8c904353a46cd89ffb8630bfdd3.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/apply_potion_537.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bvcsmcf7c2lf8\"\npath=\"res://.godot/imported/apply_potion_537.png-35b12a0cd764b81cba6eb59687eff642.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/apply_potion_537.png\"\ndest_files=[\"res://.godot/imported/apply_potion_537.png-35b12a0cd764b81cba6eb59687eff642.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/arcane_tower_attack_024.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4xwqnjdc1ipo\"\npath=\"res://.godot/imported/arcane_tower_attack_024.png-3c34fcadabf1aa922aad225fe5c748d1.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/arcane_tower_attack_024.png\"\ndest_files=[\"res://.godot/imported/arcane_tower_attack_024.png-3c34fcadabf1aa922aad225fe5c748d1.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/avatar_caster_10.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bpanfd3kpr8y7\"\npath=\"res://.godot/imported/avatar_caster_10.png-dc39185f902e530e565b71d7cbcec6dc.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/avatar_caster_10.png\"\ndest_files=[\"res://.godot/imported/avatar_caster_10.png-dc39185f902e530e565b71d7cbcec6dc.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/banshee_missile_487.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c1q82fl7tji4e\"\npath=\"res://.godot/imported/banshee_missile_487.png-25364a7a64fc77d9a6443c9690800fa2.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/banshee_missile_487.png\"\ndest_files=[\"res://.godot/imported/banshee_missile_487.png-25364a7a64fc77d9a6443c9690800fa2.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/blink_target_720.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://l77fhcp00n6l\"\npath=\"res://.godot/imported/blink_target_720.png-373f3596a65e32350f004bf02b34825c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/blink_target_720.png\"\ndest_files=[\"res://.godot/imported/blink_target_720.png-373f3596a65e32350f004bf02b34825c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/blood_splatter_376.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cueu6nx32scn\"\npath=\"res://.godot/imported/blood_splatter_376.png-7f27010f6bcca21d10d8b0ee3fccd1e8.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/blood_splatter_376.png\"\ndest_files=[\"res://.godot/imported/blood_splatter_376.png-7f27010f6bcca21d10d8b0ee3fccd1e8.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/build_tower_648.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dng7ptld4y130\"\npath=\"res://.godot/imported/build_tower_648.png-58be866426875f12a748a6e9c4ddad83.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/build_tower_648.png\"\ndest_files=[\"res://.godot/imported/build_tower_648.png-58be866426875f12a748a6e9c4ddad83.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/charm_target_703.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c75jmqs4u7hnv\"\npath=\"res://.godot/imported/charm_target_703.png-fdda3de7cd5c912e04ae90bac3cfc40b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/charm_target_703.png\"\ndest_files=[\"res://.godot/imported/charm_target_703.png-fdda3de7cd5c912e04ae90bac3cfc40b.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/cloud_of_fog_382.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dhm5njivfgxpo\"\npath=\"res://.godot/imported/cloud_of_fog_382.png-c3182a4f8f0667d26adfb41fb11cd5cf.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/cloud_of_fog_382.png\"\ndest_files=[\"res://.godot/imported/cloud_of_fog_382.png-c3182a4f8f0667d26adfb41fb11cd5cf.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/cloud_of_fog_small_428.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://m4w03jglmnu1\"\npath=\"res://.godot/imported/cloud_of_fog_small_428.png-76d40982730cadeb3682a93a6908a969.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/cloud_of_fog_small_428.png\"\ndest_files=[\"res://.godot/imported/cloud_of_fog_small_428.png-76d40982730cadeb3682a93a6908a969.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/cripple_target_198.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://crdvk0hy3x3px\"\npath=\"res://.godot/imported/cripple_target_198.png-c5605de932eb8ad13bbb8105ab5b5e28.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/cripple_target_198.png\"\ndest_files=[\"res://.godot/imported/cripple_target_198.png-c5605de932eb8ad13bbb8105ab5b5e28.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/crushing_wave_damage_584.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bxvpwc34g1fgw\"\npath=\"res://.godot/imported/crushing_wave_damage_584.png-c9804596a517e29b5079d3f9defbe24e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/crushing_wave_damage_584.png\"\ndest_files=[\"res://.godot/imported/crushing_wave_damage_584.png-c9804596a517e29b5079d3f9defbe24e.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/crypt_fiend_eggsack_528.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cvu38ecsot0h2\"\npath=\"res://.godot/imported/crypt_fiend_eggsack_528.png-1ca22185124c171b94a83c7d65ccfb4d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/crypt_fiend_eggsack_528.png\"\ndest_files=[\"res://.godot/imported/crypt_fiend_eggsack_528.png-1ca22185124c171b94a83c7d65ccfb4d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/cyclone_target_269.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d4e4pstgsefwc\"\npath=\"res://.godot/imported/cyclone_target_269.png-f29718d39ccddd934c0d1d1b15e26308.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/cyclone_target_269.png\"\ndest_files=[\"res://.godot/imported/cyclone_target_269.png-f29718d39ccddd934c0d1d1b15e26308.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/death_and_decay_71.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c8w3beqtm72u\"\npath=\"res://.godot/imported/death_and_decay_71.png-65d4ac1b4e00f637ae99e31618a3bf61.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/death_and_decay_71.png\"\ndest_files=[\"res://.godot/imported/death_and_decay_71.png-65d4ac1b4e00f637ae99e31618a3bf61.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/death_coil_special_728.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cbmu8xdosr3xw\"\npath=\"res://.godot/imported/death_coil_special_728.png-03171112b76393eeb34f217b2c2e9e92.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/death_coil_special_728.png\"\ndest_files=[\"res://.godot/imported/death_coil_special_728.png-03171112b76393eeb34f217b2c2e9e92.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/devour_509.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dqligfo47vxn1\"\npath=\"res://.godot/imported/devour_509.png-75d34b4b3d86cf7837f479bfb37ad01f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/devour_509.png\"\ndest_files=[\"res://.godot/imported/devour_509.png-75d34b4b3d86cf7837f479bfb37ad01f.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/dispel_magic_target_456.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://e2i8sa520qes\"\npath=\"res://.godot/imported/dispel_magic_target_456.png-8efd1ca3347782a6529ec0d17044da1c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/dispel_magic_target_456.png\"\ndest_files=[\"res://.godot/imported/dispel_magic_target_456.png-8efd1ca3347782a6529ec0d17044da1c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/doom_death_451.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b7j12e3p73bqd\"\npath=\"res://.godot/imported/doom_death_451.png-84643a3b3df5b123c45566d65804f1da.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/doom_death_451.png\"\ndest_files=[\"res://.godot/imported/doom_death_451.png-84643a3b3df5b123c45566d65804f1da.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/faerie_dragon_missile_482.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cuavhpswhvx4s\"\npath=\"res://.godot/imported/faerie_dragon_missile_482.png-d8fa104bede468d143dbfe056107bacf.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/faerie_dragon_missile_482.png\"\ndest_files=[\"res://.godot/imported/faerie_dragon_missile_482.png-d8fa104bede468d143dbfe056107bacf.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/firelord_death_explode_77.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bcgbhwc4vii7u\"\npath=\"res://.godot/imported/firelord_death_explode_77.png-dcf923d9f26d051cbd6870878bd269cb.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/firelord_death_explode_77.png\"\ndest_files=[\"res://.godot/imported/firelord_death_explode_77.png-dcf923d9f26d051cbd6870878bd269cb.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/flame_strike_embers_702.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ddtif7hi5hsjr\"\npath=\"res://.godot/imported/flame_strike_embers_702.png-2c912b8c99cf626f1d38d25420d2a087.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/flame_strike_embers_702.png\"\ndest_files=[\"res://.godot/imported/flame_strike_embers_702.png-2c912b8c99cf626f1d38d25420d2a087.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/flower_aura_655.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c78vkmjgqto8v\"\npath=\"res://.godot/imported/flower_aura_655.png-437e1e3d289afcc9b150ff21d6b24fa4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/flower_aura_655.png\"\ndest_files=[\"res://.godot/imported/flower_aura_655.png-437e1e3d289afcc9b150ff21d6b24fa4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/frag_boom_spawn_426.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://yvx6sbavyr4p\"\npath=\"res://.godot/imported/frag_boom_spawn_426.png-71e74214f24744a9308bae5d82458ec0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/frag_boom_spawn_426.png\"\ndest_files=[\"res://.godot/imported/frag_boom_spawn_426.png-71e74214f24744a9308bae5d82458ec0.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/freezing_breath_519.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c22lkk5uieshi\"\npath=\"res://.godot/imported/freezing_breath_519.png-3f89f5a6cc5f7008bcb7f7adba8fbe1f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/freezing_breath_519.png\"\ndest_files=[\"res://.godot/imported/freezing_breath_519.png-3f89f5a6cc5f7008bcb7f7adba8fbe1f.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/frost_armor_damage_474.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ijncv7mjaq1q\"\npath=\"res://.godot/imported/frost_armor_damage_474.png-a6040bd03b51a4f2219728ac491f763c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/frost_armor_damage_474.png\"\ndest_files=[\"res://.godot/imported/frost_armor_damage_474.png-a6040bd03b51a4f2219728ac491f763c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/frost_bolt_missile_063.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cvxaisa1jliqu\"\npath=\"res://.godot/imported/frost_bolt_missile_063.png-7955576808a701f3e5ca470d0c5b93f3.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/frost_bolt_missile_063.png\"\ndest_files=[\"res://.godot/imported/frost_bolt_missile_063.png-7955576808a701f3e5ca470d0c5b93f3.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/glaive_746.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://204ebjk0432r\"\npath=\"res://.godot/imported/glaive_746.png-bb5fa659fdaf93a3c3e8c9958ef9a799.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/glaive_746.png\"\ndest_files=[\"res://.godot/imported/glaive_746.png-bb5fa659fdaf93a3c3e8c9958ef9a799.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/gold_credit_673.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://du2y31j6qbb5m\"\npath=\"res://.godot/imported/gold_credit_673.png-2313102d30c94ee6ff770be17db148f7.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/gold_credit_673.png\"\ndest_files=[\"res://.godot/imported/gold_credit_673.png-2313102d30c94ee6ff770be17db148f7.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/gold_credit_88.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bg6jx8tkf0t6l\"\npath=\"res://.godot/imported/gold_credit_88.png-cd7b586f9ba4cd1b5b00c55ebce14678.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/gold_credit_88.png\"\ndest_files=[\"res://.godot/imported/gold_credit_88.png-cd7b586f9ba4cd1b5b00c55ebce14678.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/healing_wave_target_453.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c56ujjaxdg1my\"\npath=\"res://.godot/imported/healing_wave_target_453.png-5795e531a9d57383fdb9abdeefd4133b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/healing_wave_target_453.png\"\ndest_files=[\"res://.godot/imported/healing_wave_target_453.png-5795e531a9d57383fdb9abdeefd4133b.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/holy_bolt_241.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bfnbtlckgbnfs\"\npath=\"res://.godot/imported/holy_bolt_241.png-f7645e49cc69bfc683a03657bf979fa2.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/holy_bolt_241.png\"\ndest_files=[\"res://.godot/imported/holy_bolt_241.png-f7645e49cc69bfc683a03657bf979fa2.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/immolation_damage_541.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://hyqt8yi512yh\"\npath=\"res://.godot/imported/immolation_damage_541.png-73096aec07498e9b72e8bf0682bd66aa.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/immolation_damage_541.png\"\ndest_files=[\"res://.godot/imported/immolation_damage_541.png-73096aec07498e9b72e8bf0682bd66aa.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/impale_hit_target_529.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://tnlbuwsjjav0\"\npath=\"res://.godot/imported/impale_hit_target_529.png-e3eb6919e8686517c3c32e75d0692a2f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/impale_hit_target_529.png\"\ndest_files=[\"res://.godot/imported/impale_hit_target_529.png-e3eb6919e8686517c3c32e75d0692a2f.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/impale_target_dust_025.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://brfqvsks7awtk\"\npath=\"res://.godot/imported/impale_target_dust_025.png-4ef8bf413f6636ec28db8e21a9b86922.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/impale_target_dust_025.png\"\ndest_files=[\"res://.godot/imported/impale_target_dust_025.png-4ef8bf413f6636ec28db8e21a9b86922.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/incinerate_76.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cujsekapgggit\"\npath=\"res://.godot/imported/incinerate_76.png-9a1cd277e72c4828f136e9b6db48cdb4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/incinerate_76.png\"\ndest_files=[\"res://.godot/imported/incinerate_76.png-9a1cd277e72c4828f136e9b6db48cdb4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/keeper_grove_missile_297.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ch2peil7lqosf\"\npath=\"res://.godot/imported/keeper_grove_missile_297.png-f0e83ca13fe0b90cef4ca1c6476a6495.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/keeper_grove_missile_297.png\"\ndest_files=[\"res://.godot/imported/keeper_grove_missile_297.png-f0e83ca13fe0b90cef4ca1c6476a6495.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/level_up_455.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://wspy8ha1qyck\"\npath=\"res://.godot/imported/level_up_455.png-cce1feeac8c9e3aa9fa359bd0eef1cbb.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/level_up_455.png\"\ndest_files=[\"res://.godot/imported/level_up_455.png-cce1feeac8c9e3aa9fa359bd0eef1cbb.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/mana_burn_target_388.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cgakg4s2ct3ru\"\npath=\"res://.godot/imported/mana_burn_target_388.png-3d644d061a2c46307118e895997054a5.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/mana_burn_target_388.png\"\ndest_files=[\"res://.godot/imported/mana_burn_target_388.png-3d644d061a2c46307118e895997054a5.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/mana_shield_026.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b01ug8hkohe4a\"\npath=\"res://.godot/imported/mana_shield_026.png-aee7c9432d8d791d673cda43ceff8d09.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/mana_shield_026.png\"\ndest_files=[\"res://.godot/imported/mana_shield_026.png-aee7c9432d8d791d673cda43ceff8d09.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/mass_teleport_caster_335.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ewm7nac57wox\"\npath=\"res://.godot/imported/mass_teleport_caster_335.png-acc742fcdd7a2b95d617bfdf6bffc36c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/mass_teleport_caster_335.png\"\ndest_files=[\"res://.godot/imported/mass_teleport_caster_335.png-acc742fcdd7a2b95d617bfdf6bffc36c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/mass_teleport_target_315.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://biy8bqpp0e7kj\"\npath=\"res://.godot/imported/mass_teleport_target_315.png-7151940381d0023df1f48e61a8667ffc.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/mass_teleport_target_315.png\"\ndest_files=[\"res://.godot/imported/mass_teleport_target_315.png-7151940381d0023df1f48e61a8667ffc.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/mirror_image_caster_711.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cdt55t8kxtqiq\"\npath=\"res://.godot/imported/mirror_image_caster_711.png-a7d045309451a6744f0b4ebd0a0a29af.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/mirror_image_caster_711.png\"\ndest_files=[\"res://.godot/imported/mirror_image_caster_711.png-a7d045309451a6744f0b4ebd0a0a29af.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/moonwell_target_584.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cxngu4anhtvk6\"\npath=\"res://.godot/imported/moonwell_target_584.png-709c45dc67fae62cd706875000decdce.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/moonwell_target_584.png\"\ndest_files=[\"res://.godot/imported/moonwell_target_584.png-709c45dc67fae62cd706875000decdce.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/ne_cancel_death_672.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bryrhw6t0k26o\"\npath=\"res://.godot/imported/ne_cancel_death_672.png-1ff24ea4b29f602da747ad5f6a37fc05.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/ne_cancel_death_672.png\"\ndest_files=[\"res://.godot/imported/ne_cancel_death_672.png-1ff24ea4b29f602da747ad5f6a37fc05.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/ne_death_612.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dbjenjgmw6cgt\"\npath=\"res://.godot/imported/ne_death_612.png-8c6440a9375a8bbf5c09a2fe76c7f184.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/ne_death_612.png\"\ndest_files=[\"res://.godot/imported/ne_death_612.png-8c6440a9375a8bbf5c09a2fe76c7f184.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/placeholder_481.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://8aycp6wxnpve\"\npath=\"res://.godot/imported/placeholder_481.png-38d1edbe73a3fcc1e115861261d76a65.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/placeholder_481.png\"\ndest_files=[\"res://.godot/imported/placeholder_481.png-38d1edbe73a3fcc1e115861261d76a65.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/polymorph_target_735.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dcfs2k3q3dixg\"\npath=\"res://.godot/imported/polymorph_target_735.png-70310d37c9f62e29993359a6ba36ba36.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/polymorph_target_735.png\"\ndest_files=[\"res://.godot/imported/polymorph_target_735.png-70310d37c9f62e29993359a6ba36ba36.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/projectile_explosion_299.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cyyax4tkjt7au\"\npath=\"res://.godot/imported/projectile_explosion_299.png-29c77f39984ac1215ff0ddf72807e622.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/projectile_explosion_299.png\"\ndest_files=[\"res://.godot/imported/projectile_explosion_299.png-29c77f39984ac1215ff0ddf72807e622.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/purge_buff_target_195.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dsvu05xjwic5g\"\npath=\"res://.godot/imported/purge_buff_target_195.png-f400b467c5d033df5b330eaeb9e87da4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/purge_buff_target_195.png\"\ndest_files=[\"res://.godot/imported/purge_buff_target_195.png-f400b467c5d033df5b330eaeb9e87da4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/quillspray_747.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cknypfqkfkgiq\"\npath=\"res://.godot/imported/quillspray_747.png-dc09b60bd32b06e3a2c7f956a8765b05.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/quillspray_747.png\"\ndest_files=[\"res://.godot/imported/quillspray_747.png-dc09b60bd32b06e3a2c7f956a8765b05.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/raise_skeleton_624.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dfwypnwsg3p3u\"\npath=\"res://.godot/imported/raise_skeleton_624.png-70f385cf446664dae3a0fe7fa470590b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/raise_skeleton_624.png\"\ndest_files=[\"res://.godot/imported/raise_skeleton_624.png-70f385cf446664dae3a0fe7fa470590b.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/replenish_mana_334.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cwembk4judxy3\"\npath=\"res://.godot/imported/replenish_mana_334.png-c039b3a01cbd22c54a0f3675e9eb113e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/replenish_mana_334.png\"\ndest_files=[\"res://.godot/imported/replenish_mana_334.png-c039b3a01cbd22c54a0f3675e9eb113e.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/revive_human_623.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c7ufux57uh5ua\"\npath=\"res://.godot/imported/revive_human_623.png-f46d1403d3c9a6fe194e5099cd0b6376.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/revive_human_623.png\"\ndest_files=[\"res://.godot/imported/revive_human_623.png-f46d1403d3c9a6fe194e5099cd0b6376.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/roar_506.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://un4kd4n5xqem\"\npath=\"res://.godot/imported/roar_506.png-d34e8770877fd8df2a97fb22bc3ebc25.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/roar_506.png\"\ndest_files=[\"res://.godot/imported/roar_506.png-d34e8770877fd8df2a97fb22bc3ebc25.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/roots_235.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ddh33dc161220\"\npath=\"res://.godot/imported/roots_235.png-978aec907112557e6327d950f86c80e0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/roots_235.png\"\ndest_files=[\"res://.godot/imported/roots_235.png-978aec907112557e6327d950f86c80e0.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/shackle_439.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cv8vncnltc5ta\"\npath=\"res://.godot/imported/shackle_439.png-96b6faf1fc58d93b9c537b86b9c27516.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/shackle_439.png\"\ndest_files=[\"res://.godot/imported/shackle_439.png-96b6faf1fc58d93b9c537b86b9c27516.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/shockwave_missile_440.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://btlx0a8g4015b\"\npath=\"res://.godot/imported/shockwave_missile_440.png-c94023be65887742595aa6585a9f3747.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/shockwave_missile_440.png\"\ndest_files=[\"res://.godot/imported/shockwave_missile_440.png-c94023be65887742595aa6585a9f3747.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/silence_area_611.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cetfk6yto1khh\"\npath=\"res://.godot/imported/silence_area_611.png-0a05318235a14d652fa7d94d9f61e454.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/silence_area_611.png\"\ndest_files=[\"res://.godot/imported/silence_area_611.png-0a05318235a14d652fa7d94d9f61e454.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/small_flame_spawn_240.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://caisjfsu3fyap\"\npath=\"res://.godot/imported/small_flame_spawn_240.png-89a1568648df91c86dca2053de80d77f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/small_flame_spawn_240.png\"\ndest_files=[\"res://.godot/imported/small_flame_spawn_240.png-89a1568648df91c86dca2053de80d77f.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_aiil_452.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dr841ukdn8762\"\npath=\"res://.godot/imported/spell_aiil_452.png-566ef09b1047d09ff4e168dbdb1a7031.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_aiil_452.png\"\ndest_files=[\"res://.godot/imported/spell_aiil_452.png-566ef09b1047d09ff4e168dbdb1a7031.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_ailb_723.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://0152qy55d5hs\"\npath=\"res://.godot/imported/spell_ailb_723.png-98c991f13e9f666e164136f59d237a5a.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_ailb_723.png\"\ndest_files=[\"res://.godot/imported/spell_ailb_723.png-98c991f13e9f666e164136f59d237a5a.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_aima_194.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://csiqjph81rdq8\"\npath=\"res://.godot/imported/spell_aima_194.png-36941d638a3ad3d83f34008b0138d268.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_aima_194.png\"\ndest_files=[\"res://.godot/imported/spell_aima_194.png-36941d638a3ad3d83f34008b0138d268.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_aire_174.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ne67yotbsow\"\npath=\"res://.godot/imported/spell_aire_174.png-737e5b64b85a7db70e3d254843e24e35.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_aire_174.png\"\ndest_files=[\"res://.godot/imported/spell_aire_174.png-737e5b64b85a7db70e3d254843e24e35.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_aiso_295.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://carq8d0wtr1pl\"\npath=\"res://.godot/imported/spell_aiso_295.png-3f491ee4ae5d8d1efc85455ee8d0f6ec.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_aiso_295.png\"\ndest_files=[\"res://.godot/imported/spell_aiso_295.png-3f491ee4ae5d8d1efc85455ee8d0f6ec.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_alim_136.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cxr4c28mmw4nn\"\npath=\"res://.godot/imported/spell_alim_136.png-b878218e48bce6cd48da0b6ce051dfe6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_alim_136.png\"\ndest_files=[\"res://.godot/imported/spell_alim_136.png-b878218e48bce6cd48da0b6ce051dfe6.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spell_breaker_target_613.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://gtoj6o1w8tv0\"\npath=\"res://.godot/imported/spell_breaker_target_613.png-6acd28a2c3d88d7bbf9d9ca3eea1948a.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spell_breaker_target_613.png\"\ndest_files=[\"res://.godot/imported/spell_breaker_target_613.png-6acd28a2c3d88d7bbf9d9ca3eea1948a.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/spirit_link_target_175.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://terakoeeqruj\"\npath=\"res://.godot/imported/spirit_link_target_175.png-05c7950a5e71257f6db35775714fe948.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/spirit_link_target_175.png\"\ndest_files=[\"res://.godot/imported/spirit_link_target_175.png-05c7950a5e71257f6db35775714fe948.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/stampede_missile_death_63.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bbmm2xf32v0tx\"\npath=\"res://.godot/imported/stampede_missile_death_63.png-8c10282d1e9f9963855e1636bc7221ef.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/stampede_missile_death_63.png\"\ndest_files=[\"res://.godot/imported/stampede_missile_death_63.png-8c10282d1e9f9963855e1636bc7221ef.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/starfall_target_257.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b7swdbv14utxv\"\npath=\"res://.godot/imported/starfall_target_257.png-1b56d75787c95bbaa9cac85b9d3c2814.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/starfall_target_257.png\"\ndest_files=[\"res://.godot/imported/starfall_target_257.png-1b56d75787c95bbaa9cac85b9d3c2814.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/thunder_clap_466.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://2dquk1ppfku0\"\npath=\"res://.godot/imported/thunder_clap_466.png-e05420b06888fc45f876bb6a9124836a.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/thunder_clap_466.png\"\ndest_files=[\"res://.godot/imported/thunder_clap_466.png-e05420b06888fc45f876bb6a9124836a.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/undead_dissipate_633.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://blekt36dlhmd2\"\npath=\"res://.godot/imported/undead_dissipate_633.png-a295fb868ee597e1620b051c3da98d65.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/undead_dissipate_633.png\"\ndest_files=[\"res://.godot/imported/undead_dissipate_633.png-a295fb868ee597e1620b051c3da98d65.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/upgrade_tower_016.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cpuu4w0gghqoe\"\npath=\"res://.godot/imported/upgrade_tower_016.png-0559855c764d667674b7f3e0994f13c0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/upgrade_tower_016.png\"\ndest_files=[\"res://.godot/imported/upgrade_tower_016.png-0559855c764d667674b7f3e0994f13c0.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/vampiric_aura_199.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b2nm17eb4jt7\"\npath=\"res://.godot/imported/vampiric_aura_199.png-a6dcd595c9ded0381035bddd9fe82e86.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/vampiric_aura_199.png\"\ndest_files=[\"res://.godot/imported/vampiric_aura_199.png-a6dcd595c9ded0381035bddd9fe82e86.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/voodoo_aura_182.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cktvui85usgvp\"\npath=\"res://.godot/imported/voodoo_aura_182.png-89dcf7f0368ac32bf4c3b53b8678cf44.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/voodoo_aura_182.png\"\ndest_files=[\"res://.godot/imported/voodoo_aura_182.png-89dcf7f0368ac32bf4c3b53b8678cf44.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/warstomp_caster_536.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://di3fq4jkhoq4y\"\npath=\"res://.godot/imported/warstomp_caster_536.png-402dcaabab50fe6f7bbc751578f5f5f5.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/warstomp_caster_536.png\"\ndest_files=[\"res://.godot/imported/warstomp_caster_536.png-402dcaabab50fe6f7bbc751578f5f5f5.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/wind_shear_559.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://4vi0ba0hi12o\"\npath=\"res://.godot/imported/wind_shear_559.png-7f9e93a433bd6ef8b1eb6919b04535f9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/wind_shear_559.png\"\ndest_files=[\"res://.godot/imported/wind_shear_559.png-7f9e93a433bd6ef8b1eb6919b04535f9.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/wisp_explode_003.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://pb01lu85dqby\"\npath=\"res://.godot/imported/wisp_explode_003.png-0567a53124f13884c25a97998cc29901.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/wisp_explode_003.png\"\ndest_files=[\"res://.godot/imported/wisp_explode_003.png-0567a53124f13884c25a97998cc29901.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/ziggurat_frost_missile_325.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bvvxqx0twqcdq\"\npath=\"res://.godot/imported/ziggurat_frost_missile_325.png-370702e9f9061efffbac9318fe26e9ff.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/ziggurat_frost_missile_325.png\"\ndest_files=[\"res://.godot/imported/ziggurat_frost_missile_325.png-370702e9f9061efffbac9318fe26e9ff.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/bdragon/zombify_target_274.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dtoev5csbiekv\"\npath=\"res://.godot/imported/zombify_target_274.png-1b8f8ccadb4b4151798e378b06390e0d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/bdragon/zombify_target_274.png\"\ndest_files=[\"res://.godot/imported/zombify_target_274.png-1b8f8ccadb4b4151798e378b06390e0d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/death_explode.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ctpc46l8ddp8n\"\npath=\"res://.godot/imported/death_explode.png-edc3b0e54b65598df0eb1fd82f365779.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/death_explode.png\"\ndest_files=[\"res://.godot/imported/death_explode.png-edc3b0e54b65598df0eb1fd82f365779.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/lightning_long.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dyle0v7ow0gxp\"\npath=\"res://.godot/imported/lightning_long.png-14ced16aabd01f8365389d2f97d5d144.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/lightning_long.png\"\ndest_files=[\"res://.godot/imported/lightning_long.png-14ced16aabd01f8365389d2f97d5d144.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/effects/stun.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bmtjm6qhm3rop\"\npath=\"res://.godot/imported/stun.png-707bd2a6d06d6d55e9972b0101ba3b6c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/effects/stun.png\"\ndest_files=[\"res://.godot/imported/stun.png-707bd2a6d06d6d55e9972b0101ba3b6c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/fonts/Friz Quadrata Std Medium.otf.import",
    "content": "[remap]\n\nimporter=\"font_data_dynamic\"\ntype=\"FontFile\"\nuid=\"uid://d1pnwehsosppo\"\npath=\"res://.godot/imported/Friz Quadrata Std Medium.otf-03c51957373724d72743f58a5facb7d4.fontdata\"\n\n[deps]\n\nsource_file=\"res://assets/fonts/Friz Quadrata Std Medium.otf\"\ndest_files=[\"res://.godot/imported/Friz Quadrata Std Medium.otf-03c51957373724d72743f58a5facb7d4.fontdata\"]\n\n[params]\n\nRendering=null\nantialiasing=1\ngenerate_mipmaps=false\ndisable_embedded_bitmaps=true\nmultichannel_signed_distance_field=false\nmsdf_pixel_range=8\nmsdf_size=48\nallow_system_fallback=true\nforce_autohinter=false\nhinting=1\nsubpixel_positioning=1\noversampling=0.0\nFallbacks=null\nfallbacks=[]\nCompress=null\ncompress=true\npreload=[{\n\"chars\": [],\n\"glyphs\": [],\n\"name\": \"New Configuration\",\n\"size\": Vector2i(16, 0)\n}]\nlanguage_support={}\nscript_support={}\nopentype_features={}\n"
  },
  {
    "path": "assets/fonts/NotoSansSC-Medium.ttf.import",
    "content": "[remap]\n\nimporter=\"font_data_dynamic\"\ntype=\"FontFile\"\nuid=\"uid://b230565e8xtmg\"\npath=\"res://.godot/imported/NotoSansSC-Medium.ttf-b9fc0864eb5f89a2c92385a10052b365.fontdata\"\n\n[deps]\n\nsource_file=\"res://assets/fonts/NotoSansSC-Medium.ttf\"\ndest_files=[\"res://.godot/imported/NotoSansSC-Medium.ttf-b9fc0864eb5f89a2c92385a10052b365.fontdata\"]\n\n[params]\n\nRendering=null\nantialiasing=1\ngenerate_mipmaps=false\ndisable_embedded_bitmaps=true\nmultichannel_signed_distance_field=false\nmsdf_pixel_range=8\nmsdf_size=48\nallow_system_fallback=true\nforce_autohinter=false\nhinting=1\nsubpixel_positioning=1\noversampling=0.0\nFallbacks=null\nfallbacks=[]\nCompress=null\ncompress=true\npreload=[]\nlanguage_support={}\nscript_support={}\nopentype_features={}\n"
  },
  {
    "path": "assets/hud/bitmaps/circle_bitmap_100x100.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://tuxggwvj4o35\"\npath=\"res://.godot/imported/circle_bitmap_100x100.png-bf46af8672f9a767fc102d74b89baec0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/bitmaps/circle_bitmap_100x100.png\"\ndest_files=[\"res://.godot/imported/circle_bitmap_100x100.png-bf46af8672f9a767fc102d74b89baec0.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=100\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/bitmaps/circle_bitmap_256x256.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cbw3opxuts8mj\"\npath=\"res://.godot/imported/circle_bitmap_256x256.png-60c863ea557e8cf21dc7c84a6a00ee28.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/bitmaps/circle_bitmap_256x256.png\"\ndest_files=[\"res://.godot/imported/circle_bitmap_256x256.png-60c863ea557e8cf21dc7c84a6a00ee28.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/checkbox.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bxfq60uwqny4m\"\npath=\"res://.godot/imported/checkbox.png-cd08795d80678e62dd1fb0c25a010db2.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/checkbox.png\"\ndest_files=[\"res://.godot/imported/checkbox.png-cd08795d80678e62dd1fb0c25a010db2.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/circle_bitmap_256x256.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dsbsuq1mmtbwf\"\npath=\"res://.godot/imported/circle_bitmap_256x256.png-ac3a2d5381f13fd491a557611fb3e37d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/circle_bitmap_256x256.png\"\ndest_files=[\"res://.godot/imported/circle_bitmap_256x256.png-ac3a2d5381f13fd491a557611fb3e37d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/darkness_face.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b3s3mtb8efipi\"\npath=\"res://.godot/imported/darkness_face.png-a8fbc63b52d50a58ff7f7a758041cdde.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/darkness_face.png\"\ndest_files=[\"res://.godot/imported/darkness_face.png-a8fbc63b52d50a58ff7f7a758041cdde.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/element_progress_circle.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b36lpf5pdifac\"\npath=\"res://.godot/imported/element_progress_circle.png-8d5f0de567ea9d6a868603bbaa0790ee.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/element_progress_circle.png\"\ndest_files=[\"res://.godot/imported/element_progress_circle.png-8d5f0de567ea9d6a868603bbaa0790ee.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=74\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/horadric_cube.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://h5ppp14fvtrd\"\npath=\"res://.godot/imported/horadric_cube.png-2f402def575690efb22ed1e7b8c89a6d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/horadric_cube.png\"\ndest_files=[\"res://.godot/imported/horadric_cube.png-2f402def575690efb22ed1e7b8c89a6d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/hud_atlas.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dl22jvey8l5fo\"\npath=\"res://.godot/imported/hud_atlas.png-13eda0025b5f6ee873f6f3637b9101e5.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/hud_atlas.png\"\ndest_files=[\"res://.godot/imported/hud_atlas.png-13eda0025b5f6ee873f6f3637b9101e5.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=false\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=0\n"
  },
  {
    "path": "assets/hud/misc2.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bf7g834206kwo\"\npath=\"res://.godot/imported/misc2.png-890572f0fc34999780c41904afd4404d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/misc2.png\"\ndest_files=[\"res://.godot/imported/misc2.png-890572f0fc34999780c41904afd4404d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/misc3.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://60qc7jcvckhh\"\npath=\"res://.godot/imported/misc3.png-6f960d748cab1cbc68f85b99090cb0a6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/misc3.png\"\ndest_files=[\"res://.godot/imported/misc3.png-6f960d748cab1cbc68f85b99090cb0a6.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/misc3_s.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dyixmgwifdsin\"\npath=\"res://.godot/imported/misc3_s.png-1b5ebc68a5d9911d5fc1e91468a556eb.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/misc3_s.png\"\ndest_files=[\"res://.godot/imported/misc3_s.png-1b5ebc68a5d9911d5fc1e91468a556eb.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=256\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/misc4.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dfuxtb0pn0imr\"\npath=\"res://.godot/imported/misc4.png-3ad3fc9d533f1d69708f2cc4197b4b12.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/misc4.png\"\ndest_files=[\"res://.godot/imported/misc4.png-3ad3fc9d533f1d69708f2cc4197b4b12.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/hud/tranquility_face.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://mglwvt681k5r\"\npath=\"res://.godot/imported/tranquility_face.png-ef7d42e4a9d3f6f289ee50ce2d7e38fe.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/hud/tranquility_face.png\"\ndest_files=[\"res://.godot/imported/tranquility_face.png-ef7d42e4a9d3f6f289ee50ce2d7e38fe.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/amulets.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4f2vpcxem3iv\"\npath=\"res://.godot/imported/amulets.png-051b207025b2583cec72e8102504a488.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/amulets.png\"\ndest_files=[\"res://.godot/imported/amulets.png-051b207025b2583cec72e8102504a488.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/animals.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dqw2twgahvt7e\"\npath=\"res://.godot/imported/animals.png-a90142dc66bef90bd6076ad2dc72aab2.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/animals.png\"\ndest_files=[\"res://.godot/imported/animals.png-a90142dc66bef90bd6076ad2dc72aab2.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/armor.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://jy45uwdi1vwj\"\npath=\"res://.godot/imported/armor.png-cd0de3e584bc414792dc7177f7f97118.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/armor.png\"\ndest_files=[\"res://.godot/imported/armor.png-cd0de3e584bc414792dc7177f7f97118.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/blunt_weapons.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dxmouedtoclok\"\npath=\"res://.godot/imported/blunt_weapons.png-7b9ea6b62cce999e3e545ed73bf1c3cf.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/blunt_weapons.png\"\ndest_files=[\"res://.godot/imported/blunt_weapons.png-7b9ea6b62cce999e3e545ed73bf1c3cf.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/books.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://nr8ilug8etwa\"\npath=\"res://.godot/imported/books.png-726925d6b4b22dbff3bf219250ae0234.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/books.png\"\ndest_files=[\"res://.godot/imported/books.png-726925d6b4b22dbff3bf219250ae0234.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/bows.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dxiunk1cedalv\"\npath=\"res://.godot/imported/bows.png-53a4347f99dd5b87ac5f0c3bb40b078c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/bows.png\"\ndest_files=[\"res://.godot/imported/bows.png-53a4347f99dd5b87ac5f0c3bb40b078c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/cannons.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://hogt7wr0i6l6\"\npath=\"res://.godot/imported/cannons.png-34832a984cdcea78ed619abf862a1e01.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/cannons.png\"\ndest_files=[\"res://.godot/imported/cannons.png-34832a984cdcea78ed619abf862a1e01.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/clubs.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cd0wrsaa54yr8\"\npath=\"res://.godot/imported/clubs.png-1bd22b0911ad1df45c92e96dca6a39b6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/clubs.png\"\ndest_files=[\"res://.godot/imported/clubs.png-1bd22b0911ad1df45c92e96dca6a39b6.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/creep_icons_atlas.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://du5qunspl0v8d\"\npath=\"res://.godot/imported/creep_icons_atlas.png-4ae58f281663738ea82f2b91fe888884.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/creep_icons_atlas.png\"\ndest_files=[\"res://.godot/imported/creep_icons_atlas.png-4ae58f281663738ea82f2b91fe888884.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/daggers.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cwi67assrjmbr\"\npath=\"res://.godot/imported/daggers.png-486c40db59fcb43e602597436e4d9831.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/daggers.png\"\ndest_files=[\"res://.godot/imported/daggers.png-486c40db59fcb43e602597436e4d9831.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/dioramas.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://eahfoqydhmx8\"\npath=\"res://.godot/imported/dioramas.png-6a018a1ee4f5af3a65403e9b50ba2c9e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/dioramas.png\"\ndest_files=[\"res://.godot/imported/dioramas.png-6a018a1ee4f5af3a65403e9b50ba2c9e.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/electricity.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bdka8ghpv2c3r\"\npath=\"res://.godot/imported/electricity.png-73e32cda17a31d5f7094c70a17cdb4db.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/electricity.png\"\ndest_files=[\"res://.godot/imported/electricity.png-73e32cda17a31d5f7094c70a17cdb4db.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/elements.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://0eoqagd75i7k\"\npath=\"res://.godot/imported/elements.png-09a0570a984be624e4ee5e1d6739c7ac.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/elements.png\"\ndest_files=[\"res://.godot/imported/elements.png-09a0570a984be624e4ee5e1d6739c7ac.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/faces.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://pgeupu5vkown\"\npath=\"res://.godot/imported/faces.png-222fb277717d179e5b0a4cbe9a11996c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/faces.png\"\ndest_files=[\"res://.godot/imported/faces.png-222fb277717d179e5b0a4cbe9a11996c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/fire.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bkmpa3c1h7ylk\"\npath=\"res://.godot/imported/fire.png-cdd3b042c4e81029acb50aa6c378ee44.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/fire.png\"\ndest_files=[\"res://.godot/imported/fire.png-cdd3b042c4e81029acb50aa6c378ee44.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/food.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://versamdrv1pb\"\npath=\"res://.godot/imported/food.png-a1c28a6dd50da97a046be3406361130d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/food.png\"\ndest_files=[\"res://.godot/imported/food.png-a1c28a6dd50da97a046be3406361130d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/furniture.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dw1wnm1xtm8d3\"\npath=\"res://.godot/imported/furniture.png-c9eb4015a9c1192aa8190aeaa95d614a.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/furniture.png\"\ndest_files=[\"res://.godot/imported/furniture.png-c9eb4015a9c1192aa8190aeaa95d614a.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/gems.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cnt12q0n2qpou\"\npath=\"res://.godot/imported/gems.png-5a3fb8dba9b6a66d37d51de4e0d731dd.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/gems.png\"\ndest_files=[\"res://.godot/imported/gems.png-5a3fb8dba9b6a66d37d51de4e0d731dd.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/generic_icons.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bjf87xc5r8rig\"\npath=\"res://.godot/imported/generic_icons.png-344abc48e5501c560fc3bb8a046a4c71.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/generic_icons.png\"\ndest_files=[\"res://.godot/imported/generic_icons.png-344abc48e5501c560fc3bb8a046a4c71.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/gloves.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dnqge0ttmsxhg\"\npath=\"res://.godot/imported/gloves.png-2dadf642a9610aa2f315e2eb12fbf950.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/gloves.png\"\ndest_files=[\"res://.godot/imported/gloves.png-2dadf642a9610aa2f315e2eb12fbf950.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/helmets.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c5xyjl0m53xv0\"\npath=\"res://.godot/imported/helmets.png-07f86f332b9991f65ac637a4ef6880a9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/helmets.png\"\ndest_files=[\"res://.godot/imported/helmets.png-07f86f332b9991f65ac637a4ef6880a9.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/holy.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cj5n47n5k4p46\"\npath=\"res://.godot/imported/holy.png-95e0d9546e030a88370e6732ffbd8880.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/holy.png\"\ndest_files=[\"res://.godot/imported/holy.png-95e0d9546e030a88370e6732ffbd8880.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/hud.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bwcmn5v70q23p\"\npath=\"res://.godot/imported/hud.png-437a5395e9f9cd3a1d347638bc1852e4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/hud.png\"\ndest_files=[\"res://.godot/imported/hud.png-437a5395e9f9cd3a1d347638bc1852e4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/magic.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://6r3vtu5yr06v\"\npath=\"res://.godot/imported/magic.png-357799945309946521a1f4546b0acdfa.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/magic.png\"\ndest_files=[\"res://.godot/imported/magic.png-357799945309946521a1f4546b0acdfa.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/masks.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dbusfslop4dph\"\npath=\"res://.godot/imported/masks.png-9ba6cffa75f7cc4450f31b0483562c7c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/masks.png\"\ndest_files=[\"res://.godot/imported/masks.png-9ba6cffa75f7cc4450f31b0483562c7c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/mechanical.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ceq6tdm7gc1tw\"\npath=\"res://.godot/imported/mechanical.png-85c180bc37f14e77b13402027662097e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/mechanical.png\"\ndest_files=[\"res://.godot/imported/mechanical.png-85c180bc37f14e77b13402027662097e.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/misc.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://5mmfa2rctix6\"\npath=\"res://.godot/imported/misc.png-2b55a18b81e1ab97cbaa37ef482ac6d4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/misc.png\"\ndest_files=[\"res://.godot/imported/misc.png-2b55a18b81e1ab97cbaa37ef482ac6d4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/orbs.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cqgh5nkwvbvbg\"\npath=\"res://.godot/imported/orbs.png-74d57a7af07d550496d27affa6fb4812.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/orbs.png\"\ndest_files=[\"res://.godot/imported/orbs.png-74d57a7af07d550496d27affa6fb4812.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/plants.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b3a12s53ygdfh\"\npath=\"res://.godot/imported/plants.png-71cbb3d2d84351a7b2ce75b73d813a4e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/plants.png\"\ndest_files=[\"res://.godot/imported/plants.png-71cbb3d2d84351a7b2ce75b73d813a4e.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/potion_icons_m.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://p1qub7re6sdg\"\npath=\"res://.godot/imported/potion_icons_m.png-d3420473d0451e3ec86ded0997a5853d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/potion_icons_m.png\"\ndest_files=[\"res://.godot/imported/potion_icons_m.png-d3420473d0451e3ec86ded0997a5853d.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/rings.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ujgb13e5v2s8\"\npath=\"res://.godot/imported/rings.png-c5d7d36b0d6991dfb9ab896943f67ff4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/rings.png\"\ndest_files=[\"res://.godot/imported/rings.png-c5d7d36b0d6991dfb9ab896943f67ff4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/rockets.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cu33x7mcwrwhh\"\npath=\"res://.godot/imported/rockets.png-9bfb3eb347975ecf147d84018f5f50a9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/rockets.png\"\ndest_files=[\"res://.godot/imported/rockets.png-9bfb3eb347975ecf147d84018f5f50a9.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/scrolls.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d4f11knnb7xlr\"\npath=\"res://.godot/imported/scrolls.png-1f526dc079ce2041ba7f6c64e7665e28.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/scrolls.png\"\ndest_files=[\"res://.godot/imported/scrolls.png-1f526dc079ce2041ba7f6c64e7665e28.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/shields.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://wty1fqppvwo4\"\npath=\"res://.godot/imported/shields.png-c2ab6423158132834f33cb511b9dbd7c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/shields.png\"\ndest_files=[\"res://.godot/imported/shields.png-c2ab6423158132834f33cb511b9dbd7c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/spears.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://btgpo8wni6hc7\"\npath=\"res://.godot/imported/spears.png-e42a1474bfa3b8c7a53a75c87fa658a0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/spears.png\"\ndest_files=[\"res://.godot/imported/spears.png-e42a1474bfa3b8c7a53a75c87fa658a0.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/statues.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d1awjrjgaxq71\"\npath=\"res://.godot/imported/statues.png-81fc1519aa8b01a85f1fd79734c79cb7.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/statues.png\"\ndest_files=[\"res://.godot/imported/statues.png-81fc1519aa8b01a85f1fd79734c79cb7.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/staves.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cl7c26i3sw0e\"\npath=\"res://.godot/imported/staves.png-e20fe976cfa353c5ff423ee088a8ddb4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/staves.png\"\ndest_files=[\"res://.godot/imported/staves.png-e20fe976cfa353c5ff423ee088a8ddb4.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/swords.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d1wqk36oa6jix\"\npath=\"res://.godot/imported/swords.png-40d34ac19ec04c04c34cb35a24c959d3.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/swords.png\"\ndest_files=[\"res://.godot/imported/swords.png-40d34ac19ec04c04c34cb35a24c959d3.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/tier_icons_m.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bxlxlgnldo7ci\"\npath=\"res://.godot/imported/tier_icons_m.png-c36122fe75c9827dd5ec9dbbbb1a7d94.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/tier_icons_m.png\"\ndest_files=[\"res://.godot/imported/tier_icons_m.png-c36122fe75c9827dd5ec9dbbbb1a7d94.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=448\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/tower_icons_m.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://de76st4td7ff1\"\npath=\"res://.godot/imported/tower_icons_m.png-a0ab18c700246cd62a4f06aeb9ff97d9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/tower_icons_m.png\"\ndest_files=[\"res://.godot/imported/tower_icons_m.png-a0ab18c700246cd62a4f06aeb9ff97d9.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=false\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/tower_variations.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cqf21oho5q27w\"\npath=\"res://.godot/imported/tower_variations.png-fd1ba94c8f02dfa6fb3cba944012cafd.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/tower_variations.png\"\ndest_files=[\"res://.godot/imported/tower_variations.png-fd1ba94c8f02dfa6fb3cba944012cafd.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/trinkets.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://brf81bkx3v35k\"\npath=\"res://.godot/imported/trinkets.png-482605a7c407e43326801e4c443ba8bb.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/trinkets.png\"\ndest_files=[\"res://.godot/imported/trinkets.png-482605a7c407e43326801e4c443ba8bb.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/undead.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cavgrswpec0v7\"\npath=\"res://.godot/imported/undead.png-70e6a3e594c3edeb42faab9a2c307519.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/undead.png\"\ndest_files=[\"res://.godot/imported/undead.png-70e6a3e594c3edeb42faab9a2c307519.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/icons/weapons_misc.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dwjw6jt0jadwx\"\npath=\"res://.godot/imported/weapons_misc.png-21c850b12f704a28617989658155576c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/icons/weapons_misc.png\"\ndest_files=[\"res://.godot/imported/weapons_misc.png-21c850b12f704a28617989658155576c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/autocast_automode_particle.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ce6k2v2g5l88d\"\npath=\"res://.godot/imported/autocast_automode_particle.png-deddd02e06b837af2de105c9341deb34.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/autocast_automode_particle.png\"\ndest_files=[\"res://.godot/imported/autocast_automode_particle.png-deddd02e06b837af2de105c9341deb34.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/cast_cursor.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://buks8ou7od1lw\"\npath=\"res://.godot/imported/cast_cursor.png-c9263ef33b3393264247fb6818812593.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/cast_cursor.png\"\ndest_files=[\"res://.godot/imported/cast_cursor.png-c9263ef33b3393264247fb6818812593.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/circle_01.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dl05rggm0meke\"\npath=\"res://.godot/imported/circle_01.png-ca62a21a67bc8435508f2e7b4be3b908.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/circle_01.png\"\ndest_files=[\"res://.godot/imported/circle_01.png-ca62a21a67bc8435508f2e7b4be3b908.ctex\"]\n\n[params]\n\ncompress/mode=1\ncompress/high_quality=false\ncompress/lossy_quality=0.5\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/circle_02.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dti6d2c71hvuh\"\npath=\"res://.godot/imported/circle_02.png-28369cd5de95e017314595d3c677c0ce.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/circle_02.png\"\ndest_files=[\"res://.godot/imported/circle_02.png-28369cd5de95e017314595d3c677c0ce.ctex\"]\n\n[params]\n\ncompress/mode=1\ncompress/high_quality=false\ncompress/lossy_quality=0.5\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/circle_03.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://uev086xwodkt\"\npath=\"res://.godot/imported/circle_03.png-b34fbea2b5773220bf077cb523b37353.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/circle_03.png\"\ndest_files=[\"res://.godot/imported/circle_03.png-b34fbea2b5773220bf077cb523b37353.ctex\"]\n\n[params]\n\ncompress/mode=1\ncompress/high_quality=false\ncompress/lossy_quality=0.5\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/circle_04.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dx62w7m5jucm5\"\npath=\"res://.godot/imported/circle_04.png-59f4641951225ce02bb76cfd4cec4df6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/circle_04.png\"\ndest_files=[\"res://.godot/imported/circle_04.png-59f4641951225ce02bb76cfd4cec4df6.ctex\"]\n\n[params]\n\ncompress/mode=1\ncompress/high_quality=false\ncompress/lossy_quality=0.5\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/circle_05.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cxl665kwsrclr\"\npath=\"res://.godot/imported/circle_05.png-fd9f043d14627c1ebf01a8234847e5f1.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/circle_05.png\"\ndest_files=[\"res://.godot/imported/circle_05.png-fd9f043d14627c1ebf01a8234847e5f1.ctex\"]\n\n[params]\n\ncompress/mode=1\ncompress/high_quality=false\ncompress/lossy_quality=0.5\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/creep_blood_pool.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bqfroocbty8l3\"\npath=\"res://.godot/imported/creep_blood_pool.png-19b67b5c1bd6b9b5ccb357eb5cd95aba.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/creep_blood_pool.png\"\ndest_files=[\"res://.godot/imported/creep_blood_pool.png-19b67b5c1bd6b9b5ccb357eb5cd95aba.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/icob_min.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d35sjqib45v7r\"\npath=\"res://.godot/imported/icob_min.png-64aae72b9e53523d3fbf5713ff96485c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/icob_min.png\"\ndest_files=[\"res://.godot/imported/icob_min.png-64aae72b9e53523d3fbf5713ff96485c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/icob_ultra_wide.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bpfx0lg44dqkv\"\npath=\"res://.godot/imported/icob_ultra_wide.png-9286abbed63dd9c66506beb02d5af5bf.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/icob_ultra_wide.png\"\ndest_files=[\"res://.godot/imported/icob_ultra_wide.png-9286abbed63dd9c66506beb02d5af5bf.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/icon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bte5c4ua8te4k\"\npath=\"res://.godot/imported/icon.png-499bd3f5b4dad40780d75fb801c9d623.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/icon.png\"\ndest_files=[\"res://.godot/imported/icon.png-499bd3f5b4dad40780d75fb801c9d623.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/potion_drop_animation.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dv3gw8u27ikmq\"\npath=\"res://.godot/imported/potion_drop_animation.png-b2725d1949b19d5249b6101c140d34cf.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/potion_drop_animation.png\"\ndest_files=[\"res://.godot/imported/potion_drop_animation.png-b2725d1949b19d5249b6101c140d34cf.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/misc/projectile.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cifmqgyviomde\"\npath=\"res://.godot/imported/projectile.png-adc602fc56a13cb71df34b50491d7bdc.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/misc/projectile.png\"\ndest_files=[\"res://.godot/imported/projectile.png-adc602fc56a13cb71df34b50491d7bdc.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/secrets/badwords.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/secrets/secrets.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/sfx/161654__qubodup__war-game-battle-level-up-remix.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://boas7idikati7\"\npath=\"res://.godot/imported/161654__qubodup__war-game-battle-level-up-remix.ogg-8cfd75614385387b36213f4c145c3d31.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/161654__qubodup__war-game-battle-level-up-remix.ogg\"\ndest_files=[\"res://.godot/imported/161654__qubodup__war-game-battle-level-up-remix.ogg-8cfd75614385387b36213f4c145c3d31.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/202147__qubodup__enchant.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cat5hodmh5446\"\npath=\"res://.godot/imported/202147__qubodup__enchant.ogg-a5ed0d7e0cf3509a1753c4c5b80657fc.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/202147__qubodup__enchant.ogg\"\ndest_files=[\"res://.godot/imported/202147__qubodup__enchant.ogg-a5ed0d7e0cf3509a1753c4c5b80657fc.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/411177__silverillusionist__pick-up-item-1-short.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dukf6xu53e0db\"\npath=\"res://.godot/imported/411177__silverillusionist__pick-up-item-1-short.ogg-875615ea054fd56d84ee307626a6e991.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/411177__silverillusionist__pick-up-item-1-short.ogg\"\ndest_files=[\"res://.godot/imported/411177__silverillusionist__pick-up-item-1-short.ogg-875615ea054fd56d84ee307626a6e991.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/420676__sypherzent__spell-cast-buff-high-tone.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cf7ffvtylohym\"\npath=\"res://.godot/imported/420676__sypherzent__spell-cast-buff-high-tone.ogg-8649831617fc6eeaafedf00066231b26.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/420676__sypherzent__spell-cast-buff-high-tone.ogg\"\ndest_files=[\"res://.godot/imported/420676__sypherzent__spell-cast-buff-high-tone.ogg-8649831617fc6eeaafedf00066231b26.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/442827__qubodup__fireball.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://b7lwjrggou2kv\"\npath=\"res://.godot/imported/442827__qubodup__fireball.ogg-ebc12706b1c8a1dba49bbc2bb1131aa5.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/442827__qubodup__fireball.ogg\"\ndest_files=[\"res://.godot/imported/442827__qubodup__fireball.ogg-ebc12706b1c8a1dba49bbc2bb1131aa5.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/442903__qubodup__slash-remix.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://c10n7ho755dxu\"\npath=\"res://.godot/imported/442903__qubodup__slash-remix.ogg-2877cae8ddfc59b8c618cafd7ff85474.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/442903__qubodup__slash-remix.ogg\"\ndest_files=[\"res://.godot/imported/442903__qubodup__slash-remix.ogg-2877cae8ddfc59b8c618cafd7ff85474.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/541478__eminyildirim__magic-fire-spell-impact-punch.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://fl8pjftexan8\"\npath=\"res://.godot/imported/541478__eminyildirim__magic-fire-spell-impact-punch.ogg-b90b68de21acd9ae863d5efffcaa275e.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/541478__eminyildirim__magic-fire-spell-impact-punch.ogg\"\ndest_files=[\"res://.godot/imported/541478__eminyildirim__magic-fire-spell-impact-punch.ogg-b90b68de21acd9ae863d5efffcaa275e.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/562292__colorscrimsontears__heal-rpg.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://f1xw57wa3jvk\"\npath=\"res://.godot/imported/562292__colorscrimsontears__heal-rpg.ogg-5a4d29867d1f5372328b9fb13c2e14af.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/562292__colorscrimsontears__heal-rpg.ogg\"\ndest_files=[\"res://.godot/imported/562292__colorscrimsontears__heal-rpg.ogg-5a4d29867d1f5372328b9fb13c2e14af.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/649359__sonofxaudio__sword_water01.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://d1b7tmol4fpme\"\npath=\"res://.godot/imported/649359__sonofxaudio__sword_water01.ogg-2ee53fa40a7a637dec602919b7e0e966.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/649359__sonofxaudio__sword_water01.ogg\"\ndest_files=[\"res://.godot/imported/649359__sonofxaudio__sword_water01.ogg-2ee53fa40a7a637dec602919b7e0e966.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/665082__sunflora__thud.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dqhaaqr6h11oq\"\npath=\"res://.godot/imported/665082__sunflora__thud.ogg-3ffa0097b7161761f91c94876592ca89.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/665082__sunflora__thud.ogg\"\ndest_files=[\"res://.godot/imported/665082__sunflora__thud.ogg-3ffa0097b7161761f91c94876592ca89.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/682635__bastianhallo__magic-spell.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://ceonp35ykslsh\"\npath=\"res://.godot/imported/682635__bastianhallo__magic-spell.ogg-74f68da981d9509dd37522dd10ab21d6.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/682635__bastianhallo__magic-spell.ogg\"\ndest_files=[\"res://.godot/imported/682635__bastianhallo__magic-spell.ogg-74f68da981d9509dd37522dd10ab21d6.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/683044__brettrader__stomp-soft.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://q73606mwn1d6\"\npath=\"res://.godot/imported/683044__brettrader__stomp-soft.ogg-b0653818a0aeff384040e8c1883e571d.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/683044__brettrader__stomp-soft.ogg\"\ndest_files=[\"res://.godot/imported/683044__brettrader__stomp-soft.ogg-b0653818a0aeff384040e8c1883e571d.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/714258__qubodup__cloud-poof.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bauku4fjq5y86\"\npath=\"res://.godot/imported/714258__qubodup__cloud-poof.ogg-c47c54d8ea51debdb990d398822b1522.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/714258__qubodup__cloud-poof.ogg\"\ndest_files=[\"res://.godot/imported/714258__qubodup__cloud-poof.ogg-c47c54d8ea51debdb990d398822b1522.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/734247__noisyredfox__coins3.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://ctr1i51w35voa\"\npath=\"res://.godot/imported/734247__noisyredfox__coins3.ogg-2fe9bdd29ce58525b1d13b4b42f61be4.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/734247__noisyredfox__coins3.ogg\"\ndest_files=[\"res://.godot/imported/734247__noisyredfox__coins3.ogg-2fe9bdd29ce58525b1d13b4b42f61be4.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/738438__qubodup__orc-grunt-2.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cf7jn4afjl12v\"\npath=\"res://.godot/imported/738438__qubodup__orc-grunt-2.ogg-3733b57e4d56b32dc97426489290cf23.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/738438__qubodup__orc-grunt-2.ogg\"\ndest_files=[\"res://.godot/imported/738438__qubodup__orc-grunt-2.ogg-3733b57e4d56b32dc97426489290cf23.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/745156__tigreplayz__blast-explosion.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://be4hv3ryg5pv\"\npath=\"res://.godot/imported/745156__tigreplayz__blast-explosion.ogg-9bc33b0619ff817b122663671e83a49c.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/745156__tigreplayz__blast-explosion.ogg\"\ndest_files=[\"res://.godot/imported/745156__tigreplayz__blast-explosion.ogg-9bc33b0619ff817b122663671e83a49c.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/DoKashiteru_healspell1.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cox8ng70mj42f\"\npath=\"res://.godot/imported/DoKashiteru_healspell1.ogg-155f868443489e01be6419011fa00b7d.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/DoKashiteru_healspell1.ogg\"\ndest_files=[\"res://.godot/imported/DoKashiteru_healspell1.ogg-155f868443489e01be6419011fa00b7d.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/DoKashiteru_healspell2.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://e2u3gcov2cxr\"\npath=\"res://.godot/imported/DoKashiteru_healspell2.ogg-3208172db3ccde3f3d8c890ab3f44e9d.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/DoKashiteru_healspell2.ogg\"\ndest_files=[\"res://.godot/imported/DoKashiteru_healspell2.ogg-3208172db3ccde3f3d8c890ab3f44e9d.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/DoKashiteru_healspell3.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://duowgd03o8l0\"\npath=\"res://.godot/imported/DoKashiteru_healspell3.ogg-532df5c6b29014405e84cfc08c2fc4e7.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/DoKashiteru_healspell3.ogg\"\ndest_files=[\"res://.godot/imported/DoKashiteru_healspell3.ogg-532df5c6b29014405e84cfc08c2fc4e7.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/README.md",
    "content": "Assets in this folder come from various sources.\nCheck attribution.csv for detailed info about attribution and licenses.\n"
  },
  {
    "path": "assets/sfx/UI_Electric_01.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://ce57fjmeceevl\"\npath=\"res://.godot/imported/UI_Electric_01.ogg-b61c9fb14f1925fefe5a636904f8dfa8.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/UI_Electric_01.ogg\"\ndest_files=[\"res://.godot/imported/UI_Electric_01.ogg-b61c9fb14f1925fefe5a636904f8dfa8.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/artisticdude_freeze.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://qajhfwnml7is\"\npath=\"res://.godot/imported/artisticdude_freeze.ogg-0b16ccbf9354cf119b5198a2ecf37c2c.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/artisticdude_freeze.ogg\"\ndest_files=[\"res://.godot/imported/artisticdude_freeze.ogg-0b16ccbf9354cf119b5198a2ecf37c2c.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/attribution.csv",
    "content": "\"filename\",\"attribution text\"\n\"kevl_level_up\",\"none\ncustom made in bfxr\"\n\"442903__qubodup__slash-remix\",\"Slash by qubodup -- https://freesound.org/s/442903/ -- License: Creative Commons 0  splat.ogg by gprosser -- https://freesound.org/s/360942/ -- License: Creative Commons 0  Bloody Blade 2.wav by Kreastricon62 -- https://freesound.org/s/323526/ -- License: Creative Commons 0\"\n\"161654__qubodup__war-game-battle-level-up-remix\",\"War Game Battle Level Up by qubodup -- https://freesound.org/s/161654/ -- License: Creative Commons 0  timp_rolls.flac by spt3125 -- https://freesound.org/s/24810/ -- License: Creative Commons 0\"\n\"202147__qubodup__enchant\",\"Enchant.flac by qubodup - https://freesound.org/people/qubodup/sounds/202147/ - License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\"\n\"442827__qubodup__fireball\",\"Fireball by qubodup -- https://freesound.org/s/442827/ -- License: Attribution 4.0  Short-Fireball-Woosh.flac by wjl -- https://freesound.org/s/267887/ -- License: Creative Commons 0  Match by qubodup -- https://freesound.org/s/171693/ -- License: Attribution 4.0  23 FIACCOLA PASS.aiff by lollosound -- https://freesound.org/s/124372/ -- License: Creative Commons 0  Dull Decompression Punch Impact Explodes 96kHz by qubodup -- https://freesound.org/s/71274/ -- License: Creative Commons 0\"\n\"714258__qubodup__cloud-poof\",\"Cloud Poof by qubodup -- https://freesound.org/s/714258/ -- License: Attribution 4.0  cloud-punch.wav by CaptainYulef -- https://freesound.org/s/641241/ -- License: Creative Commons 0  Gas Cloud.wav by puppetmaster685719 -- https://freesound.org/s/627733/ -- License: Creative Commons 0  Poof in cloud by Mateusz_Chenc -- https://freesound.org/s/512217/ -- License: Creative Commons 0  Poof.wav by ryansitz -- https://freesound.org/s/387834/ -- License: Creative Commons 0  explosionsfx.wav by OtisJames -- https://freesound.org/s/249613/ -- License: Creative Commons 0\"\n\"738438__qubodup__orc-grunt-2\",\"Orc Grunt 2 by qubodup -- https://freesound.org/s/738438/ - License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\"\n\"745156__tigreplayz__blast-explosion\",\"Blast / Explosion by TigrePlayz_ -- https://freesound.org/s/745156/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n\"734247__noisyredfox__coins3\",\"Coins3 by NoisyRedFox -- https://freesound.org/s/734247/ -- License: Creative Commons 0\"\n\"683044__brettrader__stomp-soft\",\"Stomp Soft by brettrader -- https://freesound.org/s/683044/ -- License: Creative Commons 0\"\n\"411177__silverillusionist__pick-up-item-1-short\",\"Pick up Item 1.wav by SilverIllusionist -- https://freesound.org/s/411177/ -- License: Attribution 4.0\"\n\"420676__sypherzent__spell-cast-buff-high-tone\",\"Spell Cast / Buff / High Tone by SypherZent - https://freesound.org/people/SypherZent/sounds/420676/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n\"541478__eminyildirim__magic-fire-spell-impact-punch\",\"Magic Fire Spell Impact & Punch by EminYILDIRIM - freesound.org/people/EminYILDIRIM/sounds/541478  License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\"\n\"562292__colorscrimsontears__heal-rpg\",\"Heal - Rpg by colorsCrimsonTears - https://freesound.org/s/562292/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n\"649359__sonofxaudio__sword_water01\",\"Sword_Water01.wav by SonoFxAudio - https://freesound.org/people/SonoFxAudio/sounds/649359/ - License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\"\n\"665082__sunflora__thud\",\"thud.mp3 by sunflora -- https://freesound.org/s/665082/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n\"682635__bastianhallo__magic-spell\",\"Magic spell by Bastianhallo -- https://freesound.org/s/682635/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n\"bart_foom_0\",\"Spell 4 (FIRE) by Bart K. -- https://opengameart.org/content/spell-4-fire -- License: Creative Commons 3\"\n\"unknown_attack_sound1\",\"unknown, probably from Sonniss GDC Bundle - https://sonniss.com/gameaudiogdc\"\n\"unknown_fire_attack1\",\"unknown, probably from Sonniss GDC Bundle - https://sonniss.com/gameaudiogdc\"\n\"unknown_iceball\",\"unknown, probably from Sonniss GDC Bundle - https://sonniss.com/gameaudiogdc\"\n\"unknown_iron_attack1\",\"unknown, probably from Sonniss GDC Bundle - https://sonniss.com/gameaudiogdc\"\n\"unknown_swosh-08\",\"unknown, probably from Sonniss GDC Bundle - https://sonniss.com/gameaudiogdc\"\n\"unknown_swosh-11\",\"unknown, probably from Sonniss GDC Bundle - https://sonniss.com/gameaudiogdc\"\n\"michel_baradari_jump\",\"3 Item sounds by Michel Baradari -- https://opengameart.org/content/3-item-sounds -- License: Creative Commons 3\"\n\"michel_baradari_lava\",\"Lava splash by Michel Baradari -  https://opengameart.org/content/lava-splash - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"michel_baradari_teleport\",\"teleport by Q009 - https://opengameart.org/content/q009s-weapon-sounds - License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"little_robot_Spell_00\",\"Fantasy Sound Effects Library by Little Robot Sound Factory -  https://opengameart.org/content/fantasy-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_Spell_01\",\"Fantasy Sound Effects Library by Little Robot Sound Factory -  https://opengameart.org/content/fantasy-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_Whoosh_Electric_00\",\"Electric Sound Effects Library by Little Robot Sound Factory - https://opengameart.org/cntent/electric-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_Whoosh_Electric_01\",\"Electric Sound Effects Library by Little Robot Sound Factory - https://opengameart.org/cntent/electric-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_Whoosh_Electric_02\",\"Electric Sound Effects Library by Little Robot Sound Factory - https://opengameart.org/cntent/electric-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_Whoosh_Electric_03\",\"Electric Sound Effects Library by Little Robot Sound Factory - https://opengameart.org/cntent/electric-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_UI_Electric_00\",\"Electric Sound Effects Library by Little Robot Sound Factory - https://opengameart.org/cntent/electric-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"little_robot_UI_Electric_01\",\"Electric Sound Effects Library by Little Robot Sound Factory - https://opengameart.org/cntent/electric-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\"\n\"copyc4t_Archers-shooting\",\"Archers shooting by copyc4t (Paolo D'Emilio) - https://opengameart.org/content/archers-shooting - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\nThis work is an adaption of other works below:\nbow_sound.wav by Anton -- https://freesound.org/s/54/ -- License: Attribution 4.0\nSwosh / Whoosh / Air Cut by qubodup -- https://freesound.org/s/60030/ -- License: Creative Commons 0\nBow Releases.wav by Benboncan -- https://freesound.org/s/85019/ -- License: Attribution 4.0\"\n\"DoKashiteru_healspell1\",\"3 Heal Spells by DoKashiteru - https://opengameart.org/content/3-heal-spells - License: CC BY (https://creativecommons.org/licenses/by/3.0/)\"\n\"DoKashiteru_healspell2\",\"3 Heal Spells by DoKashiteru - https://opengameart.org/content/3-heal-spells - License: CC BY (https://creativecommons.org/licenses/by/3.0/)\"\n\"DoKashiteru_healspell3\",\"3 Heal Spells by DoKashiteru - https://opengameart.org/content/3-heal-spells - License: CC BY (https://creativecommons.org/licenses/by/3.0/)\"\n\"artisticdude_freeze\",\"Freeze Spell by artisticdude - https://opengameart.org/content/freeze-spell-0 - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n\"p0ss_steam\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_teleport\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_warp\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_warp2\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_water\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_zap\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_zap5a\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_zap10\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_confusion\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_curse5\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_enchant\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_enchant2\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_explode2\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_explode4\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_freeze2\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_heal\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_magicfail\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_pestilence\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_sand\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_shot\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_spell\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"p0ss_spring\",\"Spell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack  License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\"\n\"spit_01\",\"80 CC0 creature SFX by rubberduck - https://opengameart.org/content/80-cc0-creature-sfx - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\"\n"
  },
  {
    "path": "assets/sfx/attribution.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/sfx/bart_foom_0.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dhgg4hhjtpmr8\"\npath=\"res://.godot/imported/bart_foom_0.ogg-92e2988ad20e68b6715e0f209356dca1.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/bart_foom_0.ogg\"\ndest_files=[\"res://.godot/imported/bart_foom_0.ogg-92e2988ad20e68b6715e0f209356dca1.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/copyc4t_Archers-shooting.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://disrfrcxt12le\"\npath=\"res://.godot/imported/copyc4t_Archers-shooting.ogg-ba08aa1ca05d0816e5cd30ce6380c490.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/copyc4t_Archers-shooting.ogg\"\ndest_files=[\"res://.godot/imported/copyc4t_Archers-shooting.ogg-ba08aa1ca05d0816e5cd30ce6380c490.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/kevl_level_up.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://fvbx7h3gqv0n\"\npath=\"res://.godot/imported/kevl_level_up.ogg-12d27a351342dd413211a06bf7638cef.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/kevl_level_up.ogg\"\ndest_files=[\"res://.godot/imported/kevl_level_up.ogg-12d27a351342dd413211a06bf7638cef.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_Spell_00.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://etrud7n8wc43\"\npath=\"res://.godot/imported/little_robot_Spell_00.ogg-2563ec9d32b75ff5ce59f2f8ed10fca7.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_Spell_00.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_Spell_00.ogg-2563ec9d32b75ff5ce59f2f8ed10fca7.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_Spell_01.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://base5ksqlqvmq\"\npath=\"res://.godot/imported/little_robot_Spell_01.ogg-f7f311e3773489fc4253e4208ca5d242.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_Spell_01.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_Spell_01.ogg-f7f311e3773489fc4253e4208ca5d242.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_UI_Electric_00.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dvyraxl7plp5j\"\npath=\"res://.godot/imported/little_robot_UI_Electric_00.ogg-243302e4de81c64e315a85976f454112.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_UI_Electric_00.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_UI_Electric_00.ogg-243302e4de81c64e315a85976f454112.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_UI_Electric_01.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bu2wllrq03af0\"\npath=\"res://.godot/imported/little_robot_UI_Electric_01.ogg-bfbc7c237a1726c4d936a5f42fa0bd96.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_UI_Electric_01.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_UI_Electric_01.ogg-bfbc7c237a1726c4d936a5f42fa0bd96.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_Whoosh_Electric_00.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dr1weqneahltb\"\npath=\"res://.godot/imported/little_robot_Whoosh_Electric_00.ogg-a0e7f5270729fb766da6b46055f1e9d9.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_Whoosh_Electric_00.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_Whoosh_Electric_00.ogg-a0e7f5270729fb766da6b46055f1e9d9.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_Whoosh_Electric_01.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bdkv8rgngxj4u\"\npath=\"res://.godot/imported/little_robot_Whoosh_Electric_01.ogg-fef4b3f90a733fa9c80a47cf701c3371.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_Whoosh_Electric_01.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_Whoosh_Electric_01.ogg-fef4b3f90a733fa9c80a47cf701c3371.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_Whoosh_Electric_02.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://4b6t0uhcf4ka\"\npath=\"res://.godot/imported/little_robot_Whoosh_Electric_02.ogg-0b07215769e4661476c532d5a1cda0fc.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_Whoosh_Electric_02.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_Whoosh_Electric_02.ogg-0b07215769e4661476c532d5a1cda0fc.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/little_robot_Whoosh_Electric_03.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://drv7odffoyxli\"\npath=\"res://.godot/imported/little_robot_Whoosh_Electric_03.ogg-146d7317a9ed01b0489ce149e186dfc9.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/little_robot_Whoosh_Electric_03.ogg\"\ndest_files=[\"res://.godot/imported/little_robot_Whoosh_Electric_03.ogg-146d7317a9ed01b0489ce149e186dfc9.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/machel_baradari_jump.wav.import",
    "content": "[remap]\n\nimporter=\"wav\"\ntype=\"AudioStreamWAV\"\nuid=\"uid://bduealmibuh85\"\npath=\"res://.godot/imported/machel_baradari_jump.wav-5715097f212213662c28f77f6dd721f9.sample\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/machel_baradari_jump.wav\"\ndest_files=[\"res://.godot/imported/machel_baradari_jump.wav-5715097f212213662c28f77f6dd721f9.sample\"]\n\n[params]\n\nforce/8_bit=false\nforce/mono=false\nforce/max_rate=false\nforce/max_rate_hz=44100\nedit/trim=false\nedit/normalize=false\nedit/loop_mode=0\nedit/loop_begin=0\nedit/loop_end=-1\ncompress/mode=0\n"
  },
  {
    "path": "assets/sfx/michel_baradari_jump.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://de4ft67yma3p6\"\npath=\"res://.godot/imported/michel_baradari_jump.ogg-d05a3e1b59b0156e4de018ef07bee12d.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/michel_baradari_jump.ogg\"\ndest_files=[\"res://.godot/imported/michel_baradari_jump.ogg-d05a3e1b59b0156e4de018ef07bee12d.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/michel_baradari_jump.wav.import",
    "content": "[remap]\n\nimporter=\"wav\"\ntype=\"AudioStreamWAV\"\nuid=\"uid://rc05tb37xs6x\"\npath=\"res://.godot/imported/michel_baradari_jump.wav-fee899c94baf0ad271b2ab5543595891.sample\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/michel_baradari_jump.wav\"\ndest_files=[\"res://.godot/imported/michel_baradari_jump.wav-fee899c94baf0ad271b2ab5543595891.sample\"]\n\n[params]\n\nforce/8_bit=false\nforce/mono=false\nforce/max_rate=false\nforce/max_rate_hz=44100\nedit/trim=false\nedit/normalize=false\nedit/loop_mode=0\nedit/loop_begin=0\nedit/loop_end=-1\ncompress/mode=0\n"
  },
  {
    "path": "assets/sfx/michel_baradari_lava.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cpc66xggsayen\"\npath=\"res://.godot/imported/michel_baradari_lava.ogg-5d88ec9d637ff9040cee627ecf295d2e.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/michel_baradari_lava.ogg\"\ndest_files=[\"res://.godot/imported/michel_baradari_lava.ogg-5d88ec9d637ff9040cee627ecf295d2e.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/michel_baradari_teleport.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://uplb454n0n1v\"\npath=\"res://.godot/imported/michel_baradari_teleport.ogg-485cc9c1af4b8b2dc5b50ced77fb0b22.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/michel_baradari_teleport.ogg\"\ndest_files=[\"res://.godot/imported/michel_baradari_teleport.ogg-485cc9c1af4b8b2dc5b50ced77fb0b22.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_confusion.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://en4v1uflji65\"\npath=\"res://.godot/imported/p0ss_confusion.ogg-10ba2f44a22d3e0428587c6cf8a6d8af.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_confusion.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_confusion.ogg-10ba2f44a22d3e0428587c6cf8a6d8af.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_curse5.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bk8uslc4b2m4u\"\npath=\"res://.godot/imported/p0ss_curse5.ogg-5cd0ba5e46b51b9298aadd91834f16ed.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_curse5.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_curse5.ogg-5cd0ba5e46b51b9298aadd91834f16ed.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_enchant.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://crjtg5v88bhlh\"\npath=\"res://.godot/imported/p0ss_enchant.ogg-c3ee814f7e1b991e22718bf75770050c.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_enchant.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_enchant.ogg-c3ee814f7e1b991e22718bf75770050c.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_enchant2.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://lqrjoow1so5l\"\npath=\"res://.godot/imported/p0ss_enchant2.ogg-55b3e5fca4b1001df1a7ba1396ad01cb.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_enchant2.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_enchant2.ogg-55b3e5fca4b1001df1a7ba1396ad01cb.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_explode2.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://ccq2kq8imnl2a\"\npath=\"res://.godot/imported/p0ss_explode2.ogg-4a1083bc7797735f515132b9e5d1c020.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_explode2.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_explode2.ogg-4a1083bc7797735f515132b9e5d1c020.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_explode4.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://btalvah0y0jgo\"\npath=\"res://.godot/imported/p0ss_explode4.ogg-963f187df3a5f18f1cf8bddc5b802857.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_explode4.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_explode4.ogg-963f187df3a5f18f1cf8bddc5b802857.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_freeze2.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dje6ex1qm15a8\"\npath=\"res://.godot/imported/p0ss_freeze2.ogg-0fda7ed45da95e2352957c60e1983324.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_freeze2.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_freeze2.ogg-0fda7ed45da95e2352957c60e1983324.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_heal.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://brl13c0a5luxg\"\npath=\"res://.godot/imported/p0ss_heal.ogg-4d48639c5cf8ddb9caeeaa0025a19803.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_heal.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_heal.ogg-4d48639c5cf8ddb9caeeaa0025a19803.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_pestilence.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bn7o6phvua2km\"\npath=\"res://.godot/imported/p0ss_pestilence.ogg-ed2fcbe774bbaabf8edfcba978c5db70.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_pestilence.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_pestilence.ogg-ed2fcbe774bbaabf8edfcba978c5db70.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_sand.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dou7gblwp382h\"\npath=\"res://.godot/imported/p0ss_sand.ogg-6f41fa28f9a791912dcd6a0ba59c576f.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_sand.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_sand.ogg-6f41fa28f9a791912dcd6a0ba59c576f.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_shot.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://v28ufp7k5mwo\"\npath=\"res://.godot/imported/p0ss_shot.ogg-7c2b60026fc7b4094dd3889aef19ed7d.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_shot.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_shot.ogg-7c2b60026fc7b4094dd3889aef19ed7d.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_spell.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://gcl6x3bkyvvy\"\npath=\"res://.godot/imported/p0ss_spell.ogg-490d199f5f04f771988a4ec170d18bc3.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_spell.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_spell.ogg-490d199f5f04f771988a4ec170d18bc3.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_steam.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bpwvdjquknogv\"\npath=\"res://.godot/imported/p0ss_steam.ogg-7c9b5c6cfb94e8978f85d289e3385ee3.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_steam.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_steam.ogg-7c9b5c6cfb94e8978f85d289e3385ee3.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_teleport.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cwh6wv2vb61n6\"\npath=\"res://.godot/imported/p0ss_teleport.ogg-7e092e7fc61eba82fc9429aea4ab310e.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_teleport.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_teleport.ogg-7e092e7fc61eba82fc9429aea4ab310e.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_warp.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://be4vqrfr26ow\"\npath=\"res://.godot/imported/p0ss_warp.ogg-5ea133d05fab93d473a2f1b37f107de8.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_warp.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_warp.ogg-5ea133d05fab93d473a2f1b37f107de8.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_warp2.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://wr5ah4b4v2ji\"\npath=\"res://.godot/imported/p0ss_warp2.ogg-551346c8559ae26d7dc7d40236c81a47.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_warp2.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_warp2.ogg-551346c8559ae26d7dc7d40236c81a47.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_warp3.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://q0rdb6he1swy\"\npath=\"res://.godot/imported/p0ss_warp3.ogg-b0b1688303acca5e6194584cebdef15c.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_warp3.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_warp3.ogg-b0b1688303acca5e6194584cebdef15c.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_water.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://b5tunwmuyhn5l\"\npath=\"res://.godot/imported/p0ss_water.ogg-2b039c9495fee01c16ba4bf2466c61d0.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_water.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_water.ogg-2b039c9495fee01c16ba4bf2466c61d0.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_zap.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cy5ktht6ikmbg\"\npath=\"res://.godot/imported/p0ss_zap.ogg-391e61ce022753528d5e23c08d214240.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_zap.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_zap.ogg-391e61ce022753528d5e23c08d214240.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_zap10.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://c2ll1spotf6hw\"\npath=\"res://.godot/imported/p0ss_zap10.ogg-7589ce075b58c2f73b0c9706bea5f71c.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_zap10.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_zap10.ogg-7589ce075b58c2f73b0c9706bea5f71c.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/p0ss_zap5a.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://d3nnfgj2yjp6s\"\npath=\"res://.godot/imported/p0ss_zap5a.ogg-37ba665e817bfa45f2b9748600cda020.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/p0ss_zap5a.ogg\"\ndest_files=[\"res://.godot/imported/p0ss_zap5a.ogg-37ba665e817bfa45f2b9748600cda020.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/spit_01.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://c3fvell6kfceb\"\npath=\"res://.godot/imported/spit_01.ogg-59ff5392a07564ecc2ad5510ee3af3cf.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/spit_01.ogg\"\ndest_files=[\"res://.godot/imported/spit_01.ogg-59ff5392a07564ecc2ad5510ee3af3cf.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/unknown_attack_sound1.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://c1iuui177vsyu\"\npath=\"res://.godot/imported/unknown_attack_sound1.ogg-2647f8432f067b9600b0d876154b9f5f.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/unknown_attack_sound1.ogg\"\ndest_files=[\"res://.godot/imported/unknown_attack_sound1.ogg-2647f8432f067b9600b0d876154b9f5f.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/unknown_fire_attack1.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://d0hkbi724i3qx\"\npath=\"res://.godot/imported/unknown_fire_attack1.ogg-fa6f5e44d2e14af509964d14111b7c40.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/unknown_fire_attack1.ogg\"\ndest_files=[\"res://.godot/imported/unknown_fire_attack1.ogg-fa6f5e44d2e14af509964d14111b7c40.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/unknown_iceball.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://dstoyeckjihrw\"\npath=\"res://.godot/imported/unknown_iceball.ogg-68b59d9db417c0de0245ed7781244885.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/unknown_iceball.ogg\"\ndest_files=[\"res://.godot/imported/unknown_iceball.ogg-68b59d9db417c0de0245ed7781244885.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/unknown_iron_attack1.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://xenue2eclugg\"\npath=\"res://.godot/imported/unknown_iron_attack1.ogg-504dd4f58970312a866eae9d27c6c316.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/unknown_iron_attack1.ogg\"\ndest_files=[\"res://.godot/imported/unknown_iron_attack1.ogg-504dd4f58970312a866eae9d27c6c316.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/unknown_swosh-08.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://bypiqd4u02124\"\npath=\"res://.godot/imported/unknown_swosh-08.ogg-95f71be5d308c789b2615232c90db562.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/unknown_swosh-08.ogg\"\ndest_files=[\"res://.godot/imported/unknown_swosh-08.ogg-95f71be5d308c789b2615232c90db562.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/sfx/unknown_swosh-11.ogg.import",
    "content": "[remap]\n\nimporter=\"oggvorbisstr\"\ntype=\"AudioStreamOggVorbis\"\nuid=\"uid://cw3rqxuxxo3jm\"\npath=\"res://.godot/imported/unknown_swosh-11.ogg-034b3b77e11ded1504978b18d7443c8a.oggvorbisstr\"\n\n[deps]\n\nsource_file=\"res://assets/sfx/unknown_swosh-11.ogg\"\ndest_files=[\"res://.godot/imported/unknown_swosh-11.ogg-034b3b77e11ded1504978b18d7443c8a.oggvorbisstr\"]\n\n[params]\n\nloop=false\nloop_offset=0\nbpm=0\nbeat_count=0\nbar_beats=4\n"
  },
  {
    "path": "assets/texts/README.md",
    "content": "texts.csv is not uploaded to Github because it's too big and pollutes commit history.\n\nInstead, it's on Google Drive.\n\ntexts_history.csv should be updated when accepting new contributions to translations.\n"
  },
  {
    "path": "assets/texts/texts.csv.import",
    "content": "[remap]\n\nimporter=\"csv_translation\"\ntype=\"Translation\"\nuid=\"uid://b4mco2dr478ww\"\n\n[deps]\n\nfiles=[\"res://assets/texts/texts.en.translation\", \"res://assets/texts/texts.zh.translation\", \"res://assets/texts/texts.it.translation\"]\n\nsource_file=\"res://assets/texts/texts.csv\"\ndest_files=[\"res://assets/texts/texts.en.translation\", \"res://assets/texts/texts.zh.translation\", \"res://assets/texts/texts.it.translation\"]\n\n[params]\n\ncompress=true\ndelimiter=0\n"
  },
  {
    "path": "assets/texts/texts_history.csv",
    "content": "\"date\",\"author\",\"affected text IDs\",\"change description\"\n\"22.02.2025\",\"kevl\",\"All\",\"Created texts.csv\"\n\"17.03.2025\",\"lamess233\",\"DTJQ-HZB1\",\"Add partial Chinese translations for testing purposes, cn localization version 0.1.\"\n\"19.03.2025\",\"kevl\",\"DTJQ-F78J(removed),Z3E3-LB0T(added)\",\"Changed how item ability texts are stored. Created new text ids at the end of the file.\"\n\"19.03.2025\",\"lamess233\",\"K9TP-BO2P\",\"Added translations for all tower and item information.\"\n\"20.03.2025\",\"kevl\",\"V23I,DUJG,V4LB,LFYO,Y2WT,9PSU\",\"Fixed mismatched bracket characters.\"\n\"22.03.2025\",\"kevl\",\"TCH4-XI2Z\",\"Added untranslated texts for buff tooltips in tower scripts.\"\n\"23.03.2025\",\"kevl\",\"MESSAGE_WELCOME_1-COMMAND_RANGE_CHECK_DISABLE\",\"Added untranslated texts for messages, error messages and chat command texts.\"\n\"23.03.2025\",\"kevl\",\"YQK4-OEII\",\"Added untranslated texts for multiboard labels.\"\n\"24.03.2025\",\"lichcay\",\"START_BUTTON - GAME_STATUS_BUILDER\",\"Changed cn->zh to match with locale string. Added translations for texts in scene files.\"\n\"26.03.2025\",\"kevl\",\"TOWER_ATTACK_ABILITY_TITLE - UPGRADE_TOWER_BUTTON_CANNOT_UPGRADE\",\"Add untranslated texts from all script files, except for tower/item scripts.\"\n\"29.03.2025\",\"kevl\",\"UEGM - E2IZ\",\"Add untranslated texts for all floating texts.\"\n\"31.03.2025\",\"lamess233\",\"Many ID's affect - no specific range\",\"Chinese translation. Fixed issues in existing texts. Translated some new texts.\"\n\"01.04.2025\",\"lamess233\",\"MESSAGE_WELCOME_1 - PROFILE_MENU_IMPORTED_EXP_PASSWORD\",\"Chinese translation. Translate more texts.\"\n\"02.04.2025\",\"kevl\",\"ITEM_TYPE_FILTER_ALL - UNIT_MENU_TOOLTIP_SELL\",\"Add untranslated texts from UI tooltips.\"\n\"16.04.2025\",\"lamess233\",\"A5EN - RTAD, MESSAGE_DONT_HAVE_TOWER - UNIT_MENU_TOOLTIP_SELL\",\"Chinese translation. Translated the majority of remaining descriptive texts. Adjust some existing translations.\"\n\"20.04.2025\",\"kevl\",\"OKJ6 - Z2BY\",\"Reduce number of duplicated texts in tower descriptions.\"\n\"18.06.2025\",\"kevl\",\"Item tooltips\",\"Fix issues with missing newlines in 'level bonus' sections of item tooltips\"\n\"02.10.2025\",\"PiotrKaszuba\",\"WU10 - WU23, WISDOM_EFFECTIVENESS_BONUS\",\"Add texts for new wisdom upgrades and wisdom efficiency text label.\"\n\"08.11.2025\",\"kevl\",\"9RU3\",\"Fix tooltip for Goblin Alchemist builder - it had incorrect number for debuff duration.\"\n\"08.11.2025\",\"C4lut\",\"A5EN-T6VW,KJ25-V8DH\",\"Add first translations for Italian language.\"\n\"15.11.2025\",\"C4lut\",\"Misc\",\"Add more translations for Italian language.\"\n\"05.12.2025\",\"C4lut\",\"Misc\",\"Add more translations for Italian language. Fixed issues in previous translations.\"\n\"28.12.2025\",\"C4lut\",\"Misc\",\"Add more translations for Italian language.\"\n\"05.01.2026\",\"C4lut\",\"Misc\",\"Add more translations for Italian language.\""
  },
  {
    "path": "assets/texts/texts_history.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "assets/tiles/License.txt",
    "content": "\t\r\n\r\n\tDungeon Pack (2.3)\r\n\r\n\tCreated/distributed by Kenney (www.kenney.nl)\r\n\tCreation date: 15-02-2019 00:58\r\n\r\n\t\t\t------------------------------\r\n\r\n\tLicense: (Creative Commons Zero, CC0)\r\n\thttp://creativecommons.org/publicdomain/zero/1.0/\r\n\r\n\tThis content is free to use in personal, educational and commercial projects.\r\r\n\tSupport us by crediting Kenney or www.kenney.nl (this is not mandatory)\r\n\r\n\t\t\t------------------------------\r\n\r\n\tDonate:   http://support.kenney.nl\r\n\tRequest:  http://request.kenney.nl\r\n\tPatreon:  http://patreon.com/kenney/\r\n\r\n\tFollow on Twitter for updates:\r\n\thttp://twitter.com/KenneyNL"
  },
  {
    "path": "assets/tiles/README.md",
    "content": "This folder contains assets created by Kenney.\n\nSee \"License.txt\" in the same folder for the original license.\n"
  },
  {
    "path": "assets/tiles/barrels.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b8kaotwoawygm\"\npath=\"res://.godot/imported/barrels.png-3d3d22b9ea92fdebe1e1edf49c79c063.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/barrels.png\"\ndest_files=[\"res://.godot/imported/barrels.png-3d3d22b9ea92fdebe1e1edf49c79c063.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/bridges.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://8hg2mltwjvch\"\npath=\"res://.godot/imported/bridges.png-cbff1ccfe1a68b1386af562d58e4368b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/bridges.png\"\ndest_files=[\"res://.godot/imported/bridges.png-cbff1ccfe1a68b1386af562d58e4368b.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/chairs.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://q44p2wsjevl8\"\npath=\"res://.godot/imported/chairs.png-23652b1f5ed7dbe311d8b39e44d0e0ea.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/chairs.png\"\ndest_files=[\"res://.godot/imported/chairs.png-23652b1f5ed7dbe311d8b39e44d0e0ea.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/chests.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://no8l70qh6xxf\"\npath=\"res://.godot/imported/chests.png-ac5b76aed6ea4e4731f7514829706cf5.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/chests.png\"\ndest_files=[\"res://.godot/imported/chests.png-ac5b76aed6ea4e4731f7514829706cf5.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/empty_tiles.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://2v03j2bnie6o\"\npath=\"res://.godot/imported/empty_tiles.png-270af29da1c53c6b3abf5a5a2cd15ca6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/empty_tiles.png\"\ndest_files=[\"res://.godot/imported/empty_tiles.png-270af29da1c53c6b3abf5a5a2cd15ca6.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/floor.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://28he7nw8q1lo\"\npath=\"res://.godot/imported/floor.png-efbbb20e6adf7962c1762f769191b326.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/floor.png\"\ndest_files=[\"res://.godot/imported/floor.png-efbbb20e6adf7962c1762f769191b326.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/floor1_walls.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bq4bfj6wa7488\"\npath=\"res://.godot/imported/floor1_walls.png-c7dafbbc68939bf9e2ada9f012342611.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/floor1_walls.png\"\ndest_files=[\"res://.godot/imported/floor1_walls.png-c7dafbbc68939bf9e2ada9f012342611.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/planks.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bb3cy5nc11xm4\"\npath=\"res://.godot/imported/planks.png-ce6ddf8ce0b825caa4d788287315e8a6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/planks.png\"\ndest_files=[\"res://.godot/imported/planks.png-ce6ddf8ce0b825caa4d788287315e8a6.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/spiral_stairs.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ct1fnt7hxgi4o\"\npath=\"res://.godot/imported/spiral_stairs.png-71a9d80b3d0f24662ec94b47ea62b071.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/spiral_stairs.png\"\ndest_files=[\"res://.godot/imported/spiral_stairs.png-71a9d80b3d0f24662ec94b47ea62b071.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/stairs.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c2ui4kf3f3fnc\"\npath=\"res://.godot/imported/stairs.png-752f5eae91ad99bc659fda9d5287961c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/stairs.png\"\ndest_files=[\"res://.godot/imported/stairs.png-752f5eae91ad99bc659fda9d5287961c.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/stone_columns.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dbh4ut425s1ja\"\npath=\"res://.godot/imported/stone_columns.png-dd923b9fdab47b86a7397d53c657ba88.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/stone_columns.png\"\ndest_files=[\"res://.godot/imported/stone_columns.png-dd923b9fdab47b86a7397d53c657ba88.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/stone_walls.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://m7awn68i621a\"\npath=\"res://.godot/imported/stone_walls.png-a122419319c396eebe959ca05a4d046c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/stone_walls.png\"\ndest_files=[\"res://.godot/imported/stone_walls.png-a122419319c396eebe959ca05a4d046c.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/tables.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://qy7lhcabenwy\"\npath=\"res://.godot/imported/tables.png-9b508ac0a3b7f8d7234c6cb02d0f1091.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/tables.png\"\ndest_files=[\"res://.godot/imported/tables.png-9b508ac0a3b7f8d7234c6cb02d0f1091.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/wooden_pile.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b1jfa4r4faj77\"\npath=\"res://.godot/imported/wooden_pile.png-86ccf43fa54558980e28758787a9da4b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/wooden_pile.png\"\ndest_files=[\"res://.godot/imported/wooden_pile.png-86ccf43fa54558980e28758787a9da4b.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles/wooden_supports.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dwtspohoptiwn\"\npath=\"res://.godot/imported/wooden_supports.png-e2f7256585c99570530eae53fe32b7ee.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles/wooden_supports.png\"\ndest_files=[\"res://.godot/imported/wooden_supports.png-e2f7256585c99570530eae53fe32b7ee.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/bushes1.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://buuvdmdkvmrqi\"\npath=\"res://.godot/imported/bushes1.png-8482f2618fbb1252c6c8602bf0e9093b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/bushes1.png\"\ndest_files=[\"res://.godot/imported/bushes1.png-8482f2618fbb1252c6c8602bf0e9093b.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/column_overgrown.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bnkqv52xr6jwg\"\npath=\"res://.godot/imported/column_overgrown.png-3e3fbe61a472b6e6d46cf6a9ccdd8659.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/column_overgrown.png\"\ndest_files=[\"res://.godot/imported/column_overgrown.png-3e3fbe61a472b6e6d46cf6a9ccdd8659.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/leaves1.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://8k675jm7ssuf\"\npath=\"res://.godot/imported/leaves1.png-dc5a49939d165cb70f8d9f879c477680.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/leaves1.png\"\ndest_files=[\"res://.godot/imported/leaves1.png-dc5a49939d165cb70f8d9f879c477680.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/stones1.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cgpcu4ck8c2v5\"\npath=\"res://.godot/imported/stones1.png-ca20d18f9c99f96bf2be2591cff356c6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/stones1.png\"\ndest_files=[\"res://.godot/imported/stones1.png-ca20d18f9c99f96bf2be2591cff356c6.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/stones2.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cbbl57ekmerku\"\npath=\"res://.godot/imported/stones2.png-72dd4e2eb2b332933605e77ee4bb45e7.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/stones2.png\"\ndest_files=[\"res://.godot/imported/stones2.png-72dd4e2eb2b332933605e77ee4bb45e7.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/stones3.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cokj6s372752e\"\npath=\"res://.godot/imported/stones3.png-1c844d4bfa4f8434f043d8b2ef84ace4.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/stones3.png\"\ndest_files=[\"res://.godot/imported/stones3.png-1c844d4bfa4f8434f043d8b2ef84ace4.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/trees1.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b7wwnn77w8hhb\"\npath=\"res://.godot/imported/trees1.png-989cb2af708c44a2a7e0af95b58160f0.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/trees1.png\"\ndest_files=[\"res://.godot/imported/trees1.png-989cb2af708c44a2a7e0af95b58160f0.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/trees2.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://blgrogxcyqgrv\"\npath=\"res://.godot/imported/trees2.png-c9754a2df909534788f8d490b11fc3bf.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/trees2.png\"\ndest_files=[\"res://.godot/imported/trees2.png-c9754a2df909534788f8d490b11fc3bf.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines1.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dceqm4jvhllky\"\npath=\"res://.godot/imported/vines1.png-b215092d56a68495af4e72d022c5e6e7.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines1.png\"\ndest_files=[\"res://.godot/imported/vines1.png-b215092d56a68495af4e72d022c5e6e7.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines2.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c3wu26qm1m3yu\"\npath=\"res://.godot/imported/vines2.png-bbfe8c51bc647b29198997b8658db1b5.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines2.png\"\ndest_files=[\"res://.godot/imported/vines2.png-bbfe8c51bc647b29198997b8658db1b5.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines3.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d286468sfnwks\"\npath=\"res://.godot/imported/vines3.png-4732d57a5644fe28964c845d4f85df9d.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines3.png\"\ndest_files=[\"res://.godot/imported/vines3.png-4732d57a5644fe28964c845d4f85df9d.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines4.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bbqc24ypw5f6n\"\npath=\"res://.godot/imported/vines4.png-2692c9a0638c733eecdb3ec7706d2be6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines4.png\"\ndest_files=[\"res://.godot/imported/vines4.png-2692c9a0638c733eecdb3ec7706d2be6.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines5.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cas6o0y3n1aeq\"\npath=\"res://.godot/imported/vines5.png-cf8500a2a5ffa5ed6665498f4af8aaa6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines5.png\"\ndest_files=[\"res://.godot/imported/vines5.png-cf8500a2a5ffa5ed6665498f4af8aaa6.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines6.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://wob80clhcyd3\"\npath=\"res://.godot/imported/vines6.png-62caa287a305152b009b490f3247fe5f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines6.png\"\ndest_files=[\"res://.godot/imported/vines6.png-62caa287a305152b009b490f3247fe5f.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/vines7.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://crgo2lc1y87l6\"\npath=\"res://.godot/imported/vines7.png-797f48f3c99b003ddd4fc819734c85d6.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/vines7.png\"\ndest_files=[\"res://.godot/imported/vines7.png-797f48f3c99b003ddd4fc819734c85d6.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tiles_decoration/wall_vines1.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://m18bce1kiqho\"\npath=\"res://.godot/imported/wall_vines1.png-305fa6420722346fcff58b83260141ab.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tiles_decoration/wall_vines1.png\"\ndest_files=[\"res://.godot/imported/wall_vines1.png-305fa6420722346fcff58b83260141ab.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/astral_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dv1stv65yi6ch\"\npath=\"res://.godot/imported/astral_common.png-ca70de7666b502ba78a7941d3d535f53.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/astral_common.png\"\ndest_files=[\"res://.godot/imported/astral_common.png-ca70de7666b502ba78a7941d3d535f53.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/astral_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://biqwx15sdng3w\"\npath=\"res://.godot/imported/astral_rare.png-e1dd56f48968945b88cb7f2e8d70f7fa.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/astral_rare.png\"\ndest_files=[\"res://.godot/imported/astral_rare.png-e1dd56f48968945b88cb7f2e8d70f7fa.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/astral_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c0i25gqykkvq2\"\npath=\"res://.godot/imported/astral_uncommon.png-7d40c21319211ceeb67a30f80cd071c8.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/astral_uncommon.png\"\ndest_files=[\"res://.godot/imported/astral_uncommon.png-7d40c21319211ceeb67a30f80cd071c8.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/astral_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://df1ouj1h6g583\"\npath=\"res://.godot/imported/astral_unique.png-dbedcfa66d510e70ac21fb049fffc603.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/astral_unique.png\"\ndest_files=[\"res://.godot/imported/astral_unique.png-dbedcfa66d510e70ac21fb049fffc603.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/darkness_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cqetvcfdjje3s\"\npath=\"res://.godot/imported/darkness_common.png-dbf5523f3bcc090c90906fc4fdd5b07e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/darkness_common.png\"\ndest_files=[\"res://.godot/imported/darkness_common.png-dbf5523f3bcc090c90906fc4fdd5b07e.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/darkness_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://65jvdxexe8qw\"\npath=\"res://.godot/imported/darkness_rare.png-ccc241570b06e12e527c668ae2adf22f.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/darkness_rare.png\"\ndest_files=[\"res://.godot/imported/darkness_rare.png-ccc241570b06e12e527c668ae2adf22f.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/darkness_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://df1n41qevrcqi\"\npath=\"res://.godot/imported/darkness_uncommon.png-1c31161addb8c1b58c3bc0fdb2ee1f67.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/darkness_uncommon.png\"\ndest_files=[\"res://.godot/imported/darkness_uncommon.png-1c31161addb8c1b58c3bc0fdb2ee1f67.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/darkness_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b8avj0lojcn77\"\npath=\"res://.godot/imported/darkness_unique.png-bdd49c6e4baa8f7f43dbfe8359584f4c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/darkness_unique.png\"\ndest_files=[\"res://.godot/imported/darkness_unique.png-bdd49c6e4baa8f7f43dbfe8359584f4c.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/fire_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://sd50h5ps6672\"\npath=\"res://.godot/imported/fire_common.png-afade9826b51e6a51337f7603eb2009c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/fire_common.png\"\ndest_files=[\"res://.godot/imported/fire_common.png-afade9826b51e6a51337f7603eb2009c.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/fire_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cylhbe3f41e1a\"\npath=\"res://.godot/imported/fire_rare.png-6432b8fe8742c50703b63ce5f07a38fb.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/fire_rare.png\"\ndest_files=[\"res://.godot/imported/fire_rare.png-6432b8fe8742c50703b63ce5f07a38fb.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/fire_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d17ej65dobacn\"\npath=\"res://.godot/imported/fire_uncommon.png-6de277243bef411dac90eeb1e22f5bea.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/fire_uncommon.png\"\ndest_files=[\"res://.godot/imported/fire_uncommon.png-6de277243bef411dac90eeb1e22f5bea.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/fire_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bn5nfw6lifhof\"\npath=\"res://.godot/imported/fire_unique.png-33d73e561b7a43976ee79d51dcd41ffb.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/fire_unique.png\"\ndest_files=[\"res://.godot/imported/fire_unique.png-33d73e561b7a43976ee79d51dcd41ffb.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/ice_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://w6nfohk2lg1s\"\npath=\"res://.godot/imported/ice_common.png-51c65848be089a8a627005c5e63a5f20.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/ice_common.png\"\ndest_files=[\"res://.godot/imported/ice_common.png-51c65848be089a8a627005c5e63a5f20.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/ice_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://djwd1fnrh5xpc\"\npath=\"res://.godot/imported/ice_rare.png-095348029f0a6bbffc25bd7051671218.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/ice_rare.png\"\ndest_files=[\"res://.godot/imported/ice_rare.png-095348029f0a6bbffc25bd7051671218.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/ice_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://clyoh08bhg4fv\"\npath=\"res://.godot/imported/ice_uncommon.png-59c886c02f7bd89cd5f110f02b066d85.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/ice_uncommon.png\"\ndest_files=[\"res://.godot/imported/ice_uncommon.png-59c886c02f7bd89cd5f110f02b066d85.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/ice_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bcj5bery2fwd2\"\npath=\"res://.godot/imported/ice_unique.png-6afb96b8c8e379e700e0ccab3bffcaf8.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/ice_unique.png\"\ndest_files=[\"res://.godot/imported/ice_unique.png-6afb96b8c8e379e700e0ccab3bffcaf8.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/iron_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dcfvp18syyxci\"\npath=\"res://.godot/imported/iron_common.png-07cffd3ee0ad3a2fa7d81516735529d9.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/iron_common.png\"\ndest_files=[\"res://.godot/imported/iron_common.png-07cffd3ee0ad3a2fa7d81516735529d9.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/iron_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://drd4dnffccck2\"\npath=\"res://.godot/imported/iron_rare.png-6d1dd1f2c3b1cbb5f8b9465bbc524c93.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/iron_rare.png\"\ndest_files=[\"res://.godot/imported/iron_rare.png-6d1dd1f2c3b1cbb5f8b9465bbc524c93.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/iron_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://tqwlpk8sdox0\"\npath=\"res://.godot/imported/iron_uncommon.png-76e1b8b2495d7d02817154faa5f02f04.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/iron_uncommon.png\"\ndest_files=[\"res://.godot/imported/iron_uncommon.png-76e1b8b2495d7d02817154faa5f02f04.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/iron_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://badivqvsvs52t\"\npath=\"res://.godot/imported/iron_unique.png-d95fe1629eaf5e661e2e35e13bf10d65.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/iron_unique.png\"\ndest_files=[\"res://.godot/imported/iron_unique.png-d95fe1629eaf5e661e2e35e13bf10d65.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/nature_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c8uwpkclo4nk5\"\npath=\"res://.godot/imported/nature_common.png-dc1eb5f0983fb9d40f3c05932fa4792b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/nature_common.png\"\ndest_files=[\"res://.godot/imported/nature_common.png-dc1eb5f0983fb9d40f3c05932fa4792b.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/nature_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c2ipgujbe63mi\"\npath=\"res://.godot/imported/nature_rare.png-128af4e079d1d9bb97536ce553d89493.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/nature_rare.png\"\ndest_files=[\"res://.godot/imported/nature_rare.png-128af4e079d1d9bb97536ce553d89493.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/nature_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bm1dfh8a2haq1\"\npath=\"res://.godot/imported/nature_uncommon.png-7d0240c6705bfcce16c59a6fcf9d80ed.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/nature_uncommon.png\"\ndest_files=[\"res://.godot/imported/nature_uncommon.png-7d0240c6705bfcce16c59a6fcf9d80ed.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/nature_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cowfob3sgn0hd\"\npath=\"res://.godot/imported/nature_unique.png-0f4df8dbee77791b4e12d7c01acc3a96.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/nature_unique.png\"\ndest_files=[\"res://.godot/imported/nature_unique.png-0f4df8dbee77791b4e12d7c01acc3a96.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/storm_common.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dbjvvdlpstmju\"\npath=\"res://.godot/imported/storm_common.png-465eb6e249ccf8b62d4385d36be25672.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/storm_common.png\"\ndest_files=[\"res://.godot/imported/storm_common.png-465eb6e249ccf8b62d4385d36be25672.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/storm_rare.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://p0uh8dc0naey\"\npath=\"res://.godot/imported/storm_rare.png-9fdb1d2967f7530f0d65cc45310e1258.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/storm_rare.png\"\ndest_files=[\"res://.godot/imported/storm_rare.png-9fdb1d2967f7530f0d65cc45310e1258.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/storm_uncommon.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c7hu3aovppxyi\"\npath=\"res://.godot/imported/storm_uncommon.png-49592c48f8ea4db19c7e81e4bc072886.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/storm_uncommon.png\"\ndest_files=[\"res://.godot/imported/storm_uncommon.png-49592c48f8ea4db19c7e81e4bc072886.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tower_sprites/storm_unique.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b0lv1vv13qxox\"\npath=\"res://.godot/imported/storm_unique.png-3425a9499e8dbe1cb00f28ed30bbd79e.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tower_sprites/storm_unique.png\"\ndest_files=[\"res://.godot/imported/storm_unique.png-3425a9499e8dbe1cb00f28ed30bbd79e.ctex\"]\n\n[params]\n\ncompress/mode=4\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/README.md",
    "content": "Pictures for tutorial.\n\nNote that for consistency, these screenshots need to all have the same width of 600. This is because the tutorial window is setup to fix this 600 at most. Couldn't figure out how to make RichTextLabel automatically expand to fit the image.\n"
  },
  {
    "path": "assets/tutorial_pictures/build_tower.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://q81w3pck2wxy\"\npath=\"res://.godot/imported/build_tower.png-3e4772f1e6dc26f2c8d3a06114f73a77.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/build_tower.png\"\ndest_files=[\"res://.godot/imported/build_tower.png-3e4772f1e6dc26f2c8d3a06114f73a77.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/item_drop.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bisaxbubjd812\"\npath=\"res://.godot/imported/item_drop.png-6407521a04d24b1428e484fc757b1e2a.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/item_drop.png\"\ndest_files=[\"res://.godot/imported/item_drop.png-6407521a04d24b1428e484fc757b1e2a.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/research.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cj8r8gpab2shn\"\npath=\"res://.godot/imported/research.png-cc1650e6d9f5874efccbfa1cf06bdc04.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/research.png\"\ndest_files=[\"res://.godot/imported/research.png-cc1650e6d9f5874efccbfa1cf06bdc04.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/research_element.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dn2qydnve8qga\"\npath=\"res://.godot/imported/research_element.png-067e231789d5d3a6abe80a86a3936125.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/research_element.png\"\ndest_files=[\"res://.godot/imported/research_element.png-067e231789d5d3a6abe80a86a3936125.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/resource_panel.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cl7nfxmo265c8\"\npath=\"res://.godot/imported/resource_panel.png-48f66e6ef6630eb187f544c84524cd38.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/resource_panel.png\"\ndest_files=[\"res://.godot/imported/resource_panel.png-48f66e6ef6630eb187f544c84524cd38.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/roll_towers.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cy40382cjpc8e\"\npath=\"res://.godot/imported/roll_towers.png-1e5d47c9b274dab6c547da64086b31d1.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/roll_towers.png\"\ndest_files=[\"res://.godot/imported/roll_towers.png-1e5d47c9b274dab6c547da64086b31d1.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/tower_info.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cvhukhkiu0urb\"\npath=\"res://.godot/imported/tower_info.png-50ae7dced2ca88c56ec5dbb96967d1ae.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/tower_info.png\"\ndest_files=[\"res://.godot/imported/tower_info.png-50ae7dced2ca88c56ec5dbb96967d1ae.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/tower_level.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dytdvhdkhv010\"\npath=\"res://.godot/imported/tower_level.png-457c5b3a00732dec9b50e8aa7d5d8e49.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/tower_level.png\"\ndest_files=[\"res://.godot/imported/tower_level.png-457c5b3a00732dec9b50e8aa7d5d8e49.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/tower_mouse_over.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c1b2yekyu140c\"\npath=\"res://.godot/imported/tower_mouse_over.png-581902fa9e1af089227b74357badabf2.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/tower_mouse_over.png\"\ndest_files=[\"res://.godot/imported/tower_mouse_over.png-581902fa9e1af089227b74357badabf2.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/tower_stash.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c332mbde4whjb\"\npath=\"res://.godot/imported/tower_stash.png-f2cd5dfbe3cdb7832a88140d2ed83a51.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/tower_stash.png\"\ndest_files=[\"res://.godot/imported/tower_stash.png-f2cd5dfbe3cdb7832a88140d2ed83a51.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/transform.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://sg3tuwhtwjgc\"\npath=\"res://.godot/imported/transform.png-6ecff6477bfbb1114a941c30edd7cb2c.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/transform.png\"\ndest_files=[\"res://.godot/imported/transform.png-6ecff6477bfbb1114a941c30edd7cb2c.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/upgrade.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d1osbwnwhctby\"\npath=\"res://.godot/imported/upgrade.png-7f0335eec3d78c62d614b5ba1805f26b.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/upgrade.png\"\ndest_files=[\"res://.godot/imported/upgrade.png-7f0335eec3d78c62d614b5ba1805f26b.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "assets/tutorial_pictures/wave_finish.png.import",
    "content": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dn1pceb0u52v4\"\npath=\"res://.godot/imported/wave_finish.png-29cf615d24519b2ea86bffa554933315.ctex\"\nmetadata={\n\"vram_texture\": false\n}\n\n[deps]\n\nsource_file=\"res://assets/tutorial_pictures/wave_finish.png\"\ndest_files=[\"res://.godot/imported/wave_finish.png-29cf615d24519b2ea86bffa554933315.ctex\"]\n\n[params]\n\ncompress/mode=0\ncompress/high_quality=false\ncompress/lossy_quality=0.7\ncompress/hdr_compression=1\ncompress/normal_map=0\ncompress/channel_pack=0\nmipmaps/generate=false\nmipmaps/limit=-1\nroughness/mode=0\nroughness/src_normal=\"\"\nprocess/fix_alpha_border=true\nprocess/premult_alpha=false\nprocess/normal_map_invert_y=false\nprocess/hdr_as_srgb=false\nprocess/hdr_clamp_exposure=false\nprocess/size_limit=0\ndetect_3d/compress_to=1\n"
  },
  {
    "path": "build/README.md",
    "content": "This folder contains files used by github workflow. The files in the subfolder are bundled together with the html5 build of the game.\n"
  },
  {
    "path": "build/linux/README.md",
    "content": "Placeholder file to commit the empty folder. Needed for export.\n"
  },
  {
    "path": "build/macos/README.md",
    "content": "Placeholder file to commit the empty folder. Needed for export.\n"
  },
  {
    "path": "build/web/full-size.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"utf-8\">\n\t<meta name=\"viewport\" content=\"width=device-width, user-scalable=no\">\n\t<title>YouTD 2</title>\n\t<style>\n\t\tbody {\n\t\t\ttouch-action: none;\n\t\t\tmargin: 0;\n\t\t\tborder: 0 none;\n\t\t\tpadding: 0;\n\t\t\ttext-align: center;\n\t\t\tbackground-image: url(\"loading_screen.png\");\n\t\t\tbackground-size: cover;\n\t\t\tbackground-repeat: no-repeat;\n\t\t\tbackground-position: center center;\n\t\t}\n\n\t\t#canvas {\n\t\t\tdisplay: block;\n\t\t\tmargin: 0;\n\t\t\tcolor: transparent;\n\t\t}\n\n\t\t#canvas:focus {\n\t\t\toutline: none;\n\t\t}\n\n\t\t.godot {\n\t\t\tfont-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;\n\t\t\tcolor: #e0e0e0;\n\t\t\tbackground-color: #3b3943;\n\t\t\tbackground-image: linear-gradient(to bottom, #403e48, #35333c);\n\t\t\tborder: 1px solid #45434e;\n\t\t\tbox-shadow: 0 0 1px 1px #2f2d35;\n\t\t}\n\n\t\t/* Status display */\n\n\t\t#status {\n\t\t\tposition: absolute;\n\t\t\tleft: 0;\n\t\t\tright: 0;\n\t\t\tbottom: 0;\n\t\t\theight: 50px;\n\t\t\tdisplay: flex;\n\t\t\tjustify-content: center;\n\t\t\talign-items: center;\n\t\t\tvisibility: hidden;\n\t\t}\n\n\t\t#status-progress {\n\t\t\twidth: 700px;\n\t\t\theight: 7px;\n\t\t\tbackground-color: #38363A;\n\t\t\tborder: 1px solid #444246;\n\t\t\tpadding: 1px;\n\t\t\tbox-shadow: 0 0 2px 1px #1B1C22;\n\t\t\tborder-radius: 2px;\n\t\t\tvisibility: visible;\n\t\t}\n\n\t\t@media only screen and (orientation:portrait) {\n\t\t\t#status-progress {\n\t\t\t\twidth: 61.8%;\n\t\t\t}\n\t\t}\n\n\t\t#status-progress-inner {\n\t\t\theight: 100%;\n\t\t\twidth: 0;\n\t\t\tbox-sizing: border-box;\n\t\t\ttransition: width 0.5s linear;\n\t\t\tbackground-color: #202020;\n\t\t\tborder: 1px solid #222223;\n\t\t\tbox-shadow: 0 0 1px 1px #27282E;\n\t\t\tborder-radius: 3px;\n\t\t}\n\n\t\t#status-indeterminate {\n\t\t\theight: 42px;\n\t\t\tvisibility: visible;\n\t\t\tposition: relative;\n\t\t}\n\n\t\t#status-indeterminate > div {\n\t\t\twidth: 4.5px;\n\t\t\theight: 0;\n\t\t\tborder-style: solid;\n\t\t\tborder-width: 9px 3px 0 3px;\n\t\t\tborder-color: #2b2b2b transparent transparent transparent;\n\t\t\ttransform-origin: center 21px;\n\t\t\tposition: absolute;\n\t\t}\n\n\t\t#status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }\n\t\t#status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }\n\t\t#status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }\n\t\t#status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }\n\t\t#status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }\n\t\t#status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }\n\t\t#status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }\n\t\t#status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }\n\n\t\t#status-notice {\n\t\t\tmargin: 0 100px;\n\t\t\tline-height: 1.3;\n\t\t\tvisibility: visible;\n\t\t\tpadding: 4px 6px;\n\t\t\tvisibility: visible;\n\t\t}\n\n\t\t.background-video {\n\t\t\tposition: fixed;\n\t\t\ttop: 0;\n\t\t\tleft: 0;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\toverflow: hidden;\n\t\t\tz-index: -1;\n\t\t}\n\n\t\t.background-video video {\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tobject-fit: cover;\n\t\t}\n\t</style>\n\t<link id='-gd-engine-icon' rel='icon' type='image/png' href='index.icon.png' />\n\t<link rel='apple-touch-icon' href='index.apple-touch-icon.png'/>\n\t<script src=\"https://js.sentry-cdn.com/2c45aced288f448c80f8fb8d682c341c.min.js\" crossorigin=\"anonymous\"></script>\n\t<script>\n\t\tif (window.Sentry !== undefined) { // Check that Sentry is defined, because it could have been blocked by an ad blocker.\n\t\t\tSentry.onLoad(function () {\n\t\t\t\tSentry.init({\n\t\t\t\t  dsn: \"https://2c45aced288f448c80f8fb8d682c341c@o4505518956675072.ingest.sentry.io/4505518957658113\",\n\t\t\t\t  release: \"youtd2@0.0.1\",\n\t\t\t\t  integrations: [new Sentry.BrowserTracing()],\n\t\t\t\t  tracesSampleRate: 1.0,\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t</script>\n</head>\n<body>\n<div class=\"background-video\">\n\t<video autoplay muted loop>\n\t\t<source src=\"loading_screen.mp4\" type=\"video/mp4\">\n\t</video>\n</div>\n<canvas id=\"canvas\">\n\tHTML5 canvas appears to be unsupported in the current browser.<br >\n\tPlease try updating or use a different browser.\n</canvas>\n<div id=\"status\">\n\t<div id=\"status-progress\" style=\"display: none;\" oncontextmenu=\"event.preventDefault();\">\n\t\t<div id =\"status-progress-inner\"></div>\n\t</div>\n\t<div id=\"status-indeterminate\" style=\"display: none;\" oncontextmenu=\"event.preventDefault();\">\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t</div>\n\t<div id=\"status-notice\" class=\"godot\" style=\"display: none;\"></div>\n</div>\n<script src=\"index.js\"></script>\n<script>\n\tconst GODOT_CONFIG = {\"args\":[],\"canvasResizePolicy\":2,\"executable\":\"index\",\"experimentalVK\":false,\"fileSizes\":{\"index.pck\":49994672,\"index.wasm\":1642372},\"focusCanvas\":true,\"gdextensionLibs\":[]};\n\tconst engine = new Engine(GODOT_CONFIG);\n\n\t(function () {\n\t\tconst INDETERMINATE_STATUS_STEP_MS = 100;\n\t\tconst statusProgress = document.getElementById('status-progress');\n\t\tconst statusProgressInner = document.getElementById('status-progress-inner');\n\t\tconst statusIndeterminate = document.getElementById('status-indeterminate');\n\t\tconst statusNotice = document.getElementById('status-notice');\n\n\t\tlet initializing = true;\n\t\tlet statusMode = 'hidden';\n\n\t\tlet animationCallbacks = [];\n\t\tfunction animate(time) {\n\t\t\tanimationCallbacks.forEach((callback) => callback(time));\n\t\t\trequestAnimationFrame(animate);\n\t\t}\n\t\trequestAnimationFrame(animate);\n\n\t\tfunction animateStatusIndeterminate(ms) {\n\t\t\tconst i = Math.floor((ms / INDETERMINATE_STATUS_STEP_MS) % 8);\n\t\t\tif (statusIndeterminate.children[i].style.borderTopColor === '') {\n\t\t\t\tArray.prototype.slice.call(statusIndeterminate.children).forEach((child) => {\n\t\t\t\t\tchild.style.borderTopColor = '';\n\t\t\t\t});\n\t\t\t\tstatusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';\n\t\t\t}\n\t\t}\n\n\t\tfunction setStatusMode(mode) {\n\t\t\tif (statusMode === mode || !initializing) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t[statusProgress, statusIndeterminate, statusNotice].forEach((elem) => {\n\t\t\t\telem.style.display = 'none';\n\t\t\t});\n\t\t\tanimationCallbacks = animationCallbacks.filter(function (value) {\n\t\t\t\treturn (value !== animateStatusIndeterminate);\n\t\t\t});\n\t\t\tswitch (mode) {\n\t\t\t\tcase 'progress':\n\t\t\t\t\tstatusProgress.style.display = 'flex';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'indeterminate':\n\t\t\t\t\tstatusIndeterminate.style.display = 'flex';\n\t\t\t\t\tanimationCallbacks.push(animateStatusIndeterminate);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'notice':\n\t\t\t\t\tstatusNotice.style.display = 'flex';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'hidden':\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error('Invalid status mode');\n\t\t\t}\n\t\t\tstatusMode = mode;\n\t\t}\n\n\t\tfunction setStatusNotice(text) {\n\t\t\twhile (statusNotice.lastChild) {\n\t\t\t\tstatusNotice.removeChild(statusNotice.lastChild);\n\t\t\t}\n\t\t\tconst lines = text.split('\\n');\n\t\t\tlines.forEach((line) => {\n\t\t\t\tstatusNotice.appendChild(document.createTextNode(line));\n\t\t\t\tstatusNotice.appendChild(document.createElement('br'));\n\t\t\t});\n\t\t}\n\n\t\tfunction displayFailureNotice(err) {\n\t\t\tconst msg = err.message || err;\n\t\t\tconsole.error(msg);\n\t\t\tsetStatusNotice(msg);\n\t\t\tsetStatusMode('notice');\n\t\t\tinitializing = false;\n\t\t}\n\n\t\tconst missing = Engine.getMissingFeatures();\n\t\tif (missing.length !== 0) {\n\t\t\tconst missingMsg = 'Error\\nThe following features required to run Godot projects on the Web are missing:\\n';\n\t\t\tdisplayFailureNotice(missingMsg + missing.join('\\n'));\n\t\t} else {\n\t\t\tsetStatusMode('indeterminate');\n\t\t\tengine.startGame({\n\t\t\t\t'onProgress': function (current, total) {\n\t\t\t\t\tif (total > 0) {\n\t\t\t\t\t\tstatusProgressInner.style.width = `${(current / total) * 100}%`;\n\t\t\t\t\t\tsetStatusMode('progress');\n\t\t\t\t\t\tif (current === total) {\n\t\t\t\t\t\t\t// wait for progress bar animation\n\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\tsetStatusMode('indeterminate');\n\t\t\t\t\t\t\t}, 500);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetStatusMode('indeterminate');\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}).then(() => {\n\t\t\t\tsetStatusMode('hidden');\n\t\t\t\tinitializing = false;\n\t\t\t}, displayFailureNotice);\n\t\t}\n\t}());\n</script>\n</body>\n</html>\n\n"
  },
  {
    "path": "build/windows/README.md",
    "content": "Placeholder file to commit the empty folder. Needed for export.\n"
  },
  {
    "path": "data/README.md",
    "content": "This folder contains data which is loaded and used in the game. Things like tutorial text, descriptions of items, tower costs.\n"
  },
  {
    "path": "data/ability_properties.csv",
    "content": "\"id\",\"name_english\",\"range\",\"target_type\",\"icon\",\"name\",\"description_short\",\"description_long\"\n1,\"Unstable Energies\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"4ULZ\",\"TQKY\",\"E3BL\"\n2,\"Unstable Energies\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"NAPL\",\"IZOW\",\"ILJE\"\n3,\"Unstable Energies\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"9OR4\",\"N31B\",\"FBRA\"\n4,\"Unstable Energies\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"S7GF\",\"V3U5\",\"D9L2\"\n5,\"Illuminate\",\"0\",,\"res://resources/icons/staves/wand_glowing.tres\",\"88V9\",\"76PS\",\"B32H\"\n6,\"Illuminate\",\"0\",,\"res://resources/icons/staves/wand_glowing.tres\",\"VA97\",\"LBQE\",\"TFPO\"\n7,\"Illuminate\",\"0\",,\"res://resources/icons/staves/wand_glowing.tres\",\"SFAJ\",\"2OIP\",\"E125\"\n8,\"Illuminate\",\"0\",,\"res://resources/icons/staves/wand_glowing.tres\",\"PQDC\",\"NJA8\",\"M267\"\n9,\"Illuminate\",\"0\",,\"res://resources/icons/staves/wand_glowing.tres\",\"11A3\",\"TIMQ\",\"8Z92\"\n10,\"Illuminate\",\"0\",,\"res://resources/icons/staves/wand_glowing.tres\",\"6FJR\",\"6JY2\",\"TOQQ\"\n11,\"Spray and Pray\",\"0\",,\"res://resources/icons/tower_icons/meteor_totem.tres\",\"FWU1\",\"P4YE\",\"9SEO\"\n12,\"Spray and Pray\",\"0\",,\"res://resources/icons/tower_icons/meteor_totem.tres\",\"L3TU\",\"JVUC\",\"E4MP\"\n13,\"Spray and Pray\",\"0\",,\"res://resources/icons/tower_icons/meteor_totem.tres\",\"W4RR\",\"4WUM\",\"PQJ3\"\n14,\"Spray and Pray\",\"0\",,\"res://resources/icons/tower_icons/meteor_totem.tres\",\"167F\",\"WRSO\",\"MA1T\"\n15,\"Spray and Pray\",\"0\",,\"res://resources/icons/tower_icons/meteor_totem.tres\",\"14M0\",\"EOT6\",\"Q6K5\"\n16,\"Spray and Pray\",\"0\",,\"res://resources/icons/tower_icons/meteor_totem.tres\",\"8U1A\",\"GZN6\",\"MIFE\"\n17,\"Future Knowledge\",\"0\",,\"res://resources/icons/books/book_10.tres\",\"90SI\",\"H9TU\",\"LSRB\"\n18,\"Swarm of Bugs\",\"0\",,\"res://resources/icons/animals/spider_02.tres\",\"A56G\",\"2L3Z\",\"IXW2\"\n19,\"Swarm of Bugs\",\"0\",,\"res://resources/icons/animals/spider_02.tres\",\"IZHI\",\"1M1M\",\"W6MV\"\n20,\"Swarm of Bugs\",\"0\",,\"res://resources/icons/animals/spider_02.tres\",\"4PIP\",\"6BB8\",\"I4S1\"\n21,\"Swarm of Bugs\",\"0\",,\"res://resources/icons/animals/spider_02.tres\",\"FGMU\",\"DW47\",\"L9XT\"\n22,\"Ice Nova\",\"0\",,\"res://resources/icons/elements/ice.tres\",\"KSCT\",\"3FB1\",\"9JPV\"\n23,\"Ice Nova\",\"0\",,\"res://resources/icons/elements/ice.tres\",\"2WJV\",\"P5S3\",\"8PB6\"\n24,\"Ice Nova\",\"0\",,\"res://resources/icons/elements/ice.tres\",\"HDE4\",\"NQGW\",\"8HHR\"\n25,\"Ice Nova\",\"0\",,\"res://resources/icons/elements/ice.tres\",\"EAK2\",\"CYRY\",\"SP2C\"\n26,\"Alert\",\"500\",\"TOWERS\",\"res://resources/icons/misc/red_knight.tres\",\"7OX2\",\"MJC4\",\"SNQM\"\n27,\"Trespasser Awareness\",\"925\",\"CREEPS\",\"res://resources/icons/magic/eye.tres\",\"YQR7\",\"Y4TX\",\"4HWE\"\n28,\"Alert\",\"500\",\"TOWERS\",\"res://resources/icons/misc/red_knight.tres\",\"VPAN\",\"V4V3\",\"MVHF\"\n29,\"Trespasser Awareness\",\"925\",\"CREEPS\",\"res://resources/icons/magic/eye.tres\",\"PMKH\",\"2VJQ\",\"XDWH\"\n30,\"Alert\",\"500\",\"TOWERS\",\"res://resources/icons/misc/red_knight.tres\",\"GXCY\",\"MK44\",\"K9B8\"\n31,\"Trespasser Awareness\",\"925\",\"CREEPS\",\"res://resources/icons/magic/eye.tres\",\"BMD9\",\"00QV\",\"YNIX\"\n32,\"Grapple\",\"0\",,\"res://resources/icons/gloves/gloves_08.tres\",\"AX86\",\"2S9T\",\"VPNI\"\n33,\"Chaos\",\"750\",\"CREEPS\",\"res://resources/icons/books/note_02.tres\",\"EE0L\",\"LD8U\",\"T8M9\"\n34,\"Time Travel\",\"0\",,\"res://resources/icons/mechanical/compass.tres\",\"IW1G\",\"FELQ\",\"KPYV\"\n35,\"Transmute\",\"0\",,\"res://resources/icons/mechanical/gold_machine.tres\",\"WKYN\",\"RK91\",\"CN2W\"\n36,\"Gold Gree\",\"0\",,\"res://resources/icons/misc/gold_cart.tres\",\"08QK\",\"6I0B\",\"R69L\"\n37,\"Transmute\",\"0\",,\"res://resources/icons/mechanical/gold_machine.tres\",\"ZHAE\",\"RQ50\",\"BWLQ\"\n38,\"Gold Gree\",\"0\",,\"res://resources/icons/misc/gold_cart.tres\",\"TKRS\",\"OI6A\",\"6KIW\"\n39,\"Spacial Rift\",\"0\",,\"res://resources/icons/furniture/exploding_mirror.tres\",\"RJ54\",\"D7GW\",\"G4RV\"\n40,\"Ground Smash\",\"750\",\"CREEPS\",\"res://resources/icons/swords/greatsword_02.tres\",\"ISBN\",\"2QS3\",\"EZXL\"\n41,\"Occasional Thornspray\",\"0\",,\"res://resources/icons/trinkets/claw_01.tres\",\"V9CT\",\"BO31\",\"HZBE\"\n42,\"Occasional Thornspray\",\"0\",,\"res://resources/icons/trinkets/claw_01.tres\",\"06L8\",\"05LW\",\"686Q\"\n43,\"Occasional Thornspray\",\"0\",,\"res://resources/icons/trinkets/claw_01.tres\",\"36DS\",\"U954\",\"7S23\"\n44,\"Magic Split\",\"0\",,\"res://resources/icons/magic/claw_01.tres\",\"Y56N\",\"VEIJ\",\"44VD\"\n45,\"Magic Split\",\"0\",,\"res://resources/icons/magic/claw_01.tres\",\"7UIO\",\"6TD8\",\"A5J7\"\n46,\"Magic Split\",\"0\",,\"res://resources/icons/magic/claw_01.tres\",\"PG8S\",\"AXG3\",\"SIEI\"\n47,\"Magic Split\",\"0\",,\"res://resources/icons/magic/claw_01.tres\",\"1FSW\",\"2BLT\",\"OTZ7\"\n48,\"Electric Field\",\"1000\",\"CREEPS\",\"res://resources/icons/mechanical/mech_badge.tres\",\"7UEJ\",\"KOGU\",\"S6ZE\"\n49,\"Elemental Chaos\",\"0\",,\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"EJUK\",\"2TGV\",\"HZO7\"\n50,\"Elemental Chaos\",\"0\",,\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"ZW8L\",\"DO58\",\"BLQI\"\n51,\"Elemental Chaos\",\"0\",,\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"Y8MR\",\"0K5U\",\"2ETP\"\n52,\"Elemental Fury\",\"0\",,\"res://resources/icons/hud/research_elements.tres\",\"VUL8\",\"AY4T\",\"U5GY\"\n53,\"Elemental Chaos\",\"0\",,\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"FMGC\",\"SRZX\",\"9KHC\"\n54,\"Bronzefication\",\"0\",,\"res://resources/icons/potions/potion_07.tres\",\"ACCK\",\"CD6O\",\"D93H\"\n55,\"Shamanic Totem\",\"500\",\"TOWERS\",\"res://resources/icons/undead/skull_doll.tres\",\"M67X\",\"YZH2\",\"O74V\"\n56,\"Fighter Totem\",\"500\",\"TOWERS\",\"res://resources/icons/misc/spiky_totem_01.tres\",\"DAGZ\",\"GTT3\",\"HT91\"\n57,\"Ignite\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"C3PL\",\"1PI5\",\"KF1J\"\n58,\"Ignite\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"NTGS\",\"JBEY\",\"8GZT\"\n59,\"Ignite\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"58HB\",\"B7WL\",\"7WL2\"\n60,\"Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"76FM\",\"7LW4\",\"9X86\"\n61,\"Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"ELRO\",\"10C2\",\"BHZW\"\n62,\"Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"WLQX\",\"ZSA1\",\"NQDW\"\n63,\"Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"GN8A\",\"3H4F\",\"DG1F\"\n64,\"Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"GI6S\",\"0H21\",\"AVK2\"\n65,\"Extreme Cold\",\"900\",\"CREEPS\",\"res://resources/icons/furniture/furniture.tres\",\"GRJU\",\"E7MG\",\"4NEA\"\n66,\"Extreme Cold\",\"900\",\"CREEPS\",\"res://resources/icons/furniture/furniture.tres\",\"DZI4\",\"84RY\",\"XF1D\"\n67,\"Extreme Cold\",\"900\",\"CREEPS\",\"res://resources/icons/furniture/furniture.tres\",\"9B0O\",\"NKBP\",\"HC6V\"\n68,\"Power of Light\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"COZ4\",\"40FM\",\"QU63\"\n69,\"Power of Light\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"HA08\",\"OH3J\",\"M9ST\"\n70,\"Power of Light\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"19TS\",\"OSMB\",\"IU0S\"\n71,\"Power of Light\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"R3C3\",\"VEOG\",\"KEDF\"\n72,\"Power of Light\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"WKYY\",\"88HQ\",\"QM8K\"\n73,\"Ain Soph Aur\",\"0\",,\"res://resources/icons/shields/shield_with_gold_helmet.tres\",\"1XL7\",\"J03Z\",\"FD0L\"\n74,\"Ain Soph Aur\",\"0\",,\"res://resources/icons/shields/shield_with_gold_helmet.tres\",\"AMVG\",\"9IN0\",\"4P4O\"\n75,\"Ain Soph Aur\",\"0\",,\"res://resources/icons/shields/shield_with_gold_helmet.tres\",\"TW7N\",\"AH1K\",\"88WC\"\n76,\"Empowering Darkness\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"2LOY\",\"UQMU\",\"KRA6\"\n77,\"Empowering Darkness\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"DPSE\",\"X02C\",\"0LEF\"\n78,\"Empowering Darkness\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"EV3O\",\"I7DC\",\"R08W\"\n79,\"Frenzy\",\"0\",,\"res://resources/icons/undead/skull_03.tres\",\"OKLL\",\"N3MO\",\"LWC8\"\n80,\"Frenzy\",\"0\",,\"res://resources/icons/undead/skull_03.tres\",\"R4CE\",\"PFF1\",\"SCMR\"\n81,\"Frenzy\",\"0\",,\"res://resources/icons/undead/skull_03.tres\",\"JB2W\",\"WXRO\",\"9IG9\"\n82,\"Frenzy\",\"0\",,\"res://resources/icons/undead/skull_03.tres\",\"S71H\",\"A1VC\",\"RWVD\"\n83,\"Frenzy\",\"0\",,\"res://resources/icons/undead/skull_03.tres\",\"39QJ\",\"OL87\",\"J9R8\"\n84,\"Freezing Mist\",\"0\",,\"res://resources/icons/gems/crystal.tres\",\"ZC7V\",\"0Z52\",\"JM6U\"\n85,\"Glaives of Wisdom\",\"0\",,\"res://resources/icons/hud/recipe_reassemble.tres\",\"7UGE\",\"S4FY\",\"43SP\"\n86,\"Last Word\",\"0\",,\"res://resources/icons/shields/shield_skull.tres\",\"2CAG\",\"1K69\",\"UL71\"\n87,\"Curse of the Silent\",\"800\",\"CREEPS\",\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"NEI9\",\"OSZX\",\"ESLF\"\n88,\"Poisonous Spittle\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"QLJ8\",\"7MYL\",\"VTCB\"\n89,\"Poisonous Spittle\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"5L7O\",\"4DJD\",\"3WLD\"\n90,\"Poisonous Spittle\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"T1K1\",\"8CKP\",\"QBM0\"\n91,\"Poisonous Spittle\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"4LUD\",\"JV3G\",\"CHNF\"\n92,\"Steal\",\"0\",,\"res://resources/icons/gloves/steal.tres\",\"WK5Q\",\"RZS8\",\"53V0\"\n93,\"Steal\",\"0\",,\"res://resources/icons/gloves/steal.tres\",\"LYDW\",\"MSWJ\",\"ZCRM\"\n94,\"Steal\",\"0\",,\"res://resources/icons/gloves/steal.tres\",\"PA77\",\"O8LE\",\"TEGF\"\n95,\"Steal\",\"0\",,\"res://resources/icons/gloves/steal.tres\",\"WRIS\",\"IJPH\",\"KAQ2\"\n96,\"Steal\",\"0\",,\"res://resources/icons/gloves/steal.tres\",\"JCYY\",\"TE1A\",\"2NMI\"\n97,\"Spring Tide\",\"0\",,\"res://resources/icons/food/lard.tres\",\"WTVA\",\"K9R1\",\"FNLG\"\n98,\"Splash\",\"0\",,\"res://resources/icons/trinkets/trinket_02.tres\",\"Q5KO\",\"XE6Y\",\"KQVQ\"\n99,\"Serpent Ward\",\"800\",\"CREEPS\",\"res://resources/icons/tower_icons/small_serpent_ward.tres\",\"5SM6\",\"BR8N\",\"P8VK\"\n100,\"Purify\",\"0\",,\"res://resources/icons/holy/white_trinket.tres\",\"A5CO\",\"YU03\",\"ZG6P\"\n101,\"Magical Barrage\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"EI0U\",\"QW0C\",\"BDR2\"\n102,\"Magical Barrage\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"X693\",\"82S6\",\"UYQL\"\n103,\"Slumbering Parasite\",\"0\",,\"res://resources/icons/tower_icons/spider_queen.tres\",\"6DXG\",\"36PR\",\"3CUE\"\n104,\"Slumbering Parasite\",\"0\",,\"res://resources/icons/tower_icons/spider_queen.tres\",\"ZM36\",\"QLA9\",\"90NF\"\n105,\"Slumbering Parasite\",\"0\",,\"res://resources/icons/tower_icons/spider_queen.tres\",\"89Y4\",\"8CJB\",\"MH4Z\"\n106,\"Slumbering Parasite\",\"0\",,\"res://resources/icons/tower_icons/spider_queen.tres\",\"JH9O\",\"0N7T\",\"AVH4\"\n107,\"Energetic Weapon\",\"0\",,\"res://resources/icons/rockets/rocket_03.tres\",\"OVIM\",\"JV2P\",\"BAWC\"\n108,\"Energetic Weapon\",\"0\",,\"res://resources/icons/rockets/rocket_03.tres\",\"NOV0\",\"A5RI\",\"5XAB\"\n109,\"Speed Cast\",\"0\",,\"res://resources/icons/trinkets/trinket_01.tres\",\"XUF0\",\"VGWG\",\"58QJ\"\n110,\"Aqua Edge\",\"0\",,\"res://resources/icons/animals/fish_02.tres\",\"UPTO\",\"9UQR\",\"2FHG\"\n111,\"Spread\",\"0\",,\"res://resources/icons/magic/claw_02.tres\",\"7I0A\",\"Q0ZV\",\"DEL1\"\n112,\"Magic Boost\",\"350\",\"TOWERS\",\"res://resources/icons/tower_icons/storm_battery.tres\",\"68ST\",\"E0YA\",\"8DOF\"\n113,\"Shadowbolt Wave\",\"1000\",\"CREEPS\",\"res://resources/icons/tower_variations/meteor_totem_purple.tres\",\"LPUI\",\"O6PF\",\"I8KI\"\n114,\"Shadowbolt Wave\",\"1000\",\"CREEPS\",\"res://resources/icons/tower_variations/meteor_totem_purple.tres\",\"GD9N\",\"UEOL\",\"IJHQ\"\n115,\"Elemental Wrath\",\"0\",,\"res://resources/icons/scrolls/scroll_04.tres\",\"Y9CI\",\"GMRY\",\"FQYO\"\n116,\"Mimic\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"AE8P\",\"N6S8\",\"F59Y\"\n117,\"Elemental Wrath\",\"0\",,\"res://resources/icons/scrolls/scroll_04.tres\",\"JAEN\",\"7F7T\",\"MHU5\"\n118,\"Mimic\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"WK3B\",\"UAHU\",\"PXAB\"\n119,\"Elemental Wrath\",\"0\",,\"res://resources/icons/scrolls/scroll_04.tres\",\"YP4N\",\"297M\",\"767C\"\n120,\"Mimic\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"NA08\",\"FGK7\",\"LCGS\"\n121,\"Elemental Wrath\",\"0\",,\"res://resources/icons/scrolls/scroll_04.tres\",\"14XI\",\"TPL8\",\"2F9M\"\n122,\"Mimic\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"X7J0\",\"HDHU\",\"9ZEN\"\n123,\"Elemental Wrath\",\"0\",,\"res://resources/icons/scrolls/scroll_04.tres\",\"W2N7\",\"A1LZ\",\"WT4P\"\n124,\"Mimic\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"Q4AQ\",\"BSPL\",\"T4N4\"\n125,\"Flaming Inferno\",\"950\",\"CREEPS\",\"res://resources/icons/tower_icons/geothermal_extractor.tres\",\"NYI5\",\"LEPP\",\"CP1B\"\n126,\"Dragon's Hoard\",\"0\",,\"res://resources/icons/misc/gold_cart.tres\",\"5ONB\",\"LSFW\",\"B2Z1\"\n127,\"Ultimate Fighter\",\"0\",,\"res://resources/icons/weapons_misc/glaive_02.tres\",\"07LV\",\"IDGK\",\"NED2\"\n128,\"Maim\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"Q960\",\"L45J\",\"2TR0\"\n129,\"Rapid Gun Fire\",\"0\",,\"res://resources/icons/cannons/cannon_05.tres\",\"AHX3\",\"U1GI\",\"UX4A\"\n130,\"Sentry\",\"800\",\"CREEPS\",\"res://resources/icons/magic/eye.tres\",\"Q126\",\"48OA\",\"05KF\"\n131,\"Vicious Snow Ball\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"BZE1\",\"PYZW\",\"LR2R\"\n132,\"Vicious Snow Ball\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"MLYX\",\"NNUE\",\"31KC\"\n133,\"Vicious Snow Ball\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"KZHE\",\"E843\",\"1F23\"\n134,\"Twister\",\"0\",,\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"C5KR\",\"ZA8K\",\"A72R\"\n135,\"Twister\",\"0\",,\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"FWZY\",\"F7U5\",\"FSII\"\n136,\"Twin Attack\",\"0\",,\"res://resources/icons/bows/arrow_02.tres\",\"C7XA\",\"GTDD\",\"ZSDL\"\n137,\"Phoenixfire\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"WF2R\",\"BME3\",\"FPL5\"\n138,\"Phoenix Explosion\",\"0\",,\"res://resources/icons/elements/fire.tres\",\"OVOU\",\"ZZWH\",\"8R6J\"\n139,\"Twin Attack\",\"0\",,\"res://resources/icons/bows/arrow_02.tres\",\"QI1K\",\"UQSK\",\"3MSS\"\n140,\"Phoenixfire\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"I0DW\",\"GZWS\",\"MKZ4\"\n141,\"Phoenix Explosion\",\"0\",,\"res://resources/icons/elements/fire.tres\",\"1PRS\",\"1KAF\",\"O55I\"\n142,\"Twin Attack\",\"0\",,\"res://resources/icons/bows/arrow_02.tres\",\"8JEI\",\"M1CQ\",\"IR8L\"\n143,\"Phoenixfire\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"S6IJ\",\"9P3O\",\"QBUS\"\n144,\"Phoenix Explosion\",\"0\",,\"res://resources/icons/elements/fire.tres\",\"I1JK\",\"W7XR\",\"XLAK\"\n145,\"Frozen Thorn\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"0RAR\",\"YNLH\",\"XP3D\"\n146,\"Frozen Thorn\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"B2U5\",\"P6BJ\",\"ALYF\"\n147,\"Frozen Thorn\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"CP8A\",\"V698\",\"FPYB\"\n148,\"Frozen Thorn\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"3KSY\",\"Q11D\",\"OS6R\"\n149,\"Frozen Thorn\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"QEF0\",\"ZVMB\",\"2NVD\"\n150,\"Frozen Thorn\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"2COF\",\"WXCO\",\"QZFN\"\n151,\"Rejection\",\"0\",,\"res://resources/icons/clubs/club_01.tres\",\"G2RY\",\"FYC9\",\"43VR\"\n152,\"Rejection\",\"0\",,\"res://resources/icons/clubs/club_01.tres\",\"GYYI\",\"WRR2\",\"8R80\"\n153,\"Rejection\",\"0\",,\"res://resources/icons/clubs/club_01.tres\",\"8MZA\",\"IZYE\",\"CIVV\"\n154,\"Rejection\",\"0\",,\"res://resources/icons/clubs/club_01.tres\",\"OFL2\",\"9J3G\",\"82F6\"\n155,\"Mystical Storm Hammer\",\"0\",,\"res://resources/icons/blunt_weapons/hammer_04.tres\",\"LOE4\",\"GPX3\",\"VUQU\"\n156,\"Storm Bolt\",\"0\",,\"res://resources/icons/rockets/rocket_07.tres\",\"JNCV\",\"GMTY\",\"YLS0\"\n157,\"Sample Collection\",\"0\",,\"res://resources/icons/mechanical/alchemy_kit_01.tres\",\"9PNS\",\"8K9E\",\"DCSK\"\n158,\"Omnislash\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"3GWR\",\"7L1O\",\"A1ER\"\n159,\"Magic Missile\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"0YLC\",\"P62A\",\"X2Q8\"\n160,\"Acid Coating\",\"0\",,\"res://resources/icons/potions/potion_green_03.tres\",\"EFCH\",\"LUTI\",\"0TCS\"\n161,\"Acid Coating\",\"0\",,\"res://resources/icons/potions/potion_green_03.tres\",\"ZIO7\",\"HU14\",\"UARZ\"\n162,\"Acid Coating\",\"0\",,\"res://resources/icons/potions/potion_green_03.tres\",\"DEBM\",\"PIQN\",\"H3EQ\"\n163,\"Acid Coating\",\"0\",,\"res://resources/icons/potions/potion_green_03.tres\",\"948F\",\"PCAM\",\"5KNF\"\n164,\"Acid Coating\",\"0\",,\"res://resources/icons/potions/potion_green_03.tres\",\"2NZU\",\"I9BM\",\"U9W1\"\n165,\"Corpse Explosion\",\"1000\",\"CREEPS\",\"res://resources/icons/undead/skull_doll.tres\",\"Q36M\",\"A5IX\",\"13YG\"\n166,\"Critical Mass\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"YW7F\",\"75Z1\",\"CKZ2\"\n167,\"Corpse Explosion\",\"1000\",\"CREEPS\",\"res://resources/icons/undead/skull_doll.tres\",\"TWIJ\",\"2K56\",\"N1LC\"\n168,\"Critical Mass\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"TZIS\",\"ORNR\",\"JVMV\"\n169,\"Corpse Explosion\",\"1000\",\"CREEPS\",\"res://resources/icons/undead/skull_doll.tres\",\"1HVV\",\"1I15\",\"5F6Z\"\n170,\"Critical Mass\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"J27S\",\"JWFZ\",\"EDLO\"\n171,\"Corpse Explosion\",\"1000\",\"CREEPS\",\"res://resources/icons/undead/skull_doll.tres\",\"O5L5\",\"7DVY\",\"BTB8\"\n172,\"Critical Mass\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"H48H\",\"WDMX\",\"NA5L\"\n173,\"Atrophy\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"0WCV\",\"EBKO\",\"9OMC\"\n174,\"Atrophy\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"Q8CC\",\"4IUF\",\"E9ZU\"\n175,\"Atrophy\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"EQTN\",\"2ZBQ\",\"DA9P\"\n176,\"Atrophy\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"TN25\",\"C386\",\"DQSC\"\n177,\"Atrophy\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"HTQA\",\"JF8R\",\"FIGM\"\n178,\"Glare\",\"0\",,\"res://resources/icons/magic/eye_blue.tres\",\"35TU\",\"TEDI\",\"UXM2\"\n179,\"Rend\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"6XBT\",\"6IYM\",\"R3BR\"\n180,\"Rend\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"SB85\",\"0ALF\",\"IK8I\"\n181,\"Rend\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"ES60\",\"Z64Q\",\"JF95\"\n182,\"Rend\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"FRXI\",\"H9F8\",\"Q6FL\"\n183,\"Rend\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"S70X\",\"S8A6\",\"D8LD\"\n184,\"Rend\",\"0\",,\"res://resources/icons/clubs/club_glowing.tres\",\"QGPR\",\"6BUK\",\"GYBU\"\n185,\"Devour\",\"0\",,\"res://resources/icons/animals/dragon_04.tres\",\"ULBA\",\"QUWS\",\"ZWQ0\"\n186,\"Soul Split\",\"0\",,\"res://resources/icons/undead/skull_phazing.tres\",\"GVA8\",\"LPM8\",\"77N9\"\n187,\"Soul Split\",\"0\",,\"res://resources/icons/undead/skull_phazing.tres\",\"E5K9\",\"WUSY\",\"YCDL\"\n188,\"Soul Split\",\"0\",,\"res://resources/icons/undead/skull_phazing.tres\",\"GDLS\",\"SRQD\",\"R6VR\"\n189,\"Soul Split\",\"0\",,\"res://resources/icons/undead/skull_phazing.tres\",\"EHA5\",\"LE1K\",\"KTM1\"\n190,\"Piercing Shot\",\"0\",,\"res://resources/icons/rockets/rocket_02.tres\",\"FPQ5\",\"6TAU\",\"7OYM\"\n191,\"Piercing Shot\",\"0\",,\"res://resources/icons/rockets/rocket_02.tres\",\"F6UG\",\"5M96\",\"NSYV\"\n192,\"Piercing Shot\",\"0\",,\"res://resources/icons/rockets/rocket_02.tres\",\"HKFO\",\"QOH3\",\"99O7\"\n193,\"Piercing Shot\",\"0\",,\"res://resources/icons/rockets/rocket_02.tres\",\"S6WG\",\"FBQ0\",\"0FAL\"\n194,\"Energyball\",\"0\",,\"res://resources/icons/tower_icons/storm_battery.tres\",\"2KQ7\",\"12WL\",\"HQZH\"\n195,\"Weak Spots\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"5AUH\",\"1Q4C\",\"54PL\"\n196,\"Energy Detection\",\"900\",\"CREEPS\",\"res://resources/icons/trinkets/trinket_10.tres\",\"5YSX\",\"46GC\",\"69HM\"\n197,\"Energyball\",\"0\",,\"res://resources/icons/tower_icons/storm_battery.tres\",\"L8H5\",\"9IDO\",\"QIC0\"\n198,\"Weak Spots\",\"0\",,\"res://resources/icons/orbs/orb_ice_melting.tres\",\"BIYS\",\"Z448\",\"1Q9L\"\n199,\"Energy Detection\",\"900\",\"CREEPS\",\"res://resources/icons/trinkets/trinket_10.tres\",\"NUHS\",\"DYU2\",\"G0WR\"\n200,\"Zeal\",\"0\",,\"res://resources/icons/holy/cross_01.tres\",\"EU1H\",\"CFGV\",\"53J5\"\n201,\"Lightning Shield\",\"0\",,\"res://resources/icons/tower_icons/lightning_generator.tres\",\"2RJN\",\"4IUI\",\"OOPA\"\n202,\"Phase Blade\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"9ZP8\",\"UV0E\",\"GTQN\"\n203,\"Zeal\",\"0\",,\"res://resources/icons/holy/cross_01.tres\",\"RXJU\",\"GAWL\",\"D7I3\"\n204,\"Lightning Shield\",\"0\",,\"res://resources/icons/tower_icons/lightning_generator.tres\",\"4DA7\",\"N00F\",\"3VUQ\"\n205,\"Phase Blade\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"OJM5\",\"60FN\",\"NUR9\"\n206,\"Zeal\",\"0\",,\"res://resources/icons/holy/cross_01.tres\",\"WM2B\",\"IB1D\",\"ZFR5\"\n207,\"Lightning Shield\",\"0\",,\"res://resources/icons/tower_icons/lightning_generator.tres\",\"0N7J\",\"XOKG\",\"S10Q\"\n208,\"Phase Blade\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"LF95\",\"94G9\",\"OSWT\"\n209,\"Zeal\",\"0\",,\"res://resources/icons/holy/cross_01.tres\",\"KSM0\",\"6E21\",\"ZFEP\"\n210,\"Lightning Shield\",\"0\",,\"res://resources/icons/tower_icons/lightning_generator.tres\",\"NDOY\",\"S8QA\",\"6LH2\"\n211,\"Phase Blade\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"GO5C\",\"GUVF\",\"5TMA\"\n212,\"Silence\",\"0\",,\"res://resources/icons/animals/dragon_02.tres\",\"LDMJ\",\"O3EO\",\"5EAE\"\n213,\"Void\",\"0\",,\"res://resources/icons/tower_icons/small_bug_nest.tres\",\"8EHA\",\"H4AZ\",\"BZCH\"\n214,\"Silence\",\"0\",,\"res://resources/icons/animals/dragon_02.tres\",\"0AIF\",\"R9TE\",\"PSIL\"\n215,\"Void\",\"0\",,\"res://resources/icons/tower_icons/small_bug_nest.tres\",\"GYET\",\"WOTA\",\"64ZM\"\n216,\"Energetic Attack\",\"0\",,\"res://resources/icons/swords/sword_swing_01.tres\",\"IWLC\",\"7HNE\",\"5W1V\"\n217,\"Energetic Attack\",\"0\",,\"res://resources/icons/swords/sword_swing_01.tres\",\"J317\",\"2WCM\",\"YOAG\"\n218,\"Electrified Attack\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"73CG\",\"YQGB\",\"YRQJ\"\n219,\"Divine Hammer\",\"0\",,\"res://resources/icons/blunt_weapons/hammer_02.tres\",\"E2JY\",\"4D1I\",\"MLXN\"\n220,\"Grow!\",\"0\",,\"res://resources/icons/trinkets/trinket_09.tres\",\"16EY\",\"1J2B\",\"F5CK\"\n221,\"Landslide!\",\"0\",,\"res://resources/icons/food/lard.tres\",\"BI2C\",\"KHGV\",\"YNFZ\"\n222,\"Crush!\",\"500\",\"TOWERS\",\"res://resources/icons/tower_icons/black_rock_totem.tres\",\"5GWE\",\"8JN8\",\"UPIN\"\n223,\"Frag Grenade\",\"0\",,\"res://resources/icons/misc/balls_02.tres\",\"XM12\",\"4BE0\",\"W2GK\"\n224,\"Frag Grenade\",\"0\",,\"res://resources/icons/misc/balls_02.tres\",\"A6JX\",\"5J7D\",\"K0RD\"\n225,\"Warming Up\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"09DO\",\"ST7M\",\"JMEP\"\n226,\"Warming Up\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"NMUT\",\"VE26\",\"U6MG\"\n227,\"Warming Up\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"29GU\",\"XQL2\",\"UULY\"\n228,\"Warming Up\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"YAV1\",\"RCSH\",\"WBN6\"\n229,\"Warming Up\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"SUPQ\",\"2GJ6\",\"D3NI\"\n230,\"I Scale\",\"0\",,\"res://resources/icons/magic/claw_01.tres\",\"E4ZV\",\"RZXU\",\"MU9I\"\n231,\"Electrify\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"MB5S\",\"Q29F\",\"WJUQ\"\n232,\"I Overcharge\",\"0\",,\"res://resources/icons/mechanical/battery.tres\",\"0OIX\",\"SJFU\",\"86PI\"\n233,\"Fisherman's Net\",\"0\",,\"res://resources/icons/food/lard.tres\",\"J6HA\",\"9E37\",\"8ZAV\"\n234,\"Fresh Fish!\",\"500\",\"TOWERS\",\"res://resources/icons/animals/fish_01.tres\",\"XCDI\",\"ZIQQ\",\"R9C2\"\n235,\"Impatient\",\"0\",,\"res://resources/icons/daggers/dagger_06.tres\",\"OO03\",\"NWC0\",\"KDZW\"\n236,\"Twin Flames\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"VYB3\",\"ZIIB\",\"5KYE\"\n237,\"Twin Pulses\",\"900\",\"CREEPS\",\"res://resources/icons/tower_icons/fire_star.tres\",\"00T7\",\"CAGH\",\"S9VI\"\n238,\"Twin Disciplines\",\"0\",,\"res://resources/icons/swords/greatsword_03.tres\",\"JNFU\",\"5CC3\",\"SWZ0\"\n239,\"Twin Flames\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"9ERK\",\"LKDB\",\"3YTE\"\n240,\"Twin Pulses\",\"900\",\"CREEPS\",\"res://resources/icons/tower_icons/fire_star.tres\",\"INRP\",\"AZI6\",\"99JG\"\n241,\"Twin Disciplines\",\"0\",,\"res://resources/icons/swords/greatsword_03.tres\",\"1BBZ\",\"YIP6\",\"6UYT\"\n242,\"Icy Touch\",\"0\",,\"res://resources/icons/gloves/gloves_07.tres\",\"FCY1\",\"8MU6\",\"MEMI\"\n243,\"Frost Bolt\",\"0\",,\"res://resources/icons/tower_variations/meteor_totem_blue.tres\",\"91RZ\",\"4IE4\",\"LWP6\"\n244,\"Cold Blood\",\"0\",,\"res://resources/icons/potions/potion_10.tres\",\"PD39\",\"OIAP\",\"XYG0\"\n245,\"Dark Ritual\",\"0\",,\"res://resources/icons/furniture/artifact_on_pedestal.tres\",\"OYMS\",\"WJ76\",\"Q212\"\n246,\"It Hunger\",\"0\",,\"res://resources/icons/furniture/wooden_stand_with_nail.tres\",\"R4GT\",\"X2XA\",\"TASJ\"\n247,\"Mana Break\",\"0\",,\"res://resources/icons/rockets/rocket_07.tres\",\"E9KT\",\"R58F\",\"MED5\"\n248,\"Mana Break\",\"0\",,\"res://resources/icons/rockets/rocket_07.tres\",\"5X7Y\",\"1KQL\",\"DNAA\"\n249,\"Mana Break\",\"0\",,\"res://resources/icons/rockets/rocket_07.tres\",\"LVFQ\",\"MZ42\",\"DSIN\"\n250,\"Mana Break\",\"0\",,\"res://resources/icons/rockets/rocket_07.tres\",\"LKT2\",\"62WH\",\"FW3C\"\n251,\"Soul Consumption\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"BVN9\",\"ZCJ4\",\"W6QO\"\n252,\"Soul Consumption\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"XRHP\",\"0UAI\",\"LU3P\"\n253,\"Fear the Dark\",\"0\",,\"res://resources/icons/undead/skull_06.tres\",\"2GMB\",\"L42P\",\"62IC\"\n254,\"Frozen Spears\",\"0\",,\"res://resources/icons/spears/many_spears_02.tres\",\"1ZYC\",\"P5HJ\",\"OH6E\"\n255,\"Frozen Spears\",\"0\",,\"res://resources/icons/spears/many_spears_02.tres\",\"BUKD\",\"Q7MW\",\"S9AS\"\n256,\"Frozen Spears\",\"0\",,\"res://resources/icons/spears/many_spears_02.tres\",\"AGCO\",\"JO00\",\"B1NC\"\n257,\"Frozen Spears\",\"0\",,\"res://resources/icons/spears/many_spears_02.tres\",\"72YE\",\"J2ER\",\"P96M\"\n258,\"Frozen Spears\",\"0\",,\"res://resources/icons/spears/many_spears_02.tres\",\"YRL0\",\"228Q\",\"CLWM\"\n259,\"Rampage\",\"0\",,\"res://resources/icons/misc/red_knight.tres\",\"B66U\",\"DYQO\",\"U87B\"\n260,\"Rampage\",\"0\",,\"res://resources/icons/misc/red_knight.tres\",\"I486\",\"5XRS\",\"QOJT\"\n261,\"Rampage\",\"0\",,\"res://resources/icons/misc/red_knight.tres\",\"IA6K\",\"RRPK\",\"CHOP\"\n262,\"Spellfire\",\"0\",,\"res://resources/icons/scrolls/scroll_03.tres\",\"KQ2F\",\"6K8W\",\"GQWR\"\n263,\"Spellfire Projectiles\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"1CFU\",\"O7YA\",\"IE5S\"\n264,\"Spellfire\",\"0\",,\"res://resources/icons/scrolls/scroll_03.tres\",\"1VPP\",\"CFYJ\",\"3AVL\"\n265,\"Spellfire Projectiles\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"8GN9\",\"5SIZ\",\"C0EV\"\n266,\"Spellfire\",\"0\",,\"res://resources/icons/scrolls/scroll_03.tres\",\"RKIL\",\"7UBD\",\"PYMF\"\n267,\"Spellfire Projectiles\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"902A\",\"7DEL\",\"0BWX\"\n268,\"Thunderous Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"2DY9\",\"NJJ3\",\"C029\"\n269,\"Thunderous Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"H28G\",\"F7SI\",\"EDZX\"\n270,\"Thunderous Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"KIDW\",\"RO5H\",\"V8ZY\"\n271,\"Thunderous Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"URBL\",\"CVSZ\",\"35W1\"\n272,\"Thunderous Roar\",\"420\",\"TOWERS\",\"res://resources/icons/animals/dragon_03.tres\",\"4Z3C\",\"PW59\",\"92CI\"\n273,\"Ice Smashing Axe\",\"0\",,\"res://resources/icons/weapons_misc/axe_01.tres\",\"F7S8\",\"NDN3\",\"KU25\"\n274,\"Ice Coated Axes\",\"0\",,\"res://resources/icons/weapons_misc/glaive_01.tres\",\"U6T0\",\"P8JF\",\"ZUV9\"\n275,\"Ice Smashing Axe\",\"0\",,\"res://resources/icons/weapons_misc/axe_01.tres\",\"AVSA\",\"KYI6\",\"2AN4\"\n276,\"Ice Coated Axes\",\"0\",,\"res://resources/icons/weapons_misc/glaive_01.tres\",\"UVHZ\",\"USWX\",\"7S6W\"\n277,\"Ice Smashing Axe\",\"0\",,\"res://resources/icons/weapons_misc/axe_01.tres\",\"TTDL\",\"GLV3\",\"DCZO\"\n278,\"Ice Coated Axes\",\"0\",,\"res://resources/icons/weapons_misc/glaive_01.tres\",\"XCG5\",\"PRAB\",\"1G22\"\n279,\"Leaf Storm\",\"0\",,\"res://resources/icons/plants/leaf_01.tres\",\"6U9B\",\"TEIS\",\"148F\"\n280,\"Thorned!\",\"950\",\"CREEPS\",\"res://resources/icons/tower_icons/razorboar_thornweaver.tres\",\"AGA8\",\"3WSD\",\"MX4E\"\n281,\"Valor's Light\",\"800\",\"CREEPS\",\"res://resources/icons/tower_icons/small_light.tres\",\"YJP5\",\"DSZK\",\"3F1T\"\n282,\"Last Line of Defense\",\"400\",\"TOWERS\",\"res://resources/icons/shields/shield_castle.tres\",\"4I4K\",\"321C\",\"4C14\"\n283,\"Dark Orbs\",\"0\",,\"res://resources/icons/tower_icons/dark_battery.tres\",\"CNBU\",\"XLSS\",\"30L7\"\n284,\"Soul Conversion\",\"0\",,\"res://resources/icons/shields/shield_with_emblem.tres\",\"3OUY\",\"MIOU\",\"JJFK\"\n285,\"Arcane Orb\",\"0\",,\"res://resources/icons/tower_icons/dark_battery.tres\",\"HPSQ\",\"HIAE\",\"143U\"\n286,\"Grotesque Awakening\",\"0\",,\"res://resources/icons/animals/bat_03.tres\",\"KZX9\",\"7F55\",\"WHFK\"\n287,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"TCUO\",\"R64B\",\"60EY\"\n288,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"A16V\",\"Q6B9\",\"3LCD\"\n289,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"7P0Z\",\"QTG4\",\"YJFI\"\n290,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"X6G7\",\"TKRG\",\"X8VW\"\n291,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"HYWZ\",\"ESB7\",\"IDIS\"\n292,\"Poisoned Heart\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"1N2N\",\"TGSF\",\"F876\"\n293,\"Poisoned Heart\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"FH34\",\"QK7F\",\"RT3X\"\n294,\"Poisoned Heart\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"RX1N\",\"4CMS\",\"9JXT\"\n295,\"Poisoned Heart\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"T5BI\",\"C02U\",\"JBXI\"\n296,\"Poisoned Heart\",\"0\",,\"res://resources/icons/misc/poison_01.tres\",\"NCFA\",\"ZPUJ\",\"RSSD\"\n297,\"Aqua Breath\",\"0\",,\"res://resources/icons/magic/lock_04.tres\",\"6T31\",\"R0HI\",\"KLC0\"\n298,\"Cold Blooded\",\"0\",,\"res://resources/icons/gems/gem_03.tres\",\"W9QB\",\"7SN3\",\"00N3\"\n299,\"Splash\",\"0\",,\"res://resources/icons/trinkets/trinket_02.tres\",\"EQY2\",\"5R3A\",\"Q9FD\"\n300,\"Aqua Breath\",\"0\",,\"res://resources/icons/magic/lock_04.tres\",\"8CMM\",\"0IPK\",\"5RA6\"\n301,\"Cold Blooded\",\"0\",,\"res://resources/icons/gems/gem_03.tres\",\"PLOS\",\"OXDF\",\"G0E7\"\n302,\"Splash\",\"0\",,\"res://resources/icons/trinkets/trinket_02.tres\",\"42GX\",\"8B3R\",\"8OGO\"\n303,\"Aqua Breath\",\"0\",,\"res://resources/icons/magic/lock_04.tres\",\"ADV1\",\"5L0G\",\"PUHO\"\n304,\"Cold Blooded\",\"0\",,\"res://resources/icons/gems/gem_03.tres\",\"7Y6O\",\"BJQ6\",\"QHEY\"\n305,\"Splash\",\"0\",,\"res://resources/icons/trinkets/trinket_02.tres\",\"0CRE\",\"86VN\",\"Q7LW\"\n306,\"Lightning Shock\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"OOIJ\",\"SWJB\",\"EGZ4\"\n307,\"Lightning Shock\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"I1D1\",\"6O1J\",\"CUX3\"\n308,\"Maledict\",\"0\",,\"res://resources/icons/orbs/orb_shadow.tres\",\"OVMY\",\"19XQ\",\"GYQA\"\n309,\"Rampage of Pigs\",\"0\",,\"res://resources/icons/food/pork_without_plate.tres\",\"9NLA\",\"W9TI\",\"TN8X\"\n310,\"Initiative\",\"900\",\"CREEPS\",\"res://resources/icons/weapons_misc/barbed_spike.tres\",\"9V6H\",\"UEU3\",\"V664\"\n311,\"Rampage of Pigs\",\"0\",,\"res://resources/icons/food/pork_without_plate.tres\",\"MV25\",\"L8XR\",\"7TCX\"\n312,\"Initiative\",\"900\",\"CREEPS\",\"res://resources/icons/weapons_misc/barbed_spike.tres\",\"C5XX\",\"HE96\",\"WY6V\"\n313,\"Rampage of Pigs\",\"0\",,\"res://resources/icons/food/pork_without_plate.tres\",\"M9SA\",\"9PXO\",\"QBSV\"\n314,\"Initiative\",\"1400\",\"CREEPS\",\"res://resources/icons/weapons_misc/barbed_spike.tres\",\"FXQI\",\"WAUN\",\"CJ5J\"\n315,\"Storm Power\",\"0\",,\"res://resources/icons/tower_icons/lightning_generator.tres\",\"QMZ9\",\"IIM3\",\"ZGUH\"\n316,\"Chaining Storm\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"15TP\",\"MREA\",\"RWFY\"\n317,\"Cold\",\"0\",,\"res://resources/icons/magic/eye_blue.tres\",\"Z6BR\",\"SDSU\",\"BJEJ\"\n318,\"Cold\",\"0\",,\"res://resources/icons/magic/eye_blue.tres\",\"LKWW\",\"BW0E\",\"9HHL\"\n319,\"Phaze\",\"0\",,\"res://resources/icons/mechanical/lamp.tres\",\"DBW7\",\"W7EH\",\"7L29\"\n320,\"Phaze\",\"0\",,\"res://resources/icons/mechanical/lamp.tres\",\"9G0E\",\"9O86\",\"E1F6\"\n321,\"Phaze\",\"0\",,\"res://resources/icons/mechanical/lamp.tres\",\"IAON\",\"AWKE\",\"QHZ5\"\n322,\"Phaze\",\"0\",,\"res://resources/icons/mechanical/lamp.tres\",\"EEJK\",\"LM6I\",\"Q19A\"\n323,\"Phaze\",\"0\",,\"res://resources/icons/mechanical/lamp.tres\",\"ZI8T\",\"5CIH\",\"L4XA\"\n324,\"Dimensional Distortion Field\",\"800\",\"CREEPS\",\"res://resources/icons/dioramas/fountain.tres\",\"X1JW\",\"CT53\",\"YZRI\"\n325,\"Tomb's Curse\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"XCR2\",\"AB9T\",\"0TW5\"\n326,\"Tomb's Curse\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"7PYF\",\"C4GD\",\"MSDL\"\n327,\"Tomb's Curse\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"2SB8\",\"RAPF\",\"JDL6\"\n328,\"Tomb's Curse\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"4FGM\",\"BYY5\",\"2RG5\"\n329,\"Tomb's Curse\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"NROW\",\"8IIU\",\"BA11\"\n330,\"Tomb's Curse\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_purple.tres\",\"1TT6\",\"6V19\",\"8NE6\"\n331,\"Wind of Death\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"M5FN\",\"I7ZS\",\"EJEW\"\n332,\"Wind of Death\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"4HM2\",\"ZAAH\",\"A1OK\"\n333,\"Wind of Death\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"ITAT\",\"036L\",\"IJZI\"\n334,\"Wind of Death\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"XONF\",\"F1OD\",\"RB68\"\n335,\"Wind of Death\",\"0\",,\"res://resources/icons/elements/storm.tres\",\"D2OA\",\"S86O\",\"7BQL\"\n336,\"Insatiable Hunger\",\"0\",,\"res://resources/icons/helmets/helmet_07.tres\",\"ZYIQ\",\"PC3G\",\"BPCQ\"\n337,\"Withering Presence\",\"900\",\"CREEPS\",\"res://resources/icons/tower_icons/lesser_skeletal_mage.tres\",\"1RE8\",\"Z6TD\",\"WC8H\"\n338,\"Morphling Strike\",\"900\",\"CREEPS\",\"res://resources/icons/misc/poison_01.tres\",\"LL7M\",\"VS8A\",\"SGP9\"\n339,\"Evolve\",\"0\",,\"res://resources/icons/plants/tree.tres\",\"6HWH\",\"1WB9\",\"DQI0\"\n340,\"Frost\",\"0\",,\"res://resources/icons/orbs/orb_ice.tres\",\"9EIN\",\"9JU6\",\"ZPUU\"\n341,\"Frost\",\"0\",,\"res://resources/icons/orbs/orb_ice.tres\",\"KFS6\",\"4KEQ\",\"BLGR\"\n342,\"Frost\",\"0\",,\"res://resources/icons/orbs/orb_ice.tres\",\"CU63\",\"G675\",\"GFQD\"\n343,\"Activate Trap\",\"950\",\"CREEPS\",\"res://resources/icons/furniture/chest.tres\",\"2H1Z\",\"VTXC\",\"MJ97\"\n344,\"Activate Trap\",\"950\",\"CREEPS\",\"res://resources/icons/furniture/chest.tres\",\"CVCU\",\"8J6U\",\"5OSR\"\n345,\"Activate Trap\",\"950\",\"CREEPS\",\"res://resources/icons/furniture/chest.tres\",\"4UMO\",\"F1CH\",\"HD9R\"\n346,\"Activate Trap\",\"950\",\"CREEPS\",\"res://resources/icons/furniture/chest.tres\",\"N0XA\",\"8JIX\",\"8I9S\"\n347,\"Activate Trap\",\"950\",\"CREEPS\",\"res://resources/icons/furniture/chest.tres\",\"RWYW\",\"4ZC5\",\"IOJ4\"\n348,\"Mana Feed\",\"0\",,\"res://resources/icons/magic/magic_stone.tres\",\"RAR4\",\"UI2L\",\"R8X5\"\n349,\"Lightning Burst\",\"0\",,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"GPEU\",\"FLC2\",\"M08N\"\n350,\"Mana Feed\",\"0\",,\"res://resources/icons/magic/magic_stone.tres\",\"MMGO\",\"8Y3H\",\"KPLA\"\n351,\"Lightning Burst\",\"0\",,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"NQ06\",\"WTGQ\",\"SYF5\"\n352,\"Mana Feed\",\"0\",,\"res://resources/icons/magic/magic_stone.tres\",\"T3PC\",\"QD6I\",\"921L\"\n353,\"Lightning Burst\",\"0\",,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"0X76\",\"KWDX\",\"C75I\"\n354,\"Mana Feed\",\"0\",,\"res://resources/icons/magic/magic_stone.tres\",\"TF6Y\",\"XW5D\",\"GEH3\"\n355,\"Lightning Burst\",\"0\",,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"6BEH\",\"22L5\",\"UWKL\"\n356,\"Faerie Fire\",\"0\",,\"res://resources/icons/plants/flower_06.tres\",\"58U9\",\"X3GA\",\"LW5M\"\n357,\"Faerie Fire\",\"0\",,\"res://resources/icons/plants/flower_06.tres\",\"H9JZ\",\"FEXA\",\"U4Z7\"\n358,\"Faerie Fire\",\"0\",,\"res://resources/icons/plants/flower_06.tres\",\"Y8RC\",\"VSXW\",\"S8IE\"\n359,\"Blood Spill\",\"200\",\"TOWERS\",\"res://resources/icons/helmets/helmet_06.tres\",\"WTNT\",\"S7Q5\",\"GK7E\"\n360,\"Blood Spill\",\"200\",\"TOWERS\",\"res://resources/icons/helmets/helmet_06.tres\",\"N67K\",\"SSDO\",\"IGZD\"\n361,\"Shadow Glaive\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"PYCC\",\"9W1I\",\"2PG3\"\n362,\"Star Glaive\",\"0\",,\"res://resources/icons/swords/greatsword_01.tres\",\"SKOO\",\"1KVC\",\"95CI\"\n363,\"Shadow Glaive\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"29AY\",\"V9WD\",\"QYRB\"\n364,\"Star Glaive\",\"0\",,\"res://resources/icons/swords/greatsword_01.tres\",\"KW2V\",\"S6MK\",\"06AG\"\n365,\"Shadow Glaive\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"5YYS\",\"WXUM\",\"762U\"\n366,\"Star Glaive\",\"0\",,\"res://resources/icons/swords/greatsword_01.tres\",\"DZNE\",\"0LTJ\",\"DGLH\"\n367,\"Corruption\",\"0\",,\"res://resources/icons/tower_variations/meteor_totem_purple.tres\",\"FGDL\",\"Q299\",\"FF9V\"\n368,\"Corruption\",\"0\",,\"res://resources/icons/tower_variations/meteor_totem_purple.tres\",\"DR3J\",\"Y5QT\",\"Y28V\"\n369,\"Corruption\",\"0\",,\"res://resources/icons/tower_variations/meteor_totem_purple.tres\",\"PVLB\",\"MMAD\",\"3MF0\"\n370,\"Poison\",\"0\",,\"res://resources/icons/potions/potion_green_02.tres\",\"FXS6\",\"KTYN\",\"D411\"\n371,\"Poison\",\"0\",,\"res://resources/icons/potions/potion_green_02.tres\",\"OLWH\",\"6EJU\",\"UMR0\"\n372,\"Poison\",\"0\",,\"res://resources/icons/potions/potion_green_02.tres\",\"Q218\",\"1IJI\",\"Y73R\"\n373,\"Incinerate\",\"0\",,\"res://resources/icons/tower_icons/ash_geyser.tres\",\"A9IG\",\"C78P\",\"ECZ4\"\n374,\"Incinerate\",\"0\",,\"res://resources/icons/tower_icons/ash_geyser.tres\",\"15T3\",\"K7O2\",\"L6I8\"\n375,\"Incinerate\",\"0\",,\"res://resources/icons/tower_icons/ash_geyser.tres\",\"65EM\",\"G8GM\",\"MO0I\"\n376,\"Electrify\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"JXTJ\",\"ULF9\",\"PTRW\"\n377,\"Electrify\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"DHBE\",\"5CXL\",\"LIMY\"\n378,\"Electrify\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"MFYY\",\"AXWC\",\"5FTT\"\n379,\"Wrath of Ymir\",\"0\",,\"res://resources/icons/animals/dragon_05.tres\",\"NZ36\",\"8FC2\",\"1NFG\"\n380,\"Blood of Ymir\",\"900\",\"CREEPS\",\"res://resources/icons/gems/gem_07.tres\",\"EI96\",\"3TST\",\"TB07\"\n381,\"Reimbursement\",\"0\",,\"res://resources/icons/mechanical/gold_machine.tres\",\"PPQU\",\"GU51\",\"EC8C\"\n382,\"Probability Field Emitter\",\"500\",\"TOWERS\",\"res://resources/icons/dioramas/fountain.tres\",\"2ZYR\",\"PLI0\",\"DYHR\"\n383,\"Clockwork Engineer\",\"500\",\"TOWERS\",\"res://resources/icons/mechanical/mech_badge.tres\",\"K52E\",\"AYLV\",\"KNWC\"\n384,\"Goblin Sapper\",\"0\",,\"res://resources/icons/faces/mech_zombie.tres\",\"MZYZ\",\"FCZ9\",\"YQHF\"\n385,\"Burn!\",\"0\",,\"res://resources/icons/fire/fire_bowl_02.tres\",\"63IX\",\"VAGE\",\"UDXX\"\n386,\"Double the Trouble\",\"0\",,\"res://resources/icons/cannons/cannon_05.tres\",\"PAEK\",\"SOWZ\",\"XB19\"\n387,\"Soul Scattering\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"B2TJ\",\"N5OA\",\"F6QU\"\n388,\"Shadowstrike\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"5K3B\",\"Q1DG\",\"B6WT\"\n389,\"Soul Scattering\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"EVUP\",\"NC14\",\"X6K0\"\n390,\"Shadowstrike\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"WYE8\",\"II4T\",\"F8J7\"\n391,\"Soul Scattering\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"730D\",\"FMP5\",\"DTKY\"\n392,\"Shadowstrike\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"1QVR\",\"I98A\",\"5M8C\"\n393,\"Soul Scattering\",\"0\",,\"res://resources/icons/gloves/curse.tres\",\"UCN3\",\"P8DX\",\"7B1W\"\n394,\"Shadowstrike\",\"0\",,\"res://resources/icons/swords/sword_swing_02.tres\",\"YFI2\",\"WIMJ\",\"Q4LG\"\n395,\"Fungus Strike\",\"0\",,\"res://resources/icons/tower_icons/razorboar_thornweaver.tres\",\"ZTNY\",\"HSTZ\",\"B69D\"\n396,\"Rapid Growth\",\"0\",,\"res://resources/icons/tower_icons/baby_plant.tres\",\"GBQR\",\"C9NJ\",\"EAGD\"\n397,\"Chain Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"TIHX\",\"4TI2\",\"HKG8\"\n398,\"Force Attack\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"3U9L\",\"60QJ\",\"7M0W\"\n399,\"Chain Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"IWPA\",\"APJS\",\"WQTI\"\n400,\"Force Attack\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"JPFD\",\"76N5\",\"P1Z2\"\n401,\"Chain Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"5W16\",\"HO02\",\"KE06\"\n402,\"Force Attack\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"BJT7\",\"VF1K\",\"QCOC\"\n403,\"Chain Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"7X1R\",\"L9Z0\",\"G5J7\"\n404,\"Force Attack\",\"0\",,\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"21WQ\",\"GFP5\",\"PKSX\"\n405,\"Burst Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"AOV1\",\"5XZO\",\"F3WC\"\n406,\"Burst Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"WOLW\",\"ZU8A\",\"24XC\"\n407,\"Burst Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"ARN1\",\"5TM3\",\"FFRA\"\n408,\"Burst Lightning\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"OAVI\",\"1MIC\",\"NDB6\"\n409,\"Afterglow\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"K5B8\",\"5UE0\",\"S5Y0\"\n410,\"Afterglow\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"E2CC\",\"XR5V\",\"Y4CC\"\n411,\"Afterglow\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"VE5Q\",\"DIKR\",\"0QXY\"\n412,\"Afterglow\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"RFPN\",\"WFG6\",\"Y703\"\n413,\"Afterglow\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"13VP\",\"C3LK\",\"UK3J\"\n414,\"Protectress's Wrath\",\"0\",,\"res://resources/icons/plants/leaf_01.tres\",\"XXRO\",\"NT2V\",\"WA7N\"\n415,\"Meld with the Forest\",\"0\",,\"res://resources/icons/faces/sleeping_leaf_spirit.tres\",\"Z8NI\",\"PFMV\",\"Z79U\"\n416,\"Power Surge\",\"0\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"AKMC\",\"YCA4\",\"HCXD\"\n417,\"Absorb Energy\",\"0\",,\"res://resources/icons/undead/skull_phazing.tres\",\"5X99\",\"SNK6\",\"G3RA\"\n418,\"Energy Acceleration\",\"0\",,\"res://resources/icons/trinkets/trinket_10.tres\",\"R0D1\",\"D872\",\"FHQH\"\n419,\"Errant Tachyons\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"AKH3\",\"6CP9\",\"6NRU\"\n420,\"Energy Acceleration\",\"0\",,\"res://resources/icons/trinkets/trinket_10.tres\",\"FSVP\",\"ECV8\",\"IG7S\"\n421,\"Errant Tachyons\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"UQD7\",\"NCJ2\",\"K6A7\"\n422,\"Energy Acceleration\",\"0\",,\"res://resources/icons/trinkets/trinket_10.tres\",\"G8EI\",\"X7VR\",\"382K\"\n423,\"Errant Tachyons\",\"0\",,\"res://resources/icons/magic/fire.tres\",\"G9Z8\",\"6A9Z\",\"7VTT\"\n424,\"Special Training\",\"0\",,\"res://resources/icons/books/book_06.tres\",\"09RL\",\"QLMT\",\"LZ76\"\n425,\"Helicopter Zone\",\"1000\",\"CREEPS\",\"res://resources/icons/armor/vest_02.tres\",\"IMC6\",\"NACI\",\"0VQZ\"\n426,\"Fireblossom\",\"0\",,\"res://resources/icons/plants/flower_02.tres\",\"EVVG\",\"R3AJ\",\"I4QT\"\n427,\"Fireblossom\",\"0\",,\"res://resources/icons/plants/flower_02.tres\",\"DYU9\",\"QMQX\",\"J1MW\"\n428,\"Fireblossom\",\"0\",,\"res://resources/icons/plants/flower_02.tres\",\"7XSU\",\"WZYQ\",\"KH0X\"\n429,\"Fireblossom\",\"0\",,\"res://resources/icons/plants/flower_02.tres\",\"TLXO\",\"SVNL\",\"NACD\"\n430,\"Fireblossom\",\"0\",,\"res://resources/icons/plants/flower_02.tres\",\"8VWF\",\"2Y8J\",\"83G2\"\n431,\"Fireblossom\",\"0\",,\"res://resources/icons/plants/flower_02.tres\",\"UYKG\",\"4Q7B\",\"7E2Q\"\n432,\"Moths of Prey\",\"0\",,\"res://resources/icons/animals/bat_03.tres\",\"ZXVJ\",\"SR8K\",\"TA54\"\n433,\"Rare Breed\",\"110\",\"TOWERS\",\"res://resources/icons/magic/eyes_many.tres\",\"015B\",\"LFYO\",\"R587\"\n434,\"Moths of Prey\",\"0\",,\"res://resources/icons/animals/bat_03.tres\",\"HP4E\",\"G5NW\",\"1CZI\"\n435,\"Rare Breed\",\"110\",\"TOWERS\",\"res://resources/icons/magic/eyes_many.tres\",\"CEDF\",\"4X6F\",\"Y2WT\"\n436,\"Moths of Prey\",\"0\",,\"res://resources/icons/animals/bat_03.tres\",\"ZR7R\",\"PKH6\",\"CB3E\"\n437,\"Rare Breed\",\"110\",\"TOWERS\",\"res://resources/icons/magic/eyes_many.tres\",\"RRJC\",\"SP1K\",\"9PSU\"\n438,\"Cannon\",\"0\",,\"res://resources/icons/cannons/cannon_07.tres\",\"MIYH\",\"56D1\",\"Y61W\"\n439,\"Soul Attack\",\"0\",,\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"HF49\",\"6KGV\",\"ODTO\"\n440,\"Panic\",\"0\",,\"res://resources/icons/undead/skull_03.tres\",\"3K8H\",\"M6QG\",\"M579\"\n441,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"2H76\",\"BXIR\",\"PPCH\"\n442,\"Lightning Strike\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"MJHL\",\"1RQM\",\"9O9W\"\n443,\"Hail of Axes\",\"0\",,\"res://resources/icons/hud/recipe_reassemble.tres\",\"8Q9G\",\"JCWG\",\"DQPT\"\n444,\"Hail of Axes\",\"0\",,\"res://resources/icons/hud/recipe_reassemble.tres\",\"9T7U\",\"0BQS\",\"E2GS\"\n445,\"Hail of Axes\",\"0\",,\"res://resources/icons/hud/recipe_reassemble.tres\",\"NOS4\",\"HAHA\",\"SJTB\"\n446,\"Hail of Axes\",\"0\",,\"res://resources/icons/hud/recipe_reassemble.tres\",\"26QQ\",\"6CK3\",\"HCQS\"\n447,\"Firestorm\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"N1DB\",\"ACM5\",\"1WRK\"\n448,\"Firestorm\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"2JZC\",\"2WZD\",\"VZSN\"\n449,\"Firestorm\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"GEIW\",\"E8SC\",\"W25E\"\n450,\"Firestorm\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"TB08\",\"03J2\",\"8EEE\"\n451,\"Versatile\",\"0\",,\"res://resources/icons/weapons_misc/barbed_spike.tres\",\"DS9R\",\"LEBH\",\"C0YP\"\n452,\"Unleash\",\"0\",,\"res://resources/icons/tower_icons/bronze_dragon_roost.tres\",\"6B8H\",\"US76\",\"UK6X\"\n453,\"Feed the Drakes\",\"1000\",\"CREEPS\",\"res://resources/icons/undead/skull_04.tres\",\"HEH6\",\"H55Y\",\"RSYO\"\n454,\"Knowledge\",\"600\",\"TOWERS\",\"res://resources/icons/dioramas/pyramid.tres\",\"6NDN\",\"4PUT\",\"HI5L\"\n455,\"Knowledge\",\"600\",\"TOWERS\",\"res://resources/icons/dioramas/pyramid.tres\",\"O7FE\",\"Y41T\",\"S0H1\"\n456,\"Knowledge\",\"600\",\"TOWERS\",\"res://resources/icons/dioramas/pyramid.tres\",\"8H7S\",\"174O\",\"BE6U\"\n457,\"Knowledge\",\"600\",\"TOWERS\",\"res://resources/icons/dioramas/pyramid.tres\",\"053L\",\"QAK1\",\"B94W\"\n458,\"Knowledge\",\"600\",\"TOWERS\",\"res://resources/icons/dioramas/pyramid.tres\",\"WVJ4\",\"SBE3\",\"CU9B\"\n459,\"Knowledge\",\"600\",\"TOWERS\",\"res://resources/icons/dioramas/pyramid.tres\",\"E868\",\"8W7K\",\"5GH7\"\n460,\"Soulfire\",\"0\",,\"res://resources/icons/fire/flame_purple.tres\",\"U7TM\",\"P90V\",\"7TY1\"\n461,\"Soul Consumption\",\"0\",,\"res://resources/icons/tower_icons/dark_battery.tres\",\"GQKV\",\"U91V\",\"R8FG\"\n462,\"Uncontrollable Flames\",\"0\",,\"res://resources/icons/hud/dice.tres\",\"DNN9\",\"2DZV\",\"Z4RN\"\n463,\"Lingering Flame\",\"0\",,\"res://resources/icons/fire/fire_bowl_01.tres\",\"LLQO\",\"2CXG\",\"AWAU\"\n464,\"Feed the Flames\",\"0\",,\"res://resources/icons/elements/fire.tres\",\"USD8\",\"HP6Q\",\"NFHG\"\n465,\"Lacerate\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"R92O\",\"F6JS\",\"9T0D\"\n466,\"Glaive Storm\",\"0\",,\"res://resources/icons/daggers/dagger_02.tres\",\"Q124\",\"I1IH\",\"9ZKJ\"\n467,\"Bounder\",\"0\",,\"res://resources/icons/daggers/dagger_04.tres\",\"WEJI\",\"M2UW\",\"C4NT\"\n468,\"Arcane Attraction\",\"0\",,\"res://resources/icons/trinkets/trinket_10.tres\",\"GQML\",\"K89G\",\"3ZU5\"\n469,\"Surge\",\"0\",,\"res://resources/icons/scrolls/scroll_08.tres\",\"MWMT\",\"KFKG\",\"JYZZ\"\n470,\"Mana Storm\",\"0\",,\"res://resources/icons/electricity/thunderstorm.tres\",\"QELP\",\"4BIL\",\"CDJ8\"\n471,\"Icicles\",\"0\",,\"res://resources/icons/gems/gem_03.tres\",\"WEB6\",\"X9L3\",\"DYAP\"\n472,\"Icy Bombardment\",\"0\",,\"res://resources/icons/trinkets/claw_03.tres\",\"FQWZ\",\"VXB9\",\"ZHEB\"\n473,\"Frostburn\",\"0\",,\"res://resources/icons/fire/flame_blue_glowing.tres\",\"FUE1\",\"7GP7\",\"T53K\"\n474,\"Eat the Dead\",\"0\",,\"res://resources/icons/undead/skull_01.tres\",\"W968\",\"2ME6\",\"35EV\"\n475,\"Acid Goo\",\"0\",,\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"G2K8\",\"SM4C\",\"VRPH\"\n476,\"Tentacle Attack\",\"1200\",\"CREEPS\",\"res://resources/icons/clubs/club_glowing.tres\",\"7NNS\",\"LN17\",\"CDWQ\"\n477,\"Icy Touch\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_blue.tres\",\"OAVP\",\"P4XU\",\"KT15\"\n478,\"Icy Touch\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_blue.tres\",\"PVOF\",\"F3EE\",\"79BD\"\n479,\"Icy Touch\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_blue.tres\",\"JSL1\",\"MBZW\",\"Z61M\"\n480,\"Icy Touch\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_blue.tres\",\"EK2W\",\"7Q88\",\"6H27\"\n481,\"Freezing Breath\",\"0\",,\"res://resources/icons/elements/ice.tres\",\"KJMU\",\"RUKI\",\"GKC6\"\n482,\"Acid Skull\",\"0\",,\"res://resources/icons/tower_variations/ash_geyser_green.tres\",\"QZQ4\",\"I4Q9\",\"5LTO\"\n483,\"Soulsteal\",\"0\",,\"res://resources/icons/undead/skull_phazing.tres\",\"MQLY\",\"4J4D\",\"PLL7\"\n484,\"Heat Stroke\",\"0\",,\"res://resources/icons/tower_icons/fire_star.tres\",\"CUAD\",\"JBGF\",\"I4BT\"\n485,\"Lava Attack\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"O48Q\",\"PB6C\",\"0WER\"\n486,\"Divine Knowledge\",\"500\",\"TOWERS\",\"res://resources/icons/holy/white_trinket.tres\",\"PMD9\",\"37WS\",\"BRTH\"\n487,\"Rock Throw\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_gray.tres\",\"7HOH\",\"3EWF\",\"ME5B\"\n488,\"Rock Throw\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_gray.tres\",\"EXJ1\",\"RKJM\",\"EJ1S\"\n489,\"Rock Throw\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_gray.tres\",\"XTGJ\",\"CFY1\",\"GMB3\"\n490,\"Rock Throw\",\"0\",,\"res://resources/icons/tower_variations/mossy_acid_sprayer_gray.tres\",\"NJBS\",\"7VD5\",\"S4GC\"\n491,\"Coconut Rain\",\"0\",,\"res://resources/icons/orbs/orb_green.tres\",\"XRB5\",\"W1ZC\",\"4YG0\"\n492,\"Coconut Rain\",\"0\",,\"res://resources/icons/orbs/orb_green.tres\",\"V8K0\",\"PLNU\",\"34MX\"\n493,\"Ice Shard\",\"0\",,\"res://resources/icons/gems/gem_03.tres\",\"LLVI\",\"31ZI\",\"W21H\"\n494,\"Liquide Ice\",\"0\",,\"res://resources/icons/potions/potion_10.tres\",\"A09W\",\"QEBS\",\"CX8T\"\n495,\"Overheat\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"CJMN\",\"NSCY\",\"QIZ6\"\n496,\"Overheat\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"CUOP\",\"YKFA\",\"W9VW\"\n497,\"Overheat\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"VL0Z\",\"FK26\",\"572Y\"\n498,\"Overheat\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"PLGI\",\"IF90\",\"FSIK\"\n499,\"Overheat\",\"0\",,\"res://resources/icons/orbs/orb_molten.tres\",\"UUNH\",\"PPUM\",\"Q6Y3\"\n500,\"Feral Aggression\",\"0\",,\"res://resources/icons/animals/rooster_warrior.tres\",\"3V28\",\"VF1U\",\"Y9ND\"\n501,\"Bloodthirst\",\"0\",,\"res://resources/icons/potions/potion_red_03.tres\",\"FMIB\",\"T84S\",\"Y3A9\"\n502,\"Feral Aggression\",\"0\",,\"res://resources/icons/animals/rooster_warrior.tres\",\"KJ85\",\"03MT\",\"1KOR\"\n503,\"Bloodthirst\",\"0\",,\"res://resources/icons/potions/potion_red_03.tres\",\"2T0N\",\"MV1M\",\"C5TL\"\n504,\"Feral Aggression\",\"0\",,\"res://resources/icons/animals/rooster_warrior.tres\",\"AUN0\",\"73QS\",\"14NX\"\n505,\"Bloodthirst\",\"0\",,\"res://resources/icons/potions/potion_red_03.tres\",\"P1TN\",\"MB8W\",\"HVFO\"\n506,\"Absolute Zero\",\"0\",,\"res://resources/icons/tower_icons/ebonfrost_crystal.tres\",\"IYMI\",\"0YA8\",\"CYDG\"\n507,\"Absolute Zero\",\"0\",,\"res://resources/icons/tower_icons/ebonfrost_crystal.tres\",\"VAJH\",\"CVT7\",\"07IC\"\n508,\"Absolute Zero\",\"0\",,\"res://resources/icons/tower_icons/ebonfrost_crystal.tres\",\"1X8N\",\"40GQ\",\"EVSA\"\n509,\"Hellfire\",\"0\",,\"res://resources/icons/orbs/orb_fire.tres\",\"T2YK\",\"ZIOY\",\"52HT\"\n510,\"Liquid Fire\",\"0\",,\"res://resources/icons/potions/potion_orange_03.tres\",\"KWMK\",\"J449\",\"I943\"\n511,\"Hot Coals\",\"0\",,\"res://resources/icons/fire/fire_bowl_02.tres\",\"007R\",\"XF4P\",\"8SKN\"\n512,\"Hot Coals\",\"0\",,\"res://resources/icons/fire/fire_bowl_02.tres\",\"2WFB\",\"3CR4\",\"JCSG\"\n513,\"Hot Coals\",\"0\",,\"res://resources/icons/fire/fire_bowl_02.tres\",\"2HHA\",\"ZKTX\",\"CWUP\"\n514,\"Hot Coals\",\"0\",,\"res://resources/icons/fire/fire_bowl_02.tres\",\"H6T1\",\"AL0I\",\"Q294\"\n515,\"Hot Coals\",\"0\",,\"res://resources/icons/fire/fire_bowl_02.tres\",\"IM84\",\"OV8Y\",\"HJIZ\"\n516,\"Multiply Gold\",\"0\",,\"res://resources/icons/mechanical/gold_machine.tres\",\"6P5N\",\"K3SX\",\"T7J6\"\n517,\"Multiply Gold\",\"0\",,\"res://resources/icons/mechanical/gold_machine.tres\",\"AMLR\",\"TN4R\",\"BSN8\"\n518,\"Channel Energy\",\"0\",,\"res://resources/icons/gems/earring_05.tres\",\"RFYG\",\"E9WF\",\"745K\"\n519,\"Channel Energy\",\"0\",,\"res://resources/icons/gems/earring_05.tres\",\"PAP7\",\"Y87D\",\"T45P\"\n520,\"Cursed Attack\",\"0\",,\"res://resources/icons/undead/skull_wand_02.tres\",\"GODJ\",\"AJT3\",\"8HFY\"\n521,\"Cursed Attack\",\"0\",,\"res://resources/icons/undead/skull_wand_02.tres\",\"Z7YA\",\"1XAL\",\"E7AN\"\n522,\"Cursed Attack\",\"0\",,\"res://resources/icons/undead/skull_wand_02.tres\",\"26AY\",\"SL05\",\"DWOY\"\n523,\"Inject Parasite\",\"0\",,\"res://resources/icons/animals/spider_03.tres\",\"DSRE\",\"071Z\",\"I1VY\"\n524,\"Ignite\",\"0\",,\"res://resources/icons/misc/teapot_04.tres\",\"1WAT\",\"DU21\",\"LIAM\"\n525,\"Ignite\",\"0\",,\"res://resources/icons/misc/teapot_04.tres\",\"PSS7\",\"M284\",\"FANB\"\n526,\"Ignite\",\"0\",,\"res://resources/icons/misc/teapot_04.tres\",\"ZUUZ\",\"AZF2\",\"UEF4\"\n527,\"Ignite\",\"0\",,\"res://resources/icons/misc/teapot_04.tres\",\"WUQW\",\"WI5E\",\"UQI0\"\n528,\"Ignite\",\"0\",,\"res://resources/icons/misc/teapot_04.tres\",\"SGG5\",\"WL4R\",\"HHB1\"\n529,\"Torture\",\"0\",,\"res://resources/icons/tower_icons/ash_geyser.tres\",\"URRG\",\"H6HM\",\"O991\"\n530,\"Overload\",\"0\",,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"SR1Q\",\"C55Y\",\"5QMM\"\n531,\"Banish\",\"0\",,\"res://resources/icons/magic/magic_stone_green.tres\",\"WMFL\",\"SMAC\",\"6UPA\"\n532,\"Banish\",\"0\",,\"res://resources/icons/magic/magic_stone_green.tres\",\"72DO\",\"CPGK\",\"S3MM\"\n533,\"Banish\",\"0\",,\"res://resources/icons/magic/magic_stone_green.tres\",\"QO78\",\"KSYO\",\"74P0\"\n534,\"Banish\",\"0\",,\"res://resources/icons/magic/magic_stone_green.tres\",\"EZ0O\",\"U1AL\",\"F4GP\"\n535,\"Banish\",\"0\",,\"res://resources/icons/magic/magic_stone_green.tres\",\"HIG0\",\"0VDV\",\"J9I4\"\n536,\"Glacial Wrath\",\"0\",,\"res://resources/icons/tower_icons/genis_sage.tres\",\"POUH\",\"XG1J\",\"PJW0\"\n537,\"Grace\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"6IP1\",\"0GK9\",\"5BCN\"\n538,\"Grace\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"DQGG\",\"DV14\",\"HVSX\"\n539,\"Grace\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"DM6I\",\"F3NM\",\"8HU2\"\n540,\"Grace\",\"0\",,\"res://resources/icons/gloves/heal.tres\",\"R716\",\"IBTR\",\"PA2S\"\n541,\"Smite\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"EYVQ\",\"ZZKK\",\"M7S6\"\n542,\"Smite\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"2FO1\",\"F4LV\",\"T4YJ\"\n543,\"Smite\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"7VX9\",\"6E93\",\"6LTW\"\n544,\"Smite\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"ID2K\",\"WVW4\",\"79DR\"\n545,\"Smite\",\"0\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"9FSR\",\"MERI\",\"8E0U\"\n546,\"Advanced Multishot\",\"0\",,\"res://resources/icons/bows/bow_01.tres\",\"SLUM\",\"HX2N\",\"40EN\"\n547,\"Gift of the Forest\",\"0\",,\"res://resources/icons/plants/plant_in_pot.tres\",\"7C5U\",\"RSAT\",\"RLCN\"\n548,\"Advanced Multishot\",\"0\",,\"res://resources/icons/bows/bow_01.tres\",\"006O\",\"NLH8\",\"B9GO\"\n549,\"Gift of the Forest\",\"0\",,\"res://resources/icons/plants/plant_in_pot.tres\",\"ZCDL\",\"A7BA\",\"RI9D\"\n550,\"Advanced Multishot\",\"0\",,\"res://resources/icons/bows/bow_01.tres\",\"F9KH\",\"W4T6\",\"51Q0\"\n551,\"Gift of the Forest\",\"0\",,\"res://resources/icons/plants/plant_in_pot.tres\",\"MGUM\",\"STNQ\",\"Y78A\"\n552,\"Pirates\",\"0\",,\"res://resources/icons/tower_icons/dutchmans_grave.tres\",\"7K0R\",\"4D51\",\"VC3K\"\n553,\"Pirates\",\"0\",,\"res://resources/icons/tower_icons/dutchmans_grave.tres\",\"1TCN\",\"7L3M\",\"TJD2\"\n554,\"Pirates\",\"0\",,\"res://resources/icons/tower_icons/dutchmans_grave.tres\",\"5E5D\",\"14W4\",\"SEOY\"\n555,\"Pirates\",\"0\",,\"res://resources/icons/tower_icons/dutchmans_grave.tres\",\"QA3L\",\"7DEP\",\"LG5B\"\n556,\"High Knowledge\",\"0\",,\"res://resources/icons/books/book_07.tres\",\"Q0AV\",\"23JG\",\"QL7C\"\n557,\"High Knowledge\",\"0\",,\"res://resources/icons/books/book_07.tres\",\"XRQQ\",\"M3T7\",\"WXK7\"\n558,\"High Knowledge\",\"0\",,\"res://resources/icons/books/book_07.tres\",\"98QB\",\"JD1F\",\"DQZF\"\n559,\"High Knowledge\",\"0\",,\"res://resources/icons/books/book_07.tres\",\"XGUQ\",\"RE12\",\"YFBY\"\n560,\"High Knowledge\",\"0\",,\"res://resources/icons/books/book_07.tres\",\"TZ50\",\"50NF\",\"0S2J\"\n561,\"Goldrush\",\"0\",,\"res://resources/icons/gems/gem_01.tres\",\"OJ9H\",\"MBNG\",\"RVZ1\"\n562,\"Excavation\",\"0\",,\"res://resources/icons/misc/gold_cart.tres\",\"COH7\",\"ERN3\",\"AMAG\"\n563,\"Dire Instinct\",\"0\",,\"res://resources/icons/shields/shield_wood_small_glowing.tres\",\"XKZZ\",\"FYTD\",\"FCP2\"\n564,\"Bone Shatter\",\"0\",,\"res://resources/icons/swords/greatsword_01.tres\",\"FMY6\",\"Q1UD\",\"522N\"\n565,\"Embers\",\"300\",\"TOWERS\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"YBSL\",\"NNE4\",\"ZJH3\"\n566,\"Nova Storm\",\"900\",\"CREEPS\",\"res://resources/icons/magic/claw_02.tres\",\"DC58\",\"W7O1\",\"S63A\"\n567,\"Nova Storm\",\"900\",\"CREEPS\",\"res://resources/icons/magic/claw_02.tres\",\"PBC2\",\"TDMV\",\"MGYJ\"\n568,\"Nova Storm\",\"900\",\"CREEPS\",\"res://resources/icons/magic/claw_02.tres\",\"YMZF\",\"KBC8\",\"7P5W\"\n569,\"Plague\",\"0\",,\"res://resources/icons/undead/skull_04.tres\",\"O2GW\",\"0DUA\",\"DHZ4\"\n570,\"Army of the Damned\",\"1150\",\"CREEPS\",\"res://resources/icons/shields/shield_skull.tres\",\"PNNP\",\"Y5W8\",\"L08H\"\n571,\"Dreadlord Slash\",\"0\",,\"res://resources/icons/daggers/dagger_07.tres\",\"AG4A\",\"WHB5\",\"PK49\"\n572,\"Bloodsucker\",\"0\",,\"res://resources/icons/gems/gem_07.tres\",\"SDBP\",\"KBX3\",\"BLEB\"\n573,\"Icy Curse\",\"0\",,\"res://resources/icons/furniture/furniture.tres\",\"IM5Y\",\"IHXY\",\"K4MG\"\n574,\"Wrath of the Storm\",\"0\",,\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"HTLW\",\"KVCV\",\"SVB1\"\n575,\"Wrath of the Storm\",\"0\",,\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"KAZE\",\"ZYY2\",\"R581\"\n576,\"Wrath of the Storm\",\"0\",,\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"5TRV\",\"6VVY\",\"QX4J\"\n577,\"Wrath of the Storm\",\"0\",,\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"6I0Q\",\"WQBB\",\"21FK\"\n578,\"Wrath of the Storm\",\"0\",,\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"8YBX\",\"FROL\",\"L84O\"\n579,\"Wrath of the Storm\",\"0\",,\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"JSVV\",\"M2ME\",\"MIKM\"\n580,\"Planeshift\",\"0\",,\"res://resources/icons/tower_icons/harpy_witch.tres\",\"ZC39\",\"DBI2\",\"G328\"\n581,\"Essence of the Mortals\",\"0\",,\"res://resources/icons/dioramas/mountain.tres\",\"XS6D\",\"ASN2\",\"9GIB\"\n582,\"Toxic Vapor\",\"0\",,\"res://resources/icons/mechanical/factory_fumes.tres\",\"AW86\",\"MWYM\",\"TCDC\"\n583,\"Toxic Vapor\",\"0\",,\"res://resources/icons/mechanical/factory_fumes.tres\",\"W4SA\",\"X0PF\",\"F2TF\"\n584,\"Toxic Vapor\",\"0\",,\"res://resources/icons/mechanical/factory_fumes.tres\",\"MKPG\",\"EV90\",\"TM9P\"\n585,\"Toxic Vapor\",\"0\",,\"res://resources/icons/mechanical/factory_fumes.tres\",\"HBCN\",\"5Q4V\",\"M96S\"\n586,\"Burn\",\"0\",,\"res://resources/icons/fire/torch.tres\",\"OCV8\",\"OZF8\",\"QJKG\"\n587,\"Burn\",\"0\",,\"res://resources/icons/fire/torch.tres\",\"C6BE\",\"3LFC\",\"PZDK\"\n588,\"Burn\",\"0\",,\"res://resources/icons/fire/torch.tres\",\"6KGN\",\"0OFV\",\"GBGB\"\n589,\"Burn\",\"0\",,\"res://resources/icons/fire/torch.tres\",\"70V8\",\"IH7F\",\"HMUF\"\n590,\"Rocket Strike\",\"0\",,\"res://resources/icons/rockets/rocket_01.tres\",\"7IPO\",\"9PMO\",\"8SN1\"\n591,\"Rocket Strike\",\"0\",,\"res://resources/icons/rockets/rocket_01.tres\",\"ZD5E\",\"3V2T\",\"U7RL\"\n592,\"Rocket Strike\",\"0\",,\"res://resources/icons/rockets/rocket_01.tres\",\"JPHP\",\"26AS\",\"08AT\"\n593,\"Rocket Strike\",\"0\",,\"res://resources/icons/rockets/rocket_01.tres\",\"8JKF\",\"SC52\",\"LU8Z\"\n594,\"Blessed Weapon\",\"0\",,\"res://resources/icons/holy/cross_01.tres\",\"PYVL\",\"RFWA\",\"XUDE\"\n595,\"Blessed Weapon\",\"0\",,\"res://resources/icons/holy/cross_01.tres\",\"X104\",\"PR08\",\"J9DK\"\n596,\"Entangle\",\"0\",,\"res://resources/icons/plants/branch_01.tres\",\"ZDEY\",\"ZZLR\",\"20BR\"\n597,\"Entangle\",\"0\",,\"res://resources/icons/plants/branch_01.tres\",\"55J7\",\"M09J\",\"GJJA\"\n598,\"Entangle\",\"0\",,\"res://resources/icons/plants/branch_01.tres\",\"JRLE\",\"HVMD\",\"LVI7\"\n599,\"Entangle\",\"0\",,\"res://resources/icons/plants/branch_01.tres\",\"E3U9\",\"5M40\",\"1CBP\"\n600,\"Cold Feet\",\"0\",,\"res://resources/icons/furniture/furniture.tres\",\"VMH4\",\"KLRD\",\"6BVD\"\n601,\"Cold Feet\",\"0\",,\"res://resources/icons/furniture/furniture.tres\",\"V79P\",\"M0JF\",\"QH0G\"\n602,\"Cold Feet\",\"0\",,\"res://resources/icons/furniture/furniture.tres\",\"751T\",\"ISLO\",\"5QKW\"\n603,\"Glacial Wrath\",\"0\",,\"res://resources/icons/tower_icons/genis_sage.tres\",\"383M\",\"XF9Y\",\"WP51\"\n604,\"Glacial Wrath\",\"0\",,\"res://resources/icons/tower_icons/genis_sage.tres\",\"F5DX\",\"PR1C\",\"7VGU\"\n605,\"Glacial Wrath\",\"0\",,\"res://resources/icons/tower_icons/genis_sage.tres\",\"CH41\",\"RX43\",\"UKJP\"\n606,\"Glacial Wrath\",\"0\",,\"res://resources/icons/tower_icons/genis_sage.tres\",\"HTP2\",\"KAAR\",\"DDUB\"\n607,\"Dire Instinct\",\"0\",,\"res://resources/icons/shields/shield_wood_small_glowing.tres\",\"R08H\",\"RDX6\",\"AILG\"\n608,\"Bone Shatter\",\"0\",,\"res://resources/icons/swords/greatsword_01.tres\",\"JJTW\",\"JXBZ\",\"I3CC\"\n609,\"Embers\",\"300\",\"TOWERS\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"M1V6\",\"M2GW\",\"SM9B\"\n610,\"Embers\",\"300\",\"TOWERS\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"DN33\",\"QMKJ\",\"EU0A\"\n611,\"Embers\",\"300\",\"TOWERS\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"RCP2\",\"VVGP\",\"THXX\"\n612,\"Embers\",\"300\",\"TOWERS\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"90MN\",\"XDFS\",\"TTII\"\n613,\"Cripple\",0,,\"res://resources/icons/furniture/furniture.tres\",\"VYTV\",\"MXMZ\",\"MXMZ\"\n614,\"Activate Trap\",0,,\"res://resources/icons/furniture/furniture.tres\",\"F4SZ\",\"Q4JJ\",\"Q4JJ\"\n615,\"Pay With Blood\",0,,\"res://resources/icons/furniture/furniture.tres\",\"ZJVP\",\"P2W7\",\"P2W7\"\n616,\"Multishot\",0,,\"res://resources/icons/furniture/furniture.tres\",\"F3PD\",\"IZY1\",\"IZY1\"\n617,\"Crush!\",0,,\"res://resources/icons/furniture/furniture.tres\",\"N0W1\",\"QA7W\",\"QA7W\"\n618,\"Ancient Rage\",0,,\"res://resources/icons/furniture/furniture.tres\",\"I6T0\",\"M2UY\",\"M2UY\"\n619,\"Power of the Sword\",0,,\"res://resources/icons/furniture/furniture.tres\",\"BTXE\",\"FA5J\",\"FA5J\"\n620,\"Magic Weapon\",0,,\"res://resources/icons/furniture/furniture.tres\",\"SWJI\",\"B4CR\",\"B4CR\"\n621,\"Blindingly Polished Armor\",0,,\"res://resources/icons/furniture/furniture.tres\",\"SH2H\",\"UWXP\",\"UWXP\"\n622,\"Rich\",0,,\"res://resources/icons/furniture/furniture.tres\",\"VCIO\",\"QYNG\",\"QYNG\"\n623,\"Celestial Wisdom\",0,,\"res://resources/icons/furniture/furniture.tres\",\"GS14\",\"BEQO\",\"BEQO\"\n624,\"Enlighten\",0,,\"res://resources/icons/furniture/furniture.tres\",\"YMSS\",\"NDQ0\",\"NDQ0\"\n625,\"Spiderling Poison\",0,,\"res://resources/icons/furniture/furniture.tres\",\"U1ZL\",\"A6SD\",\"A6SD\"\n626,\"Purify\",0,,\"res://resources/icons/furniture/furniture.tres\",\"JMET\",\"XE1N\",\"XE1N\"\n627,\"Greed Is Good\",0,,\"res://resources/icons/furniture/furniture.tres\",\"SLDA\",\"L2MV\",\"L2MV\"\n628,\"Piercing Magic\",0,,\"res://resources/icons/furniture/furniture.tres\",\"HPVG\",\"SNOI\",\"SNOI\"\n629,\"Resonance\",0,,\"res://resources/icons/furniture/furniture.tres\",\"BGPP\",\"VKZ2\",\"VKZ2\"\n630,\"Earth and Moon\",0,,\"res://resources/icons/furniture/furniture.tres\",\"XS57\",\"J712\",\"J712\"\n631,\"Hippogryph Young\",0,,\"res://resources/icons/furniture/furniture.tres\",\"J96J\",\"AMNO\",\"AMNO\"\n632,\"Mana Charge\",0,,\"res://resources/icons/furniture/furniture.tres\",\"WA64\",\"WEI1\",\"WEI1\"\n633,\"Absorb\",0,,\"res://resources/icons/furniture/furniture.tres\",\"UZD0\",\"UPJG\",\"UPJG\"\n634,\"Deadly Poison\",0,,\"res://resources/icons/furniture/furniture.tres\",\"ED23\",\"V4LB\",\"V4LB\"\n635,\"Energy Drainer\",0,,\"res://resources/icons/furniture/furniture.tres\",\"AOLL\",\"E6FH\",\"E6FH\"\n636,\"Bartuc's Spirit\",0,,\"res://resources/icons/furniture/furniture.tres\",\"RK4M\",\"SXSG\",\"SXSG\"\n637,\"Fervor\",0,,\"res://resources/icons/furniture/furniture.tres\",\"I1P4\",\"OV4E\",\"OV4E\"\n638,\"Headhunt\",0,,\"res://resources/icons/furniture/furniture.tres\",\"HI1X\",\"PGKB\",\"PGKB\"\n639,\"Play With Me!\",0,,\"res://resources/icons/furniture/furniture.tres\",\"K6PD\",\"PBGE\",\"PBGE\"\n640,\"Bloodthirst\",0,,\"res://resources/icons/furniture/furniture.tres\",\"QSQX\",\"B7NW\",\"B7NW\"\n641,\"Learning to Kill\",0,,\"res://resources/icons/furniture/furniture.tres\",\"NR3D\",\"RO6W\",\"RO6W\"\n642,\"Learn\",0,,\"res://resources/icons/furniture/furniture.tres\",\"GWKA\",\"XMBE\",\"XMBE\"\n643,\"Infuse with Regeneration\",0,,\"res://resources/icons/furniture/furniture.tres\",\"RMWB\",\"FJ3W\",\"FJ3W\"\n644,\"Mining\",0,,\"res://resources/icons/furniture/furniture.tres\",\"HQQN\",\"XN03\",\"XN03\"\n645,\"Power Supply\",0,,\"res://resources/icons/furniture/furniture.tres\",\"DM3H\",\"FHAH\",\"FHAH\"\n646,\"Attack!\",0,,\"res://resources/icons/furniture/furniture.tres\",\"F4HC\",\"YNFE\",\"YNFE\"\n647,\"Follow Up\",0,,\"res://resources/icons/furniture/furniture.tres\",\"Y3MV\",\"ISHA\",\"ISHA\"\n648,\"Mana Zap\",0,,\"res://resources/icons/furniture/furniture.tres\",\"NRZP\",\"CV25\",\"CV25\"\n649,\"Drunk!\",0,,\"res://resources/icons/furniture/furniture.tres\",\"RY5X\",\"XKJF\",\"XKJF\"\n650,\"Drain Physical Energy\",0,,\"res://resources/icons/furniture/furniture.tres\",\"RKJ3\",\"Q00F\",\"Q00F\"\n651,\"Wheel of Fortune\",0,,\"res://resources/icons/furniture/furniture.tres\",\"F5WV\",\"PZVB\",\"PZVB\"\n652,\"Silver Threads\",0,,\"res://resources/icons/furniture/furniture.tres\",\"KA52\",\"C6GC\",\"C6GC\"\n653,\"Soul Power\",0,,\"res://resources/icons/furniture/furniture.tres\",\"MWRN\",\"I5OO\",\"I5OO\"\n654,\"Hangover\",0,,\"res://resources/icons/furniture/furniture.tres\",\"P4IZ\",\"VYTZ\",\"VYTZ\"\n655,\"Ascension\",0,,\"res://resources/icons/furniture/furniture.tres\",\"NKSY\",\"D25N\",\"D25N\"\n656,\"Speed Award\",0,,\"res://resources/icons/furniture/furniture.tres\",\"U4N1\",\"T6QX\",\"T6QX\"\n657,\"Deep Shadows\",0,,\"res://resources/icons/furniture/furniture.tres\",\"SA2G\",\"X91N\",\"X91N\"\n658,\"Essence Attack\",0,,\"res://resources/icons/furniture/furniture.tres\",\"ODRA\",\"L16K\",\"L16K\"\n659,\"Bones of Essence\",0,,\"res://resources/icons/furniture/furniture.tres\",\"H05A\",\"QXPS\",\"QXPS\"\n660,\"Piercing Magic\",0,,\"res://resources/icons/furniture/furniture.tres\",\"O6YD\",\"CJ46\",\"CJ46\"\n661,\"Frog Piper\",0,,\"res://resources/icons/furniture/furniture.tres\",\"DZHA\",\"TM4A\",\"TM4A\"\n662,\"Cast a Spell\",0,,\"res://resources/icons/furniture/furniture.tres\",\"P55N\",\"AB66\",\"AB66\"\n663,\"Even More Magical Weapon\",0,,\"res://resources/icons/furniture/furniture.tres\",\"ILRF\",\"KZGH\",\"KZGH\"\n664,\"Optimist Hunting Season\",0,,\"res://resources/icons/furniture/furniture.tres\",\"HR8C\",\"KA7K\",\"KA7K\"\n665,\"Anti-Immunity Missile\",0,,\"res://resources/icons/furniture/furniture.tres\",\"UWJ6\",\"PZ2H\",\"PZ2H\"\n666,\"Fragmentation Round\",0,,\"res://resources/icons/furniture/furniture.tres\",\"JAWX\",\"ETHO\",\"ETHO\"\n667,\"Entangling Roots\",0,,\"res://resources/icons/furniture/furniture.tres\",\"ZEIC\",\"JOWZ\",\"JOWZ\"\n668,\"Ethereal Knowledge\",0,,\"res://resources/icons/furniture/furniture.tres\",\"JI7L\",\"OQFX\",\"OQFX\"\n669,\"Ethereal Knowledge\",0,,\"res://resources/icons/furniture/furniture.tres\",\"JEV7\",\"XY86\",\"XY86\"\n670,\"Breath of Decay\",0,,\"res://resources/icons/furniture/furniture.tres\",\"XN62\",\"KHIT\",\"KHIT\"\n671,\"Breath of Fire\",0,,\"res://resources/icons/furniture/furniture.tres\",\"CPO7\",\"NZER\",\"NZER\"\n672,\"Overcharge Shot\",0,,\"res://resources/icons/furniture/furniture.tres\",\"YU23\",\"Z149\",\"Z149\"\n673,\"Magical Greed\",0,,\"res://resources/icons/furniture/furniture.tres\",\"M60I\",\"KU6N\",\"KU6N\"\n674,\"Share Knowledge\",0,,\"res://resources/icons/furniture/furniture.tres\",\"DB7W\",\"RUN2\",\"RUN2\"\n675,\"Blasting Attack\",0,,\"res://resources/icons/furniture/furniture.tres\",\"DX3B\",\"IVQN\",\"IVQN\"\n676,\"Nermind's Eye\",0,,\"res://resources/icons/furniture/furniture.tres\",\"BD9E\",\"BUX7\",\"BUX7\"\n677,\"True Sight\",0,,\"res://resources/icons/furniture/furniture.tres\",\"MXM6\",\"MOJ4\",\"MOJ4\"\n678,\"High Knowledge\",0,,\"res://resources/icons/furniture/furniture.tres\",\"M066\",\"NRIR\",\"NRIR\"\n679,\"Unstable Current\",0,,\"res://resources/icons/furniture/furniture.tres\",\"E4XQ\",\"INQ9\",\"INQ9\"\n680,\"Sacred Wisdom\",0,,\"res://resources/icons/furniture/furniture.tres\",\"XKWF\",\"A0C9\",\"A0C9\"\n681,\"Exchange\",0,,\"res://resources/icons/furniture/furniture.tres\",\"PCHO\",\"AI22\",\"AI22\"\n682,\"Duplication\",0,,\"res://resources/icons/furniture/furniture.tres\",\"T4P7\",\"HUR0\",\"HUR0\"\n683,\"Rampage\",0,,\"res://resources/icons/furniture/furniture.tres\",\"REGR\",\"I6YQ\",\"I6YQ\"\n684,\"Big Badaboom\",0,,\"res://resources/icons/furniture/furniture.tres\",\"VFWN\",\"PRQW\",\"PRQW\"\n685,\"Old Hunter\",0,,\"res://resources/icons/furniture/furniture.tres\",\"WR61\",\"PKZ5\",\"PKZ5\"\n686,\"The Customer Is Boss\",0,,\"res://resources/icons/furniture/furniture.tres\",\"O2I9\",\"M5HG\",\"M5HG\"\n687,\"Circle of Power\",0,,\"res://resources/icons/furniture/furniture.tres\",\"V23I\",\"YEZ8\",\"YEZ8\"\n688,\"Haunted!\",0,,\"res://resources/icons/furniture/furniture.tres\",\"FGP9\",\"IPAI\",\"IPAI\"\n689,\"Transform\",0,,\"res://resources/icons/furniture/furniture.tres\",\"V6YR\",\"GPFB\",\"GPFB\"\n690,\"Golden Hit\",0,,\"res://resources/icons/furniture/furniture.tres\",\"NNHG\",\"LBD6\",\"LBD6\"\n691,\"Critical Accumulation\",0,,\"res://resources/icons/furniture/furniture.tres\",\"T0XV\",\"C5DU\",\"C5DU\"\n692,\"Script Reading\",0,,\"res://resources/icons/furniture/furniture.tres\",\"L99K\",\"JS5I\",\"JS5I\"\n693,\"Soul Power\",0,,\"res://resources/icons/furniture/furniture.tres\",\"J2O0\",\"IB9A\",\"IB9A\"\n694,\"Ensign's Touch\",0,,\"res://resources/icons/furniture/furniture.tres\",\"NFBN\",\"DCO4\",\"DCO4\"\n695,\"Imitation\",0,,\"res://resources/icons/furniture/furniture.tres\",\"HZPB\",\"MLI6\",\"MLI6\"\n696,\"Restriction\",0,,\"res://resources/icons/furniture/furniture.tres\",\"QE58\",\"EDZ6\",\"EDZ6\"\n697,\"Ball Lightning\",0,,\"res://resources/icons/furniture/furniture.tres\",\"IVD6\",\"EC8M\",\"EC8M\"\n698,\"Shrapnel Munition\",0,,\"res://resources/icons/furniture/furniture.tres\",\"XUS7\",\"D0O4\",\"D0O4\"\n699,\"Vampiric Absorption\",0,,\"res://resources/icons/furniture/furniture.tres\",\"AA9P\",\"W9MT\",\"W9MT\"\n700,\"Heavy Weapon\",0,,\"res://resources/icons/furniture/furniture.tres\",\"ZOFE\",\"NAA7\",\"NAA7\"\n701,\"Tricky Weapon\",0,,\"res://resources/icons/furniture/furniture.tres\",\"LCB8\",\"HAC9\",\"HAC9\"\n702,\"Elune's Grace\",0,,\"res://resources/icons/furniture/furniture.tres\",\"N0S4\",\"M3XQ\",\"M3XQ\"\n703,\"Stunning Souls\",0,,\"res://resources/icons/furniture/furniture.tres\",\"QQAH\",\"LB9J\",\"LB9J\"\n704,\"Stun\",0,,\"res://resources/icons/furniture/furniture.tres\",\"AN22\",\"VKLH\",\"VKLH\"\n705,\"Magic Powers\",0,,\"res://resources/icons/furniture/furniture.tres\",\"L9QZ\",\"BGV7\",\"BGV7\"\n706,\"Curse of the Grave\",0,,\"res://resources/icons/furniture/furniture.tres\",\"A2Y4\",\"MW4Y\",\"MW4Y\"\n707,\"Improve Item\",0,,\"res://resources/icons/furniture/furniture.tres\",\"HB8L\",\"HAKL\",\"HAKL\"\n708,\"Phase Powers\",0,,\"res://resources/icons/furniture/furniture.tres\",\"KBNU\",\"SSNE\",\"SSNE\"\n709,\"Conduct Magic\",0,,\"res://resources/icons/furniture/furniture.tres\",\"Y3Q9\",\"OT4I\",\"OT4I\"\n710,\"Miss\",0,,\"res://resources/icons/furniture/furniture.tres\",\"OL01\",\"SKYL\",\"SKYL\"\n711,\"Reward the Faithful\",0,,\"res://resources/icons/furniture/furniture.tres\",\"SY4C\",\"BNF9\",\"BNF9\"\n712,\"Luck!\",0,,\"res://resources/icons/furniture/furniture.tres\",\"DUJG\",\"QEJQ\",\"QEJQ\"\n713,\"Launch Glaive\",0,,\"res://resources/icons/furniture/furniture.tres\",\"GTSM\",\"GTQ3\",\"GTQ3\"\n714,\"Seeker Oil ability\",0,,\"res://resources/icons/furniture/furniture.tres\",,\"RF64\",\"RF64\"\n715,\"Seeker Oil ability\",0,,\"res://resources/icons/furniture/furniture.tres\",,\"O2GJ\",\"O2GJ\"\n716,\"Oil of Lore ability\",0,,\"res://resources/icons/furniture/furniture.tres\",,\"UWF2\",\"UWF2\"\n717,\"Oil of Lore ability\",0,,\"res://resources/icons/furniture/furniture.tres\",,\"LB0T\",\"LB0T\"\n718,\"Goldrush\",\"0\",,\"res://resources/icons/gems/gem_01.tres\",\"TWNJ\",\"RX2E\",\"W8J2\"\n719,\"Excavation\",\"0\",,\"res://resources/icons/misc/gold_cart.tres\",\"O2A4\",\"TBE0\",\"SJL2\"\n720,\"Goldrush\",\"0\",,\"res://resources/icons/gems/gem_01.tres\",\"P2CU\",\"ABX4\",\"ZGN5\"\n721,\"Excavation\",\"0\",,\"res://resources/icons/misc/gold_cart.tres\",\"A90B\",\"B3DJ\",\"LNCM\"\n"
  },
  {
    "path": "data/ability_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/aura_properties.csv",
    "content": "\"id\",\"name_english\",\"aura_bt\",\"target_self\",\"range\",\"target_type\",\"is_hidden\",\"level\",\"level_add\",\"icon\",\"name\",\"description_short\",\"description_long\"\n\"1\",\"Mana Distortion Field\",\"aura_bt\",\"FALSE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/magic/magic_stone.tres\",\"K9TP\",\"0LFP\",\"YZ81\"\n\"2\",\"Mana Distortion Field\",\"aura_bt\",\"FALSE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/magic/magic_stone.tres\",\"N86L\",\"9E3F\",\"DP6R\"\n\"3\",\"Mana Distortion Field\",\"aura_bt\",\"FALSE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/magic/magic_stone.tres\",\"NSZN\",\"F6IF\",\"N9UB\"\n\"4\",\"Mana Distortion Field\",\"aura_bt\",\"FALSE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/magic/magic_stone.tres\",\"20NS\",\"C1EG\",\"C5UC\"\n\"5\",\"Time Twist\",\"aura_bt\",\"TRUE\",\"240\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/mechanical/mech_badge.tres\",\"5M1O\",\"O5DE\",\"78LG\"\n\"6\",\"Timesurge\",\"aura_bt\",\"FALSE\",\"600\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/mechanical/lamp.tres\",\"JC4W\",\"S4Y6\",\"WXAD\"\n\"7\",\"Cloud of Absorption\",\"aura_bt\",\"FALSE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/trinkets/trinket_01.tres\",\"LCH0\",\"TAUE\",\"86D4\"\n\"8\",\"Presence of the Rift\",\"aura_bt\",\"FALSE\",\"750\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/clubs/club_glowing.tres\",\"KZV2\",\"XXW6\",\"H9CL\"\n\"9\",\"Earthquake Aura\",\"aura_bt\",\"TRUE\",\"150\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/fire_battery.tres\",\"KQY8\",\"Y3WQ\",\"DZXI\"\n\"10\",\"Sunshine\",\"aura_bt\",\"FALSE\",\"800\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/staves/wand_glowing.tres\",\"5RBM\",\"OCBP\",\"7QOA\"\n\"11\",\"Sunshine\",\"aura_bt\",\"FALSE\",\"1100\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/staves/wand_glowing.tres\",\"F291\",\"THQI\",\"3WQE\"\n\"12\",\"Aura of Light\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/gloves/heal.tres\",\"OIFB\",\"VDE8\",\"5AZT\"\n\"13\",\"Aura of Light\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/gloves/heal.tres\",\"ACHN\",\"T3M6\",\"DNAL\"\n\"14\",\"Aura of Light\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/gloves/heal.tres\",\"WPO1\",\"MG4B\",\"7QA2\"\n\"15\",\"Flowing Frost\",\"aura_bt\",\"TRUE\",\"500\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/ice_battery.tres\",\"I1AQ\",\"XDQA\",\"IQSG\"\n\"16\",\"Global Silence\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/tiny_storm_lantern.tres\",\"J4QD\",\"QLDS\",\"7WY3\"\n\"17\",\"Calming Noises\",\"aura_bt\",\"TRUE\",\"250\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/dioramas/church.tres\",\"U5XF\",\"O4JT\",\"4WK3\"\n\"18\",\"Spell Absorb\",\"spell_gathering_bt\",\"TRUE\",\"650\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/magic_battery.tres\",\"OZ6M\",\"DWIJ\",\"JZR1\"\n\"19\",\"Spell Absorb\",\"spell_gathering_bt\",\"TRUE\",\"650\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/magic_battery.tres\",\"YP52\",\"D192\",\"31LI\"\n\"20\",\"Gust\",\"aura_bt\",\"TRUE\",\"800\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/ice_battery.tres\",\"CGJW\",\"4XNA\",\"5ERW\"\n\"21\",\"Slow Decay\",\"aura_bt\",\"FALSE\",\"750\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/faces/green_demon.tres\",\"TIHP\",\"01X3\",\"F32S\"\n\"22\",\"Xeno Vulnerability Research\",\"aura_bt\",\"TRUE\",\"280\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/orb_green.tres\",\"K9FB\",\"1WQ8\",\"CHPP\"\n\"23\",\"Static Field\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/dioramas/book_display.tres\",\"WUG3\",\"J30B\",\"FSMB\"\n\"24\",\"Beast Dung\",\"aura_bt\",\"TRUE\",\"400\",\"TOWERS\",\"FALSE\",\"100\",\"2\",\"res://resources/icons/trinkets/trinket_03.tres\",\"LZ0Y\",\"AKXG\",\"6CQA\"\n\"25\",\"Melt\",\"melt_bt\",\"FALSE\",\"900\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"PVOW\",\"YCGE\",\"IPU2\"\n\"26\",\"Melt\",\"melt_bt\",\"FALSE\",\"900\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"TFSQ\",\"X08C\",\"LOA4\"\n\"27\",\"Glimmer of Hope\",\"glimmer_bt\",\"TRUE\",\"500\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/holy/orb.tres\",\"99HB\",\"HGUN\",\"V371\"\n\"28\",\"Thermal Boost\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"5KEA\",\"30AO\",\"BP9W\"\n\"29\",\"Thermal Boost\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_variations/mossy_acid_sprayer_red.tres\",\"J6V3\",\"5S2V\",\"9N6O\"\n\"30\",\"Tranquility\",\"tranquility_bt\",\"TRUE\",\"450\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/misc/flag_03.tres\",\"WT0I\",\"RRK5\",\"QLEP\"\n\"31\",\"Poisonous Skin\",\"poison_skin_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"WDZX\",\"4OVF\",\"TBO8\"\n\"32\",\"Poisonous Skin\",\"poison_skin_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"NSQT\",\"1JNB\",\"O2L6\"\n\"33\",\"Poisonous Skin\",\"poison_skin_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"PAVZ\",\"CQDA\",\"WCVR\"\n\"34\",\"Poisonous Skin\",\"poison_skin_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"8WET\",\"AZ8A\",\"93L0\"\n\"35\",\"Poisonous Skin\",\"poison_skin_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"2GTP\",\"QRKX\",\"OMT0\"\n\"36\",\"We Will Not Fall!\",\"wewillnotfall_bt\",\"FALSE\",\"400\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/animals/rooster_warrior.tres\",\"RBBQ\",\"DYZS\",\"U6K6\"\n\"37\",\"Dark Shroud\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/shadow.tres\",\"3QF9\",\"XEAF\",\"LN6N\"\n\"38\",\"Arcane Aura\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/astral_rift.tres\",\"95AX\",\"QM3H\",\"HHKL\"\n\"39\",\"Lightning Charge\",\"aura_bt\",\"TRUE\",\"250\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"DBMK\",\"UFV4\",\"CU0Z\"\n\"40\",\"Lightning Charge\",\"aura_bt\",\"TRUE\",\"250\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"2GYN\",\"GXG9\",\"AO2Q\"\n\"41\",\"Demonic Edict\",\"aura_bt\",\"TRUE\",\"400\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/misc/flag_02.tres\",\"J9YJ\",\"QDMK\",\"8G2T\"\n\"42\",\"Moonlight\",\"aura_bt\",\"FALSE\",\"800\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/moon.tres\",\"EK3E\",\"F2R9\",\"YZ85\"\n\"43\",\"Moonlight\",\"aura_bt\",\"FALSE\",\"1100\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/moon.tres\",\"XDM0\",\"Z9ET\",\"PPXC\"\n\"44\",\"Strong Wind\",\"strong_wind_bt\",\"FALSE\",\"900\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"BTA9\",\"PYH3\",\"5L06\"\n\"45\",\"Distortion Flux Collector hidden aura\",\"aura_bt\",\"FALSE\",\"2150\",\"CREEPS\",\"TRUE\",\"0\",\"1\",\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"D686\",\"XWQR\",\"2HFU\"\n\"46\",\"Flesh of Ymir\",\"aura_bt\",\"TRUE\",\"0\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/scrolls/scroll_01.tres\",\"071M\",\"SMH5\",\"LCQ6\"\n\"47\",\"Strike the Unprepared\",\"aura_bt\",\"TRUE\",\"175\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/daggers/dagger_07.tres\",\"W4AO\",\"WJSW\",\"FE4G\"\n\"48\",\"Steam Power\",\"steam_bt\",\"FALSE\",\"450\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/cloudy_temple_of_absorption.tres\",\"WP8V\",\"BIL9\",\"8P7U\"\n\"49\",\"Bloody Experience\",\"aura_bt\",\"TRUE\",\"250\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/gems/gem_07.tres\",\"PBAM\",\"3RV7\",\"0XQ6\"\n\"50\",\"Bloody Experience\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/gems/gem_07.tres\",\"JPUO\",\"KWVQ\",\"S7ZK\"\n\"51\",\"Bloody Experience\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/gems/gem_07.tres\",\"FODC\",\"0WWS\",\"2PB9\"\n\"52\",\"Conduit\",\"aura_bt\",\"FALSE\",\"350\",\"TOWERS,ELEMENT_STORM,RARITY_COMMON,RARITY_UNCOMMON\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/trinkets/trinket_06.tres\",\"6V9A\",\"8Y1Y\",\"EODW\"\n\"53\",\"Realm of Thunder\",\"aura_bt\",\"TRUE\",\"1300\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/lightning_generator.tres\",\"602N\",\"83SY\",\"0Q94\"\n\"54\",\"Realm of Thunder\",\"aura_bt\",\"TRUE\",\"1300\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/lightning_generator.tres\",\"VEI8\",\"C3D3\",\"UDGA\"\n\"55\",\"Evil Device\",\"evil_device_bt\",\"FALSE\",\"350\",\"TOWERS,ELEMENT_DARKNESS,RARITY_COMMON,RARITY_UNCOMMON\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/mechanical/battery.tres\",\"QN19\",\"P6G9\",\"208Y\"\n\"56\",\"Flames of the Forge\",\"aura_bt\",\"TRUE\",\"350\",\"PLAYER_TOWERS,ELEMENT_FIRE,RARITY_COMMON,RARITY_UNCOMMON\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/cruel_fire.tres\",\"QMYX\",\"BOU8\",\"MZ38\"\n\"57\",\"Vault's Presence\",\"aura_bt\",\"FALSE\",\"775\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/small_frost_fire.tres\",\"9PRA\",\"AFFR\",\"PV37\"\n\"58\",\"Fire of Fury\",\"fire_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"NYB7\",\"Y53J\",\"3CHA\"\n\"59\",\"Fire of Fury\",\"fire_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"DBQN\",\"1NML\",\"H5RD\"\n\"60\",\"Fire of Fury\",\"fire_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"9Y9Y\",\"893I\",\"M5PV\"\n\"61\",\"Heat Aura\",\"aura_bt\",\"FALSE\",\"700\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/fire_battery.tres\",\"E2OE\",\"LOLZ\",\"6P2U\"\n\"62\",\"Dwarven Polish\",\"aura_bt\",\"TRUE\",\"550\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/swords/greatsword_04.tres\",\"C9ZX\",\"FFNI\",\"2ISW\"\n\"63\",\"Wolven Tenacity\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/faces/orc_01.tres\",\"TTGQ\",\"937D\",\"XVD4\"\n\"64\",\"Wolven Tenacity\",\"aura_bt\",\"TRUE\",\"250\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/faces/orc_01.tres\",\"MO0U\",\"ECDR\",\"W354\"\n\"65\",\"Wolven Tenacity\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/faces/orc_01.tres\",\"INKL\",\"L56S\",\"3PTE\"\n\"66\",\"Divine Research\",\"aura_bt\",\"FALSE\",\"900\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/books/book_08.tres\",\"1ERW\",\"S1WL\",\"0G33\"\n\"67\",\"Green Dragon Force\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/animals/dragon_02.tres\",\"XNJE\",\"D54P\",\"MBIJ\"\n\"68\",\"Frost\",\"aura_bt\",\"FALSE\",\"800\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/orb_ice.tres\",\"DARE\",\"GAPT\",\"IVH8\"\n\"69\",\"Frost\",\"aura_bt\",\"FALSE\",\"1100\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/orb_ice.tres\",\"HRC3\",\"JLEI\",\"L0QV\"\n\"70\",\"Mortal Coil\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/undead/demon_emblem.tres\",\"C5R3\",\"MYDP\",\"RBA9\"\n\"71\",\"Mortal Coil\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/undead/demon_emblem.tres\",\"A948\",\"BUSR\",\"L699\"\n\"72\",\"Mortal Coil\",\"aura_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/undead/demon_emblem.tres\",\"VVDP\",\"W3Y6\",\"09MR\"\n\"73\",\"Energetic Field\",\"aura_bt\",\"TRUE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/magic_battery.tres\",\"71HT\",\"PAER\",\"A7D0\"\n\"74\",\"Cleansing Water\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/orb_ice.tres\",\"ELIN\",\"W4YV\",\"1KEO\"\n\"75\",\"Cleansing Water\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/orb_ice.tres\",\"949H\",\"NCWT\",\"1IFV\"\n\"76\",\"Cleansing Water\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/orbs/orb_ice.tres\",\"MKE0\",\"J9WH\",\"5AWM\"\n\"77\",\"Ancient Magic\",\"aura_bt\",\"FALSE\",\"500\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/lightning_eye.tres\",\"Q1E2\",\"CQAT\",\"2B3N\"\n\"78\",\"Ancient Magic\",\"aura_bt\",\"FALSE\",\"500\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/lightning_eye.tres\",\"21OO\",\"ZR3G\",\"7Z8Q\"\n\"79\",\"Ancient Magic\",\"aura_bt\",\"FALSE\",\"500\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/tower_icons/lightning_eye.tres\",\"X8V3\",\"J8OM\",\"XRDP\"\n\"80\",\"Gift of Nature\",\"aura_bt\",\"TRUE\",\"175\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"V0WN\",\"AVBJ\",\"50GF\"\n\"81\",\"Treasure Seeker\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/trinkets/trinket_05.tres\",\"1D1I\",\"4AMW\",\"QGZO\"\n\"82\",\"Treasure Seeker\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/trinkets/trinket_05.tres\",\"MHME\",\"H6O6\",\"RUWO\"\n\"83\",\"Treasure Seeker\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/trinkets/trinket_05.tres\",\"CAYC\",\"T06T\",\"XFB2\"\n\"84\",\"Treasure Seeker\",\"aura_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/trinkets/trinket_05.tres\",\"CGJ7\",\"GOQV\",\"UBIM\"\n\"85\",\"Revenge of Souls\",\"aura_bt\",\"FALSE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/masks/mask_06.tres\",\"Z67U\",\"BBI2\",\"B641\"\n\"86\",\"Revenge of Souls\",\"aura_bt\",\"FALSE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/masks/mask_06.tres\",\"EI1W\",\"FDKL\",\"7RRU\"\n\"87\",\"Revenge of Souls\",\"aura_bt\",\"FALSE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/masks/mask_06.tres\",\"3YOW\",\"M6LV\",\"2SI7\"\n\"88\",\"King's Authority\",\"aura_bt\",\"FALSE\",\"900\",\"CREEPS\",\"FALSE\",\"500\",\"20\",\"res://resources/icons/helmets/helmet_07.tres\",\"0OQ9\",\"FT9L\",\"F7IL\"\n\"89\",\"Skadi's Influence\",\"slow_bt\",\"FALSE\",\"800\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"GJS8\",\"XFL1\",\"XFL1\"\n\"90\",\"Flames of Fury\",\"flames_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"5CL6\",\"38K8\",\"38K8\"\n\"91\",\"Fright\",\"fright_bt\",\"FALSE\",\"650\",\"CREEPS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"XO8P\",\"9VFO\",\"9VFO\"\n\"92\",\"War Drum\",\"drum_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"HA2N\",\"7WP1\",\"7WP1\"\n\"93\",\"Motivation\",\"motivation_bt\",\"TRUE\",\"1000\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"F8XI\",\"RBXQ\",\"RBXQ\"\n\"94\",\"Forcefield\",\"forcefield_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"MKD7\",\"B7FU\",\"B7FU\"\n\"95\",\"Mana Aura\",\"aura_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"38KA\",\"KBNV\",\"KBNV\"\n\"96\",\"Putrescent Presence\",\"presence_tower_bt\",\"TRUE\",\"350\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"GI59\",\"YNTU\",\"YNTU\"\n\"97\",\"Putrescent Presence second hidden\",\"presence_creep_bt\",\"TRUE\",\"800\",\"CREEPS\",\"TRUE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"none\",\"none\",\"none\"\n\"98\",\"Grace\",\"grace_bt\",\"TRUE\",\"150\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"NEV7\",\"DF6I\",\"DF6I\"\n\"99\",\"Charity\",\"charitable_bt\",\"TRUE\",\"300\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"EB91\",\"9NSY\",\"9NSY\"\n\"100\",\"Magnetic Field\",\"magnetic_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"B1W8\",\"F8UA\",\"F8UA\"\n\"101\",\"Holy Wrath\",\"holy_wrath_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"Y6NX\",\"RGG6\",\"RGG6\"\n\"102\",\"Rot\",\"rot_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"U3T2\",\"B8I2\",\"B8I2\"\n\"103\",\"Bestial Rage\",\"bestial_bt\",\"TRUE\",\"200\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"H2AH\",\"RORC\",\"RORC\"\n\"104\",\"The Divine Wings of Tragedy\",\"divine_wings_bt\",\"TRUE\",\"250\",\"TOWERS\",\"FALSE\",\"0\",\"1\",\"res://resources/icons/plants/leaf_03.tres\",\"GOQX\",\"BO2P\",\"BO2P\"\n\"105\",\"Creep Mana Drain\",\"slow_aura_effect\",\"FALSE\",\"1200\",\"TOWERS\",\"FALSE\",\"0\",\"0\",\"res://resources/icons/plants/leaf_03.tres\",,,\n\"106\",\"Creep Necromancer\",\"necromancer_aura_bt\",\"FALSE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"0\",\"res://resources/icons/plants/leaf_03.tres\",,,\n\"107\",\"Creep Protector\",\"aura_bt\",\"FALSE\",\"1000\",\"CREEPS\",\"FALSE\",\"0\",\"0\",\"res://resources/icons/plants/leaf_03.tres\",,,\n\"108\",\"Creep Slowing\",\"slow_aura_effect\",\"FALSE\",\"800\",\"TOWERS\",\"FALSE\",\"0\",\"0\",\"res://resources/icons/plants/leaf_03.tres\",,,\n"
  },
  {
    "path": "data/aura_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/autocast_properties.csv",
    "content": "\"id\",\"name_english\",\"handler_function\",\"autocast_type\",\"cooldown\",\"mana_cost\",\"cast_range\",\"auto_range\",\"target_self\",\"is_extended\",\"buff_type\",\"buff_target_type\",\"num_buffs_before_idle\",\"caster_art\",\"target_art\",\"icon\",\"name\",\"description_short\",\"description_long\"\n\"1\",\"Soul Revenge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"1\",\"20\",\"875\",\"875\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/orbs/orb_shadow.tres\",\"M4RZ\",\"PCII\",\"4FJR\"\n\"2\",\"Soul Revenge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"1\",\"20\",\"875\",\"875\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/orbs/orb_shadow.tres\",\"RRXJ\",\"DS5S\",\"A7HN\"\n\"3\",\"Soul Revenge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"1\",\"20\",\"875\",\"875\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/orbs/orb_shadow.tres\",\"A45X\",\"6SE7\",\"TT38\"\n\"4\",\"Soul Revenge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"1\",\"20\",\"875\",\"875\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/orbs/orb_shadow.tres\",\"CQL8\",\"Z63O\",\"URY5\"\n\"5\",\"Lunar Grace\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"0\",\"1200\",\"1200\",\"FALSE\",\"TRUE\",,,\"0\",,\"res://src/effects/spell_aiil.tscn\",\"res://resources/icons/orbs/moon.tres\",\"8UQG\",\"VZD3\",\"4YNF\"\n\"6\",\"Lunar Grace\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"0\",\"1200\",\"1200\",\"FALSE\",\"TRUE\",,,\"0\",,\"res://src/effects/spell_aiil.tscn\",\"res://resources/icons/orbs/moon.tres\",\"01D5\",\"3CHL\",\"6MKT\"\n\"7\",\"Lunar Grace\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"0\",\"1200\",\"1200\",\"FALSE\",\"TRUE\",,,\"0\",,\"res://src/effects/spell_aiil.tscn\",\"res://resources/icons/orbs/moon.tres\",\"QSLX\",\"0ROM\",\"8TSF\"\n\"8\",\"Lunar Grace\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"0\",\"1200\",\"1200\",\"FALSE\",\"TRUE\",,,\"0\",,\"res://src/effects/spell_aiil.tscn\",\"res://resources/icons/orbs/moon.tres\",\"E5KT\",\"A3Q9\",\"O7BZ\"\n\"9\",\"Time Field\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"30\",\"500\",\"950\",\"925\",\"TRUE\",\"FALSE\",\"time_field_bt\",,\"1\",\"res://src/effects/spell_ailb.tscn\",,\"res://resources/icons/mechanical/compass.tres\",\"ALHQ\",\"Q902\",\"FK6F\"\n\"10\",\"Shock\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"15\",\"50\",\"900\",\"900\",\"TRUE\",\"FALSE\",,,\"1\",,,\"res://resources/icons/electricity/electricity_blue.tres\",\"D1VZ\",\"5UB1\",\"FANY\"\n\"11\",\"Cloudy Thunderstorm\",\"on_autocast_cloud_thunderstorm\",\"AC_TYPE_NOAC_IMMEDIATE\",\"0.01\",\"1000\",\"1000\",\"0\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"7YSS\",\"XAZR\",\"IKAX\"\n\"12\",\"Adjust Thunderstorm Threshold\",\"on_autocast_adjust_threshold\",\"AC_TYPE_NOAC_IMMEDIATE\",\"0.01\",\"0\",\"0\",\"0\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/compass.tres\",\"9Y1U\",\"WAGL\",\"PPYB\"\n\"13\",\"Thornspray\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"0.2\",\"5\",\"800\",\"700\",\"TRUE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/spears/many_spears_01.tres\",\"BAL7\",\"FSFT\",\"9UKD\"\n\"14\",\"Thornspray\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"0.2\",\"5\",\"800\",\"700\",\"TRUE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/spears/many_spears_01.tres\",\"Y18E\",\"INEU\",\"PI5G\"\n\"15\",\"Thornspray\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"0.2\",\"5\",\"800\",\"700\",\"TRUE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/spears/many_spears_01.tres\",\"Z4G3\",\"UMRO\",\"1JIB\"\n\"16\",\"Charge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"20\",\"1200\",\"1200\",\"TRUE\",\"FALSE\",\"charge_bt\",\"TOWERS\",\"3\",,,\"res://resources/icons/electricity/electricity_yellow.tres\",\"UMX9\",\"XD3V\",\"I8LU\"\n\"17\",\"Demonic Fire\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"4\",\"0\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",\"demonic_fire_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/fire_bowl_02.tres\",\"BTVM\",\"2YXA\",\"WRHQ\"\n\"18\",\"Wind Shear\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"3\",\"15\",\"300\",\"300\",\"TRUE\",\"FALSE\",\"wind_shear_bt\",\"TOWERS\",\"0\",,\"res://src/effects/wind_shear.tscn\",\"res://resources/icons/plants/leaf_02.tres\",\"VNJP\",\"J4AK\",\"KJFA\"\n\"19\",\"Wind Shear\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"3\",\"15\",\"300\",\"300\",\"TRUE\",\"FALSE\",\"wind_shear_bt\",\"TOWERS\",\"0\",,\"res://src/effects/wind_shear.tscn\",\"res://resources/icons/plants/leaf_02.tres\",\"SX4X\",\"JPAR\",\"OL6T\"\n\"20\",\"Wind Shear\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"3\",\"15\",\"300\",\"300\",\"TRUE\",\"FALSE\",\"wind_shear_bt\",\"TOWERS\",\"0\",,\"res://src/effects/wind_shear.tscn\",\"res://resources/icons/plants/leaf_02.tres\",\"BFTQ\",\"VVX2\",\"A95P\"\n\"21\",\"Wind Shear\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"3\",\"15\",\"300\",\"300\",\"TRUE\",\"FALSE\",\"wind_shear_bt\",\"TOWERS\",\"0\",,\"res://src/effects/wind_shear.tscn\",\"res://resources/icons/plants/leaf_02.tres\",\"595P\",\"HKYY\",\"COP1\"\n\"22\",\"Wind Shear\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"3\",\"15\",\"300\",\"300\",\"TRUE\",\"FALSE\",\"wind_shear_bt\",\"TOWERS\",\"0\",,\"res://src/effects/wind_shear.tscn\",\"res://resources/icons/plants/leaf_02.tres\",\"XCD4\",\"DOPY\",\"ACC8\"\n\"23\",\"Snake Charm\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"10\",\"200\",\"200\",\"FALSE\",\"FALSE\",\"charm_bt\",\"TOWERS\",\"1\",,,\"res://resources/icons/undead/skull_wand_03.tres\",\"Q588\",\"56GP\",\"80TB\"\n\"24\",\"Snake Charm\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"10\",\"200\",\"200\",\"FALSE\",\"FALSE\",\"charm_bt\",\"TOWERS\",\"1\",,,\"res://resources/icons/undead/skull_wand_03.tres\",\"2JHT\",\"O6BY\",\"UUPR\"\n\"25\",\"Snake Charm\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"10\",\"200\",\"200\",\"FALSE\",\"FALSE\",\"charm_bt\",\"TOWERS\",\"1\",,,\"res://resources/icons/undead/skull_wand_03.tres\",\"JGOE\",\"M34M\",\"YTE8\"\n\"26\",\"Snake Charm\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"10\",\"200\",\"200\",\"FALSE\",\"FALSE\",\"charm_bt\",\"TOWERS\",\"1\",,,\"res://resources/icons/undead/skull_wand_03.tres\",\"F2SK\",\"CWBS\",\"MY87\"\n\"27\",\"Ice Claw\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"10\",\"850\",\"850\",\"FALSE\",\"FALSE\",\"ice_claw_bt\",,\"1\",,,\"res://resources/icons/magic/claw_02.tres\",\"0216\",\"RZF0\",\"5DW3\"\n\"28\",\"Ice Claw\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"10\",\"850\",\"850\",\"FALSE\",\"FALSE\",\"ice_claw_bt\",,\"1\",,,\"res://resources/icons/magic/claw_02.tres\",\"XEM8\",\"RM9G\",\"A0F6\"\n\"29\",\"Ice Claw\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"10\",\"850\",\"850\",\"FALSE\",\"FALSE\",\"ice_claw_bt\",,\"1\",,,\"res://resources/icons/magic/claw_02.tres\",\"WK0B\",\"8XPV\",\"K4V0\"\n\"30\",\"Ice Claw\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"10\",\"850\",\"850\",\"FALSE\",\"FALSE\",\"ice_claw_bt\",,\"1\",,,\"res://resources/icons/magic/claw_02.tres\",\"YX7X\",\"RZKU\",\"H3MU\"\n\"31\",\"Ice Claw\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"2\",\"10\",\"850\",\"850\",\"FALSE\",\"FALSE\",\"ice_claw_bt\",,\"1\",,,\"res://resources/icons/magic/claw_02.tres\",\"0PTV\",\"DUL8\",\"U5GS\"\n\"32\",\"Jolt\",,\"AC_TYPE_ALWAYS_BUFF\",\"8\",\"15\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"jolt_bt\",\"TOWERS\",\"0\",,,\"res://resources/icons/electricity/electricity_yellow.tres\",\"V9DL\",\"EZDZ\",\"6YWK\"\n\"33\",\"Jolt\",,\"AC_TYPE_ALWAYS_BUFF\",\"8\",\"15\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"jolt_bt\",\"TOWERS\",\"0\",,,\"res://resources/icons/electricity/electricity_yellow.tres\",\"KZ25\",\"54EK\",\"KBL9\"\n\"34\",\"Jolt\",,\"AC_TYPE_ALWAYS_BUFF\",\"8\",\"15\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"jolt_bt\",\"TOWERS\",\"0\",,,\"res://resources/icons/electricity/electricity_yellow.tres\",\"D8JX\",\"JDGB\",\"USHL\"\n\"35\",\"Maledict\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"5\",\"30\",\"800\",\"800\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/undead/monster_hand.tres\",\"9M4F\",\"BPVM\",\"3K53\"\n\"36\",\"Energy Absorb\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"40\",\"0\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/rings/ring_06.tres\",\"JIBC\",\"6OWA\",\"T5UM\"\n\"37\",\"Energy Absorb\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"40\",\"0\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/rings/ring_06.tres\",\"Y50I\",\"F8VU\",\"MNGS\"\n\"38\",\"Freezing Gust\",,\"AC_TYPE_ALWAYS_BUFF\",\"0.1\",\"15\",\"800\",\"800\",\"FALSE\",\"TRUE\",\"freezing_bt\",\"TOWERS\",\"0\",\"res://src/effects/ancient_protector_missile.tscn\",,\"res://resources/icons/fire/flame_blue.tres\",\"YZLA\",\"CKYQ\",\"6Y0N\"\n\"39\",\"Siphon Essence\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"2.5\",\"0\",\"400\",\"400\",\"FALSE\",\"TRUE\",\"siphon_bt\",\"TOWERS\",\"1\",,,\"res://resources/icons/fire/flame_purple.tres\",\"T2DL\",\"LV6Y\",\"E77O\"\n\"40\",\"Siphon Essence\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"1.5\",\"0\",\"400\",\"400\",\"FALSE\",\"TRUE\",\"siphon_bt\",\"TOWERS\",\"1\",,,\"res://resources/icons/fire/flame_purple.tres\",\"E4JX\",\"G0VS\",\"GD3S\"\n\"41\",\"Sparks\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"22\",\"500\",\"500\",\"FALSE\",\"FALSE\",\"twister_bt\",\"TOWERS\",\"1\",,\"res://src/effects/monsoon_bolt.tscn\",\"res://resources/icons/electricity/electricity_blue.tres\",\"QOXP\",\"FLCO\",\"WVGP\"\n\"42\",\"Sparks\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"22\",\"500\",\"500\",\"FALSE\",\"FALSE\",\"twister_bt\",\"TOWERS\",\"1\",,\"res://src/effects/monsoon_bolt.tscn\",\"res://resources/icons/electricity/electricity_blue.tres\",\"2PC4\",\"42QP\",\"QWZT\"\n\"43\",\"Eruption\",\"on_autocast\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/fire/fire_bowl_02.tres\",\"3D28\",\"NSUC\",\"FJ2Y\"\n\"44\",\"Eruption\",\"on_autocast\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/fire/fire_bowl_02.tres\",\"86LV\",\"UKQY\",\"048F\"\n\"45\",\"Eruption\",\"on_autocast\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/fire/fire_bowl_02.tres\",\"X6AM\",\"VOAV\",\"D2BZ\"\n\"46\",\"Hammer Fall\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"10\",\"50\",\"900\",\"900\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/blunt_weapons/hammer_02.tres\",\"GQKH\",\"QBXH\",\"SKPE\"\n\"47\",\"Choose Modification\",\"on_autocast_choose\",\"AC_TYPE_NOAC_IMMEDIATE\",\"0.25\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/trinkets/trinket_01.tres\",\"VIM7\",\"FGPJ\",\"K21Y\"\n\"48\",\"Apply Modification\",\"on_autocast_add\",\"AC_TYPE_NOAC_IMMEDIATE\",\"0.25\",\"0\",\"0\",\"0\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/magic/claw_02.tres\",\"VK3M\",\"ZUEN\",\"BGW5\"\n\"49\",\"Remove Modification\",\"on_autocast_remove\",\"AC_TYPE_NOAC_IMMEDIATE\",\"0.25\",\"0\",\"0\",\"0\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/magic/claw_04.tres\",\"3QU6\",\"J473\",\"L5OS\"\n\"50\",\"Love Potion\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"25\",\"1100\",\"1100\",\"FALSE\",\"FALSE\",\"love_bt\",,\"1\",,,\"res://resources/icons/potions/potion_heart_02.tres\",\"JHXO\",\"7UXR\",\"75Y8\"\n\"51\",\"Love Potion\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"25\",\"1100\",\"1100\",\"FALSE\",\"FALSE\",\"love_bt\",,\"1\",,,\"res://resources/icons/potions/potion_heart_02.tres\",\"VAKZ\",\"JP2E\",\"NKKA\"\n\"52\",\"Love Potion\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"25\",\"1100\",\"1100\",\"FALSE\",\"FALSE\",\"love_bt\",,\"1\",,,\"res://resources/icons/potions/potion_heart_02.tres\",\"2RWU\",\"5W0J\",\"LPMH\"\n\"53\",\"Love Potion\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"25\",\"1100\",\"1100\",\"FALSE\",\"FALSE\",\"love_bt\",,\"1\",,,\"res://resources/icons/potions/potion_heart_02.tres\",\"PGTK\",\"ZUOL\",\"G4J6\"\n\"54\",\"Release Energy\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"5\",\"15\",\"800\",\"800\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/electricity_yellow.tres\",\"DKNR\",\"JMWD\",\"BITA\"\n\"55\",\"Release Energy\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"5\",\"15\",\"800\",\"800\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/electricity_yellow.tres\",\"X6WE\",\"B19O\",\"T3XS\"\n\"56\",\"Thunderstorm\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"10\",\"90\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"1WTR\",\"T4IJ\",\"9JC8\"\n\"57\",\"Stim\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"1\",\"25\",\"1200\",\"1200\",\"TRUE\",\"FALSE\",,,\"0\",\"res://src/effects/avatar_caster.tscn\",,\"res://resources/icons/rockets/rocket_06.tres\",\"YDBK\",\"6TUS\",\"ZILH\"\n\"58\",\"Stim\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"1\",\"25\",\"1200\",\"1200\",\"TRUE\",\"FALSE\",,,\"0\",\"res://src/effects/avatar_caster.tscn\",,\"res://resources/icons/rockets/rocket_06.tres\",\"Z8MV\",\"9OD5\",\"FNLW\"\n\"59\",\"Energy Conversion\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"12\",\"1200\",\"0\",\"650\",\"FALSE\",\"TRUE\",,,\"0\",\"res://src/effects/mass_teleport_caster.tscn\",,\"res://resources/icons/mechanical/battery.tres\",\"BAMJ\",\"4O1K\",\"THRB\"\n\"60\",\"Lightmare\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"10.5\",\"1000\",\"1500\",\"1500\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"YK63\",\"UDMU\",\"KDRX\"\n\"61\",\"Sunlight Burst\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"90\",\"1000\",\"850\",\"FALSE\",\"FALSE\",,,\"0\",\"res://src/effects/silence_area.tscn\",,\"res://resources/icons/electricity/electricity_yellow.tres\",\"63MN\",\"GHQ4\",\"YHAM\"\n\"62\",\"Recreation Field\",\"on_autocast_recreation\",\"AC_TYPE_NOAC_POINT\",\"5\",\"0\",\"800\",\"0\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/magic/magic_stone.tres\",\"CDGY\",\"ZXU1\",\"FU01\"\n\"63\",\"Corruption Field\",\"on_autocast_corruption\",\"AC_TYPE_NOAC_POINT\",\"5\",\"0\",\"800\",\"0\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/misc/poison_02.tres\",\"X7CK\",\"54N9\",\"3O3Z\"\n\"64\",\"Concussive Bombs\",\"on_autocast_concussive\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"concussive_tower_bt\",,\"1\",,,\"res://resources/icons/orbs/orb_molten_dull.tres\",\"R6E2\",\"ZJ3B\",\"VQ35\"\n\"65\",\"Acid Bombs\",\"on_autocast_acid\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"acid_tower_bt\",,\"1\",,,\"res://resources/icons/fire/fire_bowl_03.tres\",\"1PM5\",\"G5PR\",\"PFF7\"\n\"66\",\"Smoke Bombs\",\"on_autocast_smoke\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"smoke_tower_bt\",,\"1\",,,\"res://resources/icons/misc/balls_02.tres\",\"KBHW\",\"6AT5\",\"F832\"\n\"67\",\"Concussive Bombs\",\"on_autocast_concussive\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"concussive_tower_bt\",,\"1\",,,\"res://resources/icons/orbs/orb_molten_dull.tres\",\"54RT\",\"ELJ0\",\"XXX2\"\n\"68\",\"Acid Bombs\",\"on_autocast_acid\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"acid_tower_bt\",,\"1\",,,\"res://resources/icons/fire/fire_bowl_03.tres\",\"I7V4\",\"U6IS\",\"C5IH\"\n\"69\",\"Smoke Bombs\",\"on_autocast_smoke\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"smoke_tower_bt\",,\"1\",,,\"res://resources/icons/misc/balls_02.tres\",\"P637\",\"UGG6\",\"6LPB\"\n\"70\",\"Soul Link\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"50\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",\"soul_link_bt\",\"CREEPS\",\"1\",,,\"res://resources/icons/undead/skull_phazing.tres\",\"FELI\",\"GK81\",\"DCG5\"\n\"71\",\"Soul Link\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"50\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",\"soul_link_bt\",\"CREEPS\",\"1\",,,\"res://resources/icons/undead/skull_phazing.tres\",\"1S4D\",\"IA2M\",\"PYIW\"\n\"72\",\"Fire Blast\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/elements/fire.tres\",\"W9AL\",\"549A\",\"XGFT\"\n\"73\",\"Fire Blast\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/elements/fire.tres\",\"Q647\",\"BHHW\",\"VOLB\"\n\"74\",\"Fire Blast\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/elements/fire.tres\",\"8FBN\",\"9Z91\",\"A90C\"\n\"75\",\"Fire Blast\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/elements/fire.tres\",\"YG8E\",\"N4W7\",\"ZM84\"\n\"76\",\"Fire Blast\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/elements/fire.tres\",\"BW35\",\"1YQA\",\"D2GG\"\n\"77\",\"Release Lightning\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_glowing.tres\",\"LDOD\",\"IHRQ\",\"I5MI\"\n\"78\",\"Release Lightning\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_glowing.tres\",\"WNRX\",\"SODG\",\"D7ZB\"\n\"79\",\"Release Lightning\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_glowing.tres\",\"PTJ2\",\"Q311\",\"LQZM\"\n\"80\",\"Release Lightning\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_glowing.tres\",\"3XED\",\"MD8J\",\"LAJC\"\n\"81\",\"Release Lightning\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_glowing.tres\",\"BDQN\",\"4W44\",\"XQX7\"\n\"82\",\"Entangling Roots\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"10\",\"90\",\"950\",\"950\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/plants/branch_01.tres\",\"BH1G\",\"BK5R\",\"9NQD\"\n\"83\",\"Impenetrable Darkness\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"8\",\"90\",\"850\",\"850\",\"FALSE\",\"FALSE\",\"darkness_bt\",\"CREEPS\",\"1\",,\"res://src/effects/frag_boom_spawn.tscn\",\"res://resources/icons/orbs/orb_molten_dull.tres\",\"5OT3\",\"FVOB\",\"4K16\"\n\"84\",\"Dimensional Link\",\"on_autocast\",\"AC_TYPE_NOAC_PLAYER_TOWER\",\"1\",\"0\",\"800\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/circuit_board.tres\",\"959I\",\"CPIK\",\"LMOO\"\n\"85\",\"Will of the Undying\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"10\",\"50\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",\"res://src/effects/howl_caster.tscn\",,\"res://resources/icons/undead/skull_01.tres\",\"I625\",\"MHIF\",\"POAT\"\n\"86\",\"Morph: Might\",\"on_autocast_might\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"might_bt\",,\"1\",,,\"res://resources/icons/trinkets/trinket_07.tres\",\"TA3Y\",\"SL1G\",\"EASO\"\n\"87\",\"Morph: Swiftness\",\"on_autocast_swiftness\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"swiftness_bt\",,\"1\",,,\"res://resources/icons/trinkets/trinket_08.tres\",\"ZIPX\",\"YM0Y\",\"KK19\"\n\"88\",\"Adapt\",\"on_autocast_adapt\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",\"adapt_bt\",,\"0\",,,\"res://resources/icons/trinkets/trinket_01.tres\",\"EFZD\",\"GJQ6\",\"1FDG\"\n\"89\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"R8FP\",\"7SRN\",\"EP0A\"\n\"90\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"D7Q6\",\"Q813\",\"VPMF\"\n\"91\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"N9HX\",\"PZNY\",\"6TGE\"\n\"92\",\"Thunder Shock\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"12\",\"1200\",\"1200\",\"TRUE\",\"FALSE\",,,\"1\",\"res://src/effects/purge_buff_target.tscn\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"4REX\",\"QVKX\",\"B7PW\"\n\"93\",\"Thunder Shock\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"12\",\"1200\",\"1200\",\"TRUE\",\"FALSE\",,,\"1\",\"res://src/effects/purge_buff_target.tscn\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"CN62\",\"IVTB\",\"XV8T\"\n\"94\",\"Thunder Shock\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"3\",\"12\",\"1200\",\"1200\",\"TRUE\",\"FALSE\",,,\"1\",\"res://src/effects/purge_buff_target.tscn\",,\"res://resources/icons/electricity/lightning_glowing.tres\",\"EOAG\",\"C9XW\",\"HRRL\"\n\"95\",\"Lightning Surge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"6\",\"60\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"62OY\",\"6P2M\",\"9XD7\"\n\"96\",\"Lightning Surge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"6\",\"60\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"5SKO\",\"88K2\",\"OPUQ\"\n\"97\",\"Lightning Surge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"6\",\"60\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"Y71A\",\"YLMR\",\"TT4G\"\n\"98\",\"Lightning Surge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"6\",\"60\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/electricity/lightning_circle_white.tres\",\"VO3B\",\"1XTE\",\"GI9Q\"\n\"99\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"MVZH\",\"OBSV\",\"QN3V\"\n\"100\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"CQY1\",\"6M4T\",\"W3GJ\"\n\"101\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"FA2S\",\"YTSS\",\"TX13\"\n\"102\",\"Sacrifice\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"6\",\"90\",\"500\",\"500\",\"FALSE\",\"FALSE\",\"sacrifice_boost_bt\",\"TOWERS\",\"1\",\"res://src/effects/faerie_dragon_missile.tscn\",\"res://src/effects/frost_armor_damage_purple.tscn\",\"res://resources/icons/furniture/artifact_on_pedestal.tres\",\"QIKO\",\"ZHI6\",\"4N39\"\n\"103\",\"Sacrifice\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"6\",\"90\",\"500\",\"500\",\"FALSE\",\"FALSE\",\"sacrifice_boost_bt\",\"TOWERS\",\"1\",\"res://src/effects/faerie_dragon_missile.tscn\",\"res://src/effects/frost_armor_damage_purple.tscn\",\"res://resources/icons/furniture/artifact_on_pedestal.tres\",\"KMCT\",\"CNEJ\",\"BC6G\"\n\"104\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"VLUF\",\"J0SI\",\"QOVB\"\n\"105\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"R1UQ\",\"H9OY\",\"MKXF\"\n\"106\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"Q732\",\"XOBE\",\"KKQ8\"\n\"107\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/poison_battery.tres\",\"S8UR\",\"EA6W\",\"KB8Q\"\n\"108\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/poison_battery.tres\",\"YFVK\",\"ZS7O\",\"RSW1\"\n\"109\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/poison_battery.tres\",\"M4K1\",\"046D\",\"TR4K\"\n\"110\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/fire_battery.tres\",\"YA9V\",\"KDKK\",\"3VWU\"\n\"111\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/fire_battery.tres\",\"AD57\",\"Z60W\",\"KOCY\"\n\"112\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_icons/fire_battery.tres\",\"T2YT\",\"BL34\",\"N39F\"\n\"113\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"2DWD\",\"8Y1F\",\"HHFY\"\n\"114\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"7WAQ\",\"3GYN\",\"BT1Q\"\n\"115\",\"Battery Overload\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"20\",\"100\",\"1200\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/mechanical/battery.tres\",\"ROO8\",\"QJ2A\",\"GZC8\"\n\"116\",\"Soul Chill\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,\"res://src/effects/raise_skeleton.tscn\",\"res://resources/icons/fire/flame_blue_glowing.tres\",\"MF16\",\"83JE\",\"O2M7\"\n\"117\",\"Soul Chill\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,\"res://src/effects/raise_skeleton.tscn\",\"res://resources/icons/fire/flame_blue_glowing.tres\",\"FIR2\",\"O5L9\",\"DXC3\"\n\"118\",\"Soul Chill\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,\"res://src/effects/raise_skeleton.tscn\",\"res://resources/icons/fire/flame_blue_glowing.tres\",\"0CBX\",\"QHC9\",\"GWQ5\"\n\"119\",\"Soul Chill\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,\"res://src/effects/raise_skeleton.tscn\",\"res://resources/icons/fire/flame_blue_glowing.tres\",\"1XVL\",\"SQAN\",\"ET56\"\n\"120\",\"Soul Chill\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"1\",\"20\",\"900\",\"900\",\"FALSE\",\"FALSE\",,,\"0\",,\"res://src/effects/raise_skeleton.tscn\",\"res://resources/icons/fire/flame_blue_glowing.tres\",\"UB4K\",\"F4Y6\",\"R69J\"\n\"121\",\"Mystical Trance\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"50\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"trance_bt\",\"TOWERS\",\"1\",\"res://src/effects/spell_aire.tscn\",,\"res://resources/icons/masks/mask_05.tres\",\"OD1G\",\"1HTO\",\"X4L4\"\n\"122\",\"Speed Up\",\"on_autocast_speed_up\",\"AC_TYPE_NOAC_IMMEDIATE\",\"0.5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/magic/claw_03.tres\",\"KBAV\",\"TWGX\",\"2K7I\"\n\"123\",\"Speed Down\",\"on_autocast_speed_down\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/magic/claw_04.tres\",\"WCWC\",\"K7B0\",\"0LIU\"\n\"124\",\"Bloodlust\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"15\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"bloodlust_bt\",\"TOWERS\",\"1\",,\"res://src/effects/roar.tscn\",\"res://resources/icons/masks/mask_07.tres\",\"DICL\",\"GYWD\",\"E0JA\"\n\"125\",\"Bloodlust\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"15\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"bloodlust_bt\",\"TOWERS\",\"1\",,\"res://src/effects/roar.tscn\",\"res://resources/icons/masks/mask_07.tres\",\"T2WW\",\"5U87\",\"H6Y7\"\n\"126\",\"Bloodlust\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"15\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"bloodlust_bt\",\"TOWERS\",\"1\",,\"res://src/effects/roar.tscn\",\"res://resources/icons/masks/mask_07.tres\",\"SYUI\",\"UYSJ\",\"7JJB\"\n\"127\",\"Nature's Gift\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"45\",\"500\",\"500\",\"FALSE\",\"FALSE\",,\"TOWERS\",\"5\",,,\"res://resources/icons/plants/leaf_03.tres\",\"MT0B\",\"KTAD\",\"9F0V\"\n\"128\",\"Nature's Gift\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"45\",\"500\",\"500\",\"FALSE\",\"FALSE\",,\"TOWERS\",\"5\",,,\"res://resources/icons/plants/leaf_03.tres\",\"IVZY\",\"3CE2\",\"T5X7\"\n\"129\",\"Nature's Gift\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"45\",\"500\",\"500\",\"FALSE\",\"FALSE\",,\"TOWERS\",\"5\",,,\"res://resources/icons/plants/leaf_03.tres\",\"PPWV\",\"IJJK\",\"81IX\"\n\"130\",\"Unleash\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"0.5\",\"400\",\"1200\",\"1200\",\"FALSE\",\"FALSE\",,\"CREEPS\",\"1\",,,\"res://resources/icons/electricity/electricity_blue.tres\",\"XXQW\",\"G669\",\"57BH\"\n\"131\",\"Targeted Run\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"15\",\"0\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/rings/ring_06.tres\",\"2KDA\",\"LDL2\",\"W5XA\"\n\"132\",\"Soul Storm\",\"on_autocast\",\"AC_TYPE_NOAC_IMMEDIATE\",\"5\",\"0\",\"600\",\"600\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/misc/flag_02.tres\",\"PL8E\",\"CRC8\",\"B705\"\n\"133\",\"Awaken\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"4\",\"50\",\"900\",\"900\",\"FALSE\",\"TRUE\",,,\"0\",\"res://src/effects/incinerate.tscn\",,\"res://resources/icons/magic/fire.tres\",\"K8VZ\",\"7OIR\",\"JIA3\"\n\"134\",\"Intense Heat\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"5\",\"100\",\"1000\",\"1000\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/orbs/orb_fire.tres\",\"7IM4\",\"9ISH\",\"D22P\"\n\"135\",\"Glaivesaw\",\"on_autocast\",\"AC_TYPE_NOAC_POINT\",\"1\",\"0\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/clubs/club_02.tres\",\"EFK8\",\"16RM\",\"QAUO\"\n\"136\",\"Shattering Barrage\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"30\",\"300\",\"1000\",\"750\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/tower_variations/meteor_totem_blue.tres\",\"5PSG\",\"VHOI\",\"MI6L\"\n\"137\",\"Blizzard\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"10\",\"95\",\"900\",\"900\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_variations/meteor_totem_blue.tres\",\"0J2A\",\"BF1D\",\"L3HS\"\n\"138\",\"Blizzard\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"10\",\"95\",\"900\",\"900\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_variations/meteor_totem_blue.tres\",\"D3Z0\",\"OQTD\",\"EXEW\"\n\"139\",\"Blizzard\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"10\",\"95\",\"900\",\"900\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_variations/meteor_totem_blue.tres\",\"A6F2\",\"8ORV\",\"K1RK\"\n\"140\",\"Blizzard\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_UNIT\",\"10\",\"95\",\"900\",\"900\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/tower_variations/meteor_totem_blue.tres\",\"EF0D\",\"DJS4\",\"6D16\"\n\"141\",\"Divine Teachings\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"5\",\"30\",\"500\",\"500\",\"FALSE\",\"FALSE\",\"teachings_bt\",\"TOWERS\",\"0\",\"res://src/effects/spell_aire.tscn\",\"res://src/effects/charm_target.tscn\",\"res://resources/icons/books/book_02.tres\",\"KMZP\",\"4O1Q\",\"S1FS\"\n\"142\",\"Burning Mark\",,\"AC_TYPE_OFFENSIVE_BUFF\",\"2\",\"20\",\"500\",\"500\",\"TRUE\",\"FALSE\",\"mark_bt\",\"TOWERS\",\"3\",,\"res://src/effects/doom_death.tscn\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"MO8V\",\"M7FQ\",\"UAJE\"\n\"143\",\"Dark Curse\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"30\",\"900\",\"900\",\"FALSE\",\"FALSE\",\"curse_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/flame_purple.tres\",\"BPZN\",\"F3EW\",\"LG1X\"\n\"144\",\"Dark Curse\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"30\",\"900\",\"900\",\"FALSE\",\"FALSE\",\"curse_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/flame_purple.tres\",\"4RUJ\",\"BUJ8\",\"HGE7\"\n\"145\",\"Dark Curse\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"30\",\"900\",\"900\",\"FALSE\",\"FALSE\",\"curse_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/flame_purple.tres\",\"9A79\",\"4KU7\",\"PVBJ\"\n\"146\",\"Dark Curse\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"30\",\"900\",\"900\",\"FALSE\",\"FALSE\",\"curse_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/flame_purple.tres\",\"JCO0\",\"XDSH\",\"UUPI\"\n\"147\",\"Golden Influence\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"4\",\"20\",\"400\",\"400\",\"TRUE\",\"FALSE\",\"golden_bt\",\"TOWERS\",\"3\",,\"res://src/effects/gold_credit.tscn\",\"res://resources/icons/hud/gold.tres\",\"WK7Z\",\"P7JL\",\"AXPI\"\n\"148\",\"Golden Influence\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"4\",\"20\",\"400\",\"400\",\"TRUE\",\"FALSE\",\"golden_bt\",\"TOWERS\",\"3\",,\"res://src/effects/gold_credit.tscn\",\"res://resources/icons/hud/gold.tres\",\"PVF5\",\"W8BG\",\"LAMD\"\n\"149\",\"Extract Experience\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"20\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",\"extract_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/fire_in_cup.tres\",\"XMNR\",\"X8P6\",\"16VZ\"\n\"150\",\"Extract Experience\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"5\",\"20\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",\"extract_bt\",\"CREEPS\",\"3\",,,\"res://resources/icons/fire/fire_in_cup.tres\",\"83XJ\",\"4FHT\",\"9AD0\"\n\"151\",\"Attraction\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"4\",\"0\",\"500\",\"500\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/fire/fire_bowl_02.tres\",\"OOQO\",\"9OHP\",\"8CQJ\"\n\"152\",\"Magnetic Surge\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"4\",\"40\",\"1000\",\"1000\",\"FALSE\",\"FALSE\",,\"CREEPS\",\"1\",,,\"res://resources/icons/electricity/electricity_blue.tres\",\"E0LQ\",\"K8XG\",\"G0R1\"\n\"153\",\"Replenish\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"5\",\"200\",\"500\",\"500\",\"TRUE\",\"FALSE\",,,\"0\",\"res://src/effects/replenish_mana.tscn\",\"res://src/effects/spell_aima.tscn\",\"res://resources/icons/plants/flower_01.tres\",\"EM6X\",\"GXKI\",\"68XA\"\n\"154\",\"Replenish\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"5\",\"200\",\"500\",\"500\",\"TRUE\",\"FALSE\",,,\"0\",\"res://src/effects/replenish_mana.tscn\",\"res://src/effects/spell_aima.tscn\",\"res://resources/icons/plants/flower_01.tres\",\"HLEV\",\"XJ2R\",\"R9O2\"\n\"155\",\"Replenish\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"5\",\"200\",\"500\",\"500\",\"TRUE\",\"FALSE\",,,\"0\",\"res://src/effects/replenish_mana.tscn\",\"res://src/effects/spell_aima.tscn\",\"res://resources/icons/plants/flower_01.tres\",\"TRB6\",\"LY16\",\"I9AV\"\n\"156\",\"Dreadlord's Awakening\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"80\",\"0\",\"0\",\"900\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/undead/skull_03.tres\",\"3R4Q\",\"OU4J\",\"TH8U\"\n\"157\",\"Astral Eruption\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"35\",\"1000\",\"0\",\"700\",\"TRUE\",\"FALSE\",\"eruption_bt\",,\"0\",,,\"res://resources/icons/magic/magic_stone.tres\",\"TD6U\",\"LHLO\",\"26ML\"\n\"158\",\"Eden's Wrath\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"10\",\"0\",\"800\",\"800\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/trinkets/trinket_03.tres\",\"IRVV\",\"UT0C\",\"D4FX\"\n\"159\",\"For the God\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"4\",\"10\",\"600\",\"600\",\"TRUE\",\"FALSE\",\"crusader_bt\",\"TOWERS\",\"5\",,,\"res://resources/icons/holy/altar.tres\",\"GJY6\",\"IINF\",\"UUT2\"\n\"160\",\"For the God\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_BUFF\",\"4\",\"10\",\"600\",\"600\",\"TRUE\",\"FALSE\",\"crusader_bt\",\"TOWERS\",\"5\",,,\"res://resources/icons/holy/altar.tres\",\"AZVN\",\"24HA\",\"VBMN\"\n\"161\",\"Search For Item\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"150\",\"0\",\"300\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",\"Z3E3\",\"R5S7\",\"R5S7\"\n\"162\",\"Chrono Jump\",\"on_autocast\",\"AC_TYPE_NOAC_POINT\",\"30\",\"0\",\"1500\",\"1500\",\"FALSE\",\"TRUE\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",\"CFLU\",\"FAED\",\"FAED\"\n\"163\",\"Learn\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"15\",\"0\",\"200\",\"200\",\"TRUE\",\"FALSE\",,\"TOWERS\",\"0\",,\"res://src/effects/spell_alim.tscn\",\"res://resources/icons/hud/gold.tres\",\"FP35\",\"VTZZ\",\"VTZZ\"\n\"164\",\"Shamanistic Ritual\",\"\",\"AC_TYPE_OFFENSIVE_BUFF\",\"10\",\"0\",\"450\",\"450\",\"TRUE\",\"FALSE\",\"ritual_bt\",\"TOWERS\",\"1\",,\"res://src/effects/healing_wave_target.tscn\",\"res://resources/icons/hud/gold.tres\",\"NFNI\",\"V9X6\",\"V9X6\"\n\"165\",\"Siphon Knowledge\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"30\",\"0\",\"450\",\"0\",\"FALSE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",\"YH7R\",\"RUF1\",\"RUF1\"\n\"166\",\"Purchase an Item\",\"on_autocast\",\"AC_TYPE_NOAC_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",\"C9E3\",\"M48Y\",\"M48Y\"\n\"167\",\"Transfer Experience\",\"on_autocast\",\"AC_TYPE_ALWAYS_BUFF\",\"60\",\"0\",\"1200\",\"1200\",\"FALSE\",\"TRUE\",,\"TOWERS\",\"1\",\"res://src/effects/dispel_magic_target.tscn\",,\"res://resources/icons/hud/gold.tres\",\"HKOD\",\"Z7Y8\",\"Z7Y8\"\n\"168\",\"Strength Boost\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"4\",\"0\",\"0\",\"1000\",\"TRUE\",\"FALSE\",,,\"0\",\"res://src/effects/dispel_magic_target.tscn\",,\"res://resources/icons/hud/gold.tres\",\"CNNX\",\"HRA5\",\"HRA5\"\n\"169\",\"Speed Boost\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"4\",\"0\",\"0\",\"1000\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",\"T8J0\",\"WRUL\",\"WRUL\"\n\"170\",\"Insane Strength\",\"on_autocast\",\"AC_TYPE_NOAC_IMMEDIATE\",\"120\",\"0\",\"0\",\"0\",\"TRUE\",\"FALSE\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",\"WHCY\",\"P59Y\",\"P59Y\"\n\"171\",\"Creep Broody\",\"on_autocast\",\"AC_TYPE_OFFENSIVE_IMMEDIATE\",\"6\",\"30\",\"1200\",\"0\",\"0\",\"0\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",,,\n\"172\",\"Creep Protector\",\"on_autocast\",\"AC_TYPE_ALWAYS_IMMEDIATE\",\"1\",\"0\",\"0\",\"0\",\"0\",\"0\",,,\"0\",,,\"res://resources/icons/hud/gold.tres\",,,\n"
  },
  {
    "path": "data/autocast_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/builder_properties.csv",
    "content": "\"id\",\"name english\",\"short name\",\"tier\",\"req level\",\"script path\",\"icon\",\"display name\",\"description\"\n0,\"None\",\"none\",\"beginner\",0,\"res://src/builders/instances/builder_none.gd\",\"res://resources/icons/animals/piglet_warrior.tres\",,\n1,\"Blademaster\",\"blademaster\",\"beginner\",0,\"res://src/builders/instances/builder_blademaster.gd\",\"res://resources/icons/animals/piglet_warrior.tres\",\"FEQ2\",\"H5K9\"\n2,\"Queen of the Seven Skies\",\"queen\",\"beginner\",0,\"res://src/builders/instances/builder_queen.gd\",\"res://resources/icons/tower_icons/harpy_witch.tres\",\"5MI4\",\"DZJM\"\n3,\"Adventurer\",\"adventurer\",\"beginner\",0,\"res://src/builders/instances/builder_adventurer.gd\",\"res://resources/icons/tower_icons/forest_archer.tres\",\"WFDL\",\"UDIO\"\n4,\"Iron Maiden\",\"iron_maiden\",\"beginner\",0,\"res://src/builders/instances/builder_iron_maiden.gd\",\"res://resources/icons/faces/woman_02.tres\",\"9I2M\",\"WYZZ\"\n5,\"Farseer\",\"farseer\",\"beginner\",0,\"res://src/builders/instances/builder_farseer.gd\",\"res://resources/icons/tower_icons/scales.tres\",\"5BS5\",\"MKRV\"\n6,\"Elementalist\",\"elementalist\",\"advanced\",5,\"res://src/builders/instances/builder_elementalist.gd\",\"res://resources/icons/tower_icons/servant_of_the_twin_flames.tres\",\"I8MD\",\"G03O\"\n7,\"Veteran Pilot\",\"veteran_pilot\",\"advanced\",5,\"res://src/builders/instances/builder_veteran_pilot.gd\",\"res://resources/icons/tower_icons/time_manipulator.tres\",\"I5GL\",\"R23Q\"\n8,\"Royal Assassin\",\"royal_assassin\",\"advanced\",5,\"res://src/builders/instances/builder_royal_assassin.gd\",\"res://resources/icons/faces/man_03.tres\",\"KBWV\",\"PB4F\"\n9,\"Benevolent Witch\",\"benevolent_witch\",\"advanced\",5,\"res://src/builders/instances/builder_benevolent_witch.gd\",\"res://resources/icons/faces/woman_01.tres\",\"DZ93\",\"YLE1\"\n10,\"Spirit Warden\",\"spirit_warden\",\"advanced\",5,\"res://src/builders/instances/builder_spirit_warden.gd\",\"res://resources/icons/faces/sleeping_leaf_spirit.tres\",\"K6EL\",\"0CWF\"\n11,\"Master of Encyclopedic Wisdom\",\"master\",\"advanced\",5,\"res://src/builders/instances/builder_master_of_encyclopedic_wisdom.gd\",\"res://resources/icons/tower_icons/bonk_the_living_mountain.tres\",\"114Y\",\"NOXV\"\n12,\"Feeble Fender\",\"fender\",\"specialist\",10,\"res://src/builders/instances/builder_feeble_fender.gd\",\"res://resources/icons/tower_icons/phantom.tres\",\"DG21\",\"T7S5\"\n13,\"Realist\",\"realist\",\"specialist\",10,\"res://src/builders/instances/builder_realist.gd\",\"res://resources/icons/tower_icons/arcane_storm.tres\",\"B4PL\",\"QT0I\"\n14,\"Arch Sorceress\",\"arch_sorceress\",\"specialist\",10,\"res://src/builders/instances/builder_arch_sorceress.gd\",\"res://resources/icons/tower_icons/sorceress.tres\",\"94TA\",\"ZF6J\"\n15,\"Barbarian Warlord\",\"barbarian\",\"specialist\",10,\"res://src/builders/instances/builder_barbarian_warlord.gd\",\"res://resources/icons/faces/orc_02.tres\",\"O9S7\",\"CLDT\"\n16,\"Panda Monk\",\"panda\",\"specialist\",10,\"res://src/builders/instances/builder_panda_monk.gd\",\"res://resources/icons/tower_icons/polar_bear_cub.tres\",\"F0OK\",\"MDLL\"\n17,\"Naga Time Twister\",\"naga\",\"specialist\",10,\"res://src/builders/instances/builder_naga_time_twister.gd\",\"res://resources/icons/tower_icons/forest_protectress.tres\",\"BTN2\",\"LP5E\"\n18,\"Goblin Alchemist\",\"goblin\",\"specialist\",10,\"res://src/builders/instances/builder_goblin_alchemist.gd\",\"res://resources/icons/tower_icons/thief_apprentice.tres\",\"WVTZ\",\"9RU3\"\n19,\"Backpacker\",\"backpacker\",\"specialist\",10,\"res://src/builders/instances/builder_backpacker.gd\",\"res://resources/icons/tower_icons/young_northern_troll.tres\",\"LUT6\",\"A2G8\"\n20,\"Maverick\",\"maverick\",\"hardcore\",20,\"res://src/builders/instances/builder_maverick.gd\",\"res://resources/icons/tower_icons/the_council_of_demons.tres\",\"IFL8\",\"H3RK\"\n21,\"Antagonizer\",\"antagonizer\",\"hardcore\",20,\"res://src/builders/instances/builder_antagonizer.gd\",\"res://resources/icons/tower_icons/wild_warbeast.tres\",\"Y86J\",\"NAG7\"\n"
  },
  {
    "path": "data/builder_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/exp_for_level.csv",
    "content": "level,exp\n0,0\n1,12\n2,24\n3,37\n4,51\n5,66\n6,82\n7,99\n8,117\n9,136\n10,156\n11,177\n12,199\n13,222\n14,246\n15,271\n16,297\n17,324\n18,352\n19,381\n20,411\n21,442\n22,474\n23,507\n24,541\n25,576\n26,612\n27,649\n28,687\n29,726\n30,766\n"
  },
  {
    "path": "data/exp_for_level.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/advanced.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Diminishing Returns\",\"KY9C\",\"3XT5\"\n\"Stacking buffs\",\"02CH\",\"ENAD\"\n\"Distribute experience\",\"HRF7\",\"WH6F\"\n\"Carry towers\",\"26NV\",\"PUPD\"\n\"Support towers\",\"A1G7\",\"K19J\"\n\"On attack abilities\",\"987U\",\"JAJI\"\n\"On hit abilities\",\"VQV4\",\"R82O\"\n\"On spell cast abilities\",\"1RPM\",\"3ZTG\"\n\"Attack speed adjusted chance\",\"27NS\",\"34UQ\"\n\"Multiplicative stats\",\"JSAY\",\"258N\"\n"
  },
  {
    "path": "data/hints/advanced.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/basic.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/basics.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Welcome\",\"AT2N\",\"EHPT\"\n\"Controls\",\"T375\",\"IVZ3\"\n\"Protect the portal\",\"RCI6\",\"TATP\"\n\"Income\",\"KYOA\",\"SGT4\"\n\"Choosing Elements\",\"RLYE\",\"KNIV\"\n\"Game Modes\",\"MIZU\",\"76JP\"\n\"Researching\",\"Y9M4\",\"PNLC\"\n"
  },
  {
    "path": "data/hints/basics.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/chat_commands.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"How to type\",\"6LQ9\",\"BK24\"\n\"/ready\",\"0BC0\",\"2YZ3\"\n\"/pause\",\"BE53\",\"39J6\"\n\"/ignore\",\"11QW\",\"1VP7\"\n\"/autospawn\",\"9TEO\",\"J4EI\"\n\"/autooil\",\"SNW8\",\"I8D1\"\n\"/gamespeed\",\"BVOE\",\"1QB0\"\n\"/damage-meters\",\"09BD\",\"5PJ5\"\n\"/ping\",\"9DW3\",\"4FGG\"\n\"/check-range-attack\",\"5HPS\",\"NYNW\"\n\"/print-ranges-to-towers\",\"PYZB\",\"8HQ7\"\n\"/allow-all\",\"X4NJ\",\"5WNE\"\n"
  },
  {
    "path": "data/hints/chat_commands.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/creep_specials.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Speed\",\"Z4S1\",\"PUOE\"\n\"Greater Speed\",\"QDDQ\",\"H4ZU\"\n\"Xtreme Speed\",\"VR83\",\"HAC3\"\n\"Slow\",\"0OJK\",\"CFVO\"\n\"Strong\",\"DKP4\",\"6RME\"\n\"Rich\",\"LQ4E\",\"EOQQ\"\n\"Relic Raider\",\"FYQ0\",\"X79J\"\n\"Ultra Wisdom\",\"KGXE\",\"NG49\"\n\"Armored\",\"LTN2\",\"RMVG\"\n\"Heavy Armored\",\"4U2J\",\"TKF9\"\n\"Xtreme Armor\",\"BKNH\",\"YBGJ\"\n\"Evasion\",\"KWYF\",\"I2AS\"\n\"Xtreme Evasion\",\"BMCE\",\"UVBG\"\n\"Ghost\",\"X810\",\"D7VR\"\n\"Spell Resistance\",\"TVP7\",\"ZRSG\"\n\"Greater Spell Resistance\",\"75BM\",\"3J3H\"\n\"Magic Immunity\",\"A65S\",\"BIBQ\"\n\"Ethereal\",\"9CZH\",\"2INL\"\n\"Slow Aura\",\"YECG\",\"S59I\"\n\"Mana Drain Aura\",\"93LW\",\"RY9O\"\n\"Spellbinder\",\"E0AD\",\"TV6K\"\n\"Stun Revenge\",\"50I1\",\"CJ17\"\n\"Regeneration\",\"UWXG\",\"KSH8\"\n\"Xtreme Regeneration\",\"QMRH\",\"CTCE\"\n\"Second Chance\",\"Y0VF\",\"3K6C\"\n\"Semi-Mechanical\",\"HIHB\",\"KA2W\"\n\"Mechanical\",\"7HYR\",\"ACUS\"\n\"Meaty\",\"I9SK\",\"SIQM\"\n\"Evolving\",\"HWF3\",\"6TXG\"\n\"Unlucky\",\"EJWU\",\"QQLY\"\n\"Flock\",\"MUGE\",\"ZQ56\"\n\"Protector\",\"GCZ3\",\"5NSZ\"\n\"Manashield\",\"ZJP2\",\"8HSS\"\n\"Manashield+\",\"3N95\",\"YFLA\"\n\"Purge Revenge\",\"JFM5\",\"BJ6B\"\n\"Dart\",\"4UHS\",\"IAW4\"\n\"Necromancer\",\"X7NZ\",\"M206\"\n\"Gravid\",\"B8YY\",\"JRM2\"\n"
  },
  {
    "path": "data/hints/creep_specials.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/creeps.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Creep Info\",\"K5GY\",\"3NNL\"\n\"Creep Specials\",\"LS4N\",\"3SFD\"\n\"Challenge creeps\",\"GUCR\",\"L7L0\"\n\"Sif creeps\",\"QP00\",\"PU56\"\n"
  },
  {
    "path": "data/hints/creeps.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/items.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Item drops\",\"0THT\",\"ELV8\"\n\"Equip Items\",\"A74M\",\"X8SZ\"\n\"Oil Items\",\"8H84\",\"DWL4\"\n\"Consumable Items\",\"ITTZ\",\"5KEK\"\n\"Item rarity\",\"YB2E\",\"PWTZ\"\n\"Horadric Cube\",\"NIBC\",\"RXL6\"\n\"Locking Items\",\"FY9Y\",\"ED47\"\n\"Tactical Items\",\"SO7S\",\"VMKY\"\n"
  },
  {
    "path": "data/hints/items.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/towers.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Tower Stats\",\"7YI4\",\"TDO8\"\n\"Upgrading\",\"Y53I\",\"XDM6\"\n\"Transforming\",\"CAVN\",\"5RTO\"\n\"Tower Positioning\",\"L97B\",\"836J\"\n\"Attack damage vs Spell damage\",\"URMS\",\"8TLT\"\n\"Critical hit\",\"FBML\",\"UECA\"\n\"Multicrit\",\"7P9S\",\"QQTB\"\n\"Tower Level\",\"IPQP\",\"TQUN\"\n\"Attack Types\",\"4L37\",\"VRQV\"\n\"Killing Blows\",\"40N7\",\"7H17\"\n\"Buff groups\",\"8ETV\",\"6R2P\"\n"
  },
  {
    "path": "data/hints/towers.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/hints/tutorial.csv",
    "content": "\"Title English\",\"Title\",\"Text\"\n\"Tutorial intro for random mode\",\"LF36\",\"294U\"\n\"Tutorial intro for build mode\",\"0NNW\",\"FIJK\"\n\"Research Elements\",\"1BOW\",\"FTNN\"\n\"Roll towers\",\"67KG\",\"KI8B\"\n\"Tower Stash\",\"HDCP\",\"2RYT\"\n\"Build a tower\",\"UH5S\",\"OONE\"\n\"Resources\",\"0MRM\",\"QETK\"\n\"Tower Info\",\"Q1F1\",\"0BC9\"\n\"Items\",\"FYWE\",\"DRLX\"\n\"Tower levels\",\"88YG\",\"NCLA\"\n\"Portal damage\",\"FJOB\",\"AZYT\"\n\"Wave finish\",\"ENNR\",\"141E\"\n\"Challenge wave\",\"8CCS\",\"49AV\"\n\"Upgrading towers\",\"FITA\",\"LL83\"\n\"Transforming towers\",\"CAIK\",\"HZB1\"\n"
  },
  {
    "path": "data/hints/tutorial.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/item_properties.csv",
    "content": "\"id\",\"name english\",\"type\",\"author\",\"rarity\",\"cost\",\"required wave level\",\"specials\",\"ability list\",\"aura list\",\"autocast list\",\"script path\",\"icon\",\"name\",\"description\"\r\n1,\"Artifact of Skadi\",\"regular\",\"Boekie\",\"unique\",1000,28,,,\"89\",,\"res://src/items/item_behaviors/artifact_of_skadi.gd\",\"res://resources/icons/furniture/artifact_of_skadi.tres\",\"GDNN\",\"A5EN\"\r\n2,\"Claws of Attack\",\"regular\",\"Boekie\",\"common\",632,46,\"MOD_DAMAGE_ADD_PERC,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/daggers/dagger_03.tres\",\"V6EL\",\"L1MX\"\r\n3,\"Vulshok's Claws\",\"regular\",\"Boekie\",\"uncommon\",1031,59,\"MOD_ATTACKSPEED,0.15,0.004\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_icons/vulshok_the_berserker.tres\",\"YJDZ\",\"CP7W\"\r\n4,\"Dragon's Heart\",\"regular\",\"Boekie\",\"uncommon\",1268,74,\"MOD_ATK_CRIT_CHANCE,0.1,0|MOD_ATK_CRIT_DAMAGE,0.075,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/dragon_01.tres\",\"P0UX\",\"MXKN\"\r\n5,\"Archer's Hood\",\"regular\",\"Boekie\",\"uncommon\",779,43,\"MOD_ATTACKSPEED,0.15,0|MOD_DAMAGE_ADD_PERC,-0.1,0|MOD_TRIGGER_CHANCES,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_icons/forest_archer.tres\",\"EHN2\",\"U56W\"\r\n6,\"Wizard Staff\",\"regular\",\"Boekie\",\"uncommon\",873,49,\"MOD_MANA_PERC,0.5,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/staff_06.tres\",\"57IQ\",\"5V66\"\r\n7,\"Heavy Gun\",\"regular\",\"Boekie\",\"uncommon\",981,56,\"MOD_DMG_TO_MASS,0.1,0|MOD_ATTACKSPEED,-0.25,0|MOD_DAMAGE_ADD_PERC,0.75,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/cannon_06.tres\",\"ZHDZ\",\"3BET\"\r\n8,\"Enchanted Mining Pick\",\"regular\",\"Boekie\",\"rare\",1090,44,\"MOD_DAMAGE_ADD_PERC,-0.175,0|MOD_SPELL_DAMAGE_DEALT,-0.175,0|MOD_ITEM_CHANCE_ON_KILL,0.55,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/mining_pick_02.tres\",\"N8BY\",\"8Z7L\"\r\n9,\"Backpack\",\"regular\",\"Boekie\",\"unique\",150,0,,,,\"161\",\"res://src/items/item_behaviors/backpack.gd\",\"res://resources/icons/hud/item_stash.tres\",\"LJVT\",\"2ROI\"\r\n10,\"Cursed Claw\",\"regular\",\"Boekie\",\"rare\",800,31,,\"613\",,,\"res://src/items/item_behaviors/cursed_claw.gd\",\"res://resources/icons/trinkets/claw_02.tres\",\"VE3B\",\"SI2Y\"\r\n11,\"Land Mine\",\"regular\",\"Boekie\",\"common\",275,18,\"MOD_DMG_TO_AIR,-0.25,0|MOD_DAMAGE_ADD_PERC,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/clubs/club_04_without_handle.tres\",\"L9OD\",\"C8PA\"\r\n12,\"Magical Essence\",\"regular\",\"Boekie\",\"common\",452,32,\"MOD_MANA_PERC,0.2,0|MOD_MANA_REGEN_PERC,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_05.tres\",\"ODOO\",\"GGDF\"\r\n13,\"Stasis Trap\",\"regular\",\"Boekie\",\"unique\",200,2,,\"614\",,,\"res://src/items/item_behaviors/stasis_trap.gd\",\"res://resources/icons/mechanical/circuit_board.tres\",\"0WHK\",\"33NT\"\r\n14,\"Fist of Doom\",\"regular\",\"Boekie\",\"rare\",536,19,\"MOD_DAMAGE_ADD_PERC,0.4,0|MOD_SPELL_DAMAGE_DEALT,0.4,0\",\"615\",,,\"res://src/items/item_behaviors/fist_of_doom.gd\",\"res://resources/icons/helmets/helmet_06.tres\",\"50MS\",\"70R9\"\r\n15,\"Outworn Spell Book\",\"regular\",\"Boekie\",\"common\",197,11,\"MOD_SPELL_CRIT_CHANCE,0.03,0|MOD_SPELL_CRIT_DAMAGE,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/dioramas/book_display.tres\",\"R3CD\",\"J8W8\"\r\n16,\"Ninja Glaive\",\"regular\",\"Boekie\",\"common\",390,27,\"MOD_DMG_TO_BOSS,0.35,0|MOD_ATK_CRIT_CHANCE,0.025,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/daggers/dagger_04.tres\",\"OUD1\",\"448I\"\r\n17,\"Cruel Torch\",\"regular\",\"Boekie\",\"unique\",1100,31,,,\"90\",,\"res://src/items/item_behaviors/cruel_torch.gd\",\"res://resources/icons/fire/torch.tres\",\"407N\",\"0F2E\"\r\n18,\"Enchanted Knives\",\"regular\",\"Boekie\",\"unique\",2500,76,\"MOD_ATTACKSPEED,-0.5,0\",\"616\",,,\"res://src/items/item_behaviors/enchanted_knives.gd\",\"res://resources/icons/daggers/dagger_02.tres\",\"ILAQ\",\"KFLV\"\r\n19,\"Survival Kit\",\"regular\",\"Boekie\",\"uncommon\",303,14,\"MOD_EXP_RECEIVED,0.05,0|MOD_BOUNTY_RECEIVED,0.05,0|MOD_ITEM_CHANCE_ON_KILL,0.05,0|MOD_ITEM_QUALITY_ON_KILL,0.05,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/food/beer_02.tres\",\"885F\",\"4AKZ\"\r\n20,\"Combat Gloves\",\"regular\",\"Boekie\",\"uncommon\",624,34,\"MOD_DMG_TO_UNDEAD,0.4,0.008|MOD_DMG_TO_ORC,0.4,0.008\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gloves/gloves_03.tres\",\"EZ2J\",\"UQWF\"\r\n21,\"Orc War Spear\",\"regular\",\"Boekie\",\"common\",486,34,\"MOD_DAMAGE_ADD_PERC,0.15,0|MOD_ATK_CRIT_DAMAGE,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/spears/spear_02.tres\",\"0TQD\",\"6QNA\"\r\n22,\"Divine Shield\",\"regular\",\"Boekie\",\"rare\",992,40,\"MOD_DEBUFF_DURATION,-0.45,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/shields/shield_white.tres\",\"9V0L\",\"CQZO\"\r\n23,\"Love Potion\",\"regular\",\"Boekie\",\"rare\",1333,55,\"MOD_BUFF_DURATION,0.5,0.004\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_heart_01.tres\",\"7D9F\",\"A36C\"\r\n24,\"Moonsilver Circlet\",\"regular\",\"Majildian\",\"uncommon\",1401,82,\"MOD_SPELL_DAMAGE_DEALT,0.2,0|MOD_SPELL_CRIT_DAMAGE,1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/helmets/crown_03.tres\",\"KP2I\",\"U7LK\"\r\n25,\"Crystal Staff\",\"regular\",\"Neotopia\",\"uncommon\",961,55,\"MOD_DMG_TO_UNDEAD,0.25,0.01|MOD_SPELL_DAMAGE_DEALT,0.2,0.006\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/staff_05.tres\",\"DW8H\",\"UA2U\"\r\n26,\"Lightning Boots\",\"regular\",\"Boekie\",\"uncommon\",572,31,\"MOD_ATTACKSPEED,0.3,0.004|MOD_MULTICRIT_COUNT,-1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/armor/lightning_boot.tres\",\"ELY8\",\"H7FM\"\r\n27,\"Claws of the Bear\",\"regular\",\"drol\",\"uncommon\",540,29,\"MOD_DAMAGE_ADD_PERC,0.15,0|MOD_MANA_PERC,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/barbed_spike.tres\",\"B4VY\",\"2NY2\"\r\n28,\"Ceremonial Skull\",\"regular\",\"Boekie\",\"uncommon\",265,12,\"MOD_ATTACKSPEED,-0.15,0|MOD_SPELL_DAMAGE_DEALT,0.4,0.005\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/undead/skull_06.tres\",\"S9RG\",\"6IEH\"\r\n29,\"Scroll of Myths\",\"regular\",\"Boekie\",\"common\",293,19,\"MOD_MANA_REGEN_PERC,0.3,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/scrolls/scroll_04.tres\",\"8XXD\",\"1SML\"\r\n30,\"Tome of Shadow Magic\",\"regular\",\"drol\",\"uncommon\",257,11,\"MOD_DMG_TO_UNDEAD,-0.05,0|MOD_BUFF_DURATION,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/book_11.tres\",\"9ES8\",\"FASD\"\r\n31,\"Zombie Hand\",\"regular\",\"Majildian\",\"uncommon\",1047,60,\"MOD_MANA_PERC,0.4,0|MOD_MANA_REGEN_PERC,-0.3,0|MOD_BUFF_DURATION,0.4,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gloves/gloves_06.tres\",\"MY6Y\",\"VWMA\"\r\n32,\"Phoenix Egg\",\"regular\",\"drol\",\"rare\",1656,69,\"MOD_SPELL_DAMAGE_DEALT,0.2,0|MOD_BUFF_DURATION,0.4,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/gem_07.tres\",\"WJIJ\",\"YLN5\"\r\n33,\"Bomb Shells\",\"regular\",\"Neotopia\",\"common\",452,32,\"MOD_DMG_TO_MASS,0.5,0|MOD_ATTACKSPEED,0.05,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/misc/balls_02.tres\",\"VDT8\",\"Z3ZF\"\r\n34,\"Hand of Ruin\",\"regular\",\"drol\",\"uncommon\",293,14,\"MOD_DMG_TO_NATURE,0.2,0|MOD_DMG_TO_ORC,0.2,0|MOD_DMG_TO_HUMANOID,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/masks/mask_04.tres\",\"YYR3\",\"0I0D\"\r\n35,\"Bonk's Face\",\"regular\",\"drol\",\"unique\",800,21,\"MOD_DMG_TO_MASS,0.25,0\",\"617\",,,\"res://src/items/item_behaviors/bonks_face.gd\",\"res://resources/icons/tower_variations/bonk_the_living_mountain_small.tres\",\"Q1CV\",\"MPHM\"\r\n36,\"Magic Branch\",\"regular\",\"Boekie\",\"common\",517,37,\"MOD_ATTACKSPEED,0.05,0|MOD_SPELL_DAMAGE_DEALT,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/plants/branch_02.tres\",\"0HPR\",\"7ZH0\"\r\n37,\"Mini Sheep\",\"regular\",\"Boekie\",\"common\",517,37,\"MOD_DMG_TO_NATURE,0.25,0|MOD_TRIGGER_CHANCES,0.125,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/cow.tres\",\"MK5Z\",\"Q0B9\"\r\n38,\"Pirate Map\",\"regular\",\"Boekie\",\"common\",729,54,\"MOD_BOUNTY_RECEIVED,0.3,0|MOD_ITEM_CHANCE_ON_KILL,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/note_01.tres\",\"9LEE\",\"SR0B\"\r\n39,\"Piece of Meat\",\"regular\",\"Boekie\",\"common\",567,41,\"MOD_DMG_TO_NORMAL,0.1,0|MOD_DAMAGE_ADD_PERC,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/scrolls/scroll_01.tres\",\"3HPC\",\"0ZCZ\"\r\n40,\"Gargoyle Wing\",\"regular\",\"Boekie\",\"common\",640,47,\"MOD_DMG_TO_AIR,1,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/bat_03.tres\",\"XQVP\",\"MFWG\"\r\n41,\"Ancient Figurine\",\"regular\",\"drol\",\"uncommon\",1161,67,\"MOD_MANA_PERC,0.25,0|MOD_MANA_REGEN_PERC,0.5,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/statues/statue_dwarf_02.tres\",\"W674\",\"7ODQ\"\r\n42,\"Sleeve of Rage\",\"regular\",\"SirCoqaLot.\",\"unique\",2000,60,,\"618\",,,\"res://src/items/item_behaviors/sleeve_of_rage.gd\",\"res://resources/icons/fire/burning_cloth.tres\",\"OPRW\",\"PGZO\"\r\n43,\"Wine of Aluqah\",\"regular\",\"SymphonyX\",\"uncommon\",585,32,\"MOD_ATTACKSPEED,-0.15,0|MOD_DAMAGE_ADD_PERC,0.5,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/beaker_02.tres\",\"4NAS\",\"LH6M\"\r\n44,\"Mask of Sanity\",\"regular\",\"SymphonyX\",\"uncommon\",656,36,\"MOD_DMG_TO_NORMAL,0.2,0|MOD_DMG_TO_CHAMPION,0.1,0|MOD_DMG_TO_AIR,-0.25,0|MOD_ATTACKSPEED,0.1,0.0025\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/masks/mask_02.tres\",\"JEQ5\",\"RIEH\"\r\n45,\"Excalibur\",\"regular\",\"SymphonyX\",\"unique\",1405,40,\"MOD_ATTACKSPEED,-0.05,0|MOD_ATK_CRIT_CHANCE,0.1,0|MOD_ATK_CRIT_DAMAGE,0.1,0\",\"619\",,,\"res://src/items/item_behaviors/excalibur.gd\",\"res://resources/icons/swords/greatsword_02.tres\",\"C6MS\",\"74BN\"\r\n46,\"Minds Key\",\"regular\",\"Neotopia\",\"uncommon\",1225,71,\"MOD_SPELL_CRIT_CHANCE,0.025,0.001|MOD_TRIGGER_CHANCES,0.15,0.006\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/scrolls/scroll_02.tres\",\"GR7L\",\"RNQ6\"\r\n47,\"Mana Shell\",\"regular\",\"drol\",\"common\",154,8,\"MOD_MANA_PERC,0.195,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/lock_02.tres\",\"IA26\",\"BKJB\"\r\n48,\"Lucky Dice\",\"regular\",\"Majildian\",\"rare\",1867,78,\"MOD_ATK_CRIT_CHANCE,0.025,0.002|MOD_SPELL_CRIT_CHANCE,0.025,0.002|MOD_ITEM_CHANCE_ON_KILL,0.05,0.004|MOD_TRIGGER_CHANCES,0.025,0.002\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/hud/dice.tres\",\"FH4X\",\"3LA8\"\r\n49,\"Scepter of the Lunar Light\",\"regular\",\"drol\",\"rare\",1708,71,\"MOD_DMG_TO_MAGIC,0.5,0|MOD_SPELL_CRIT_CHANCE,0.12,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/wand_02.tres\",\"0URL\",\"7VEA\"\r\n50,\"Magic Hammer\",\"regular\",\"F12ight\",\"rare\",150,2,,\"620\",,,\"res://src/items/item_behaviors/magic_hammer.gd\",\"res://resources/icons/blunt_weapons/hammer_03.tres\",\"TMBN\",\"FNMM\"\r\n51,\"Battle Suit\",\"regular\",\"Boekie\",\"uncommon\",617,33,\"MOD_ATTACKSPEED,0,0.006|MOD_DAMAGE_ADD_PERC,0,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/helmets/helmet_08.tres\",\"ZZ5Y\",\"8K35\"\r\n52,\"Zombie Head\",\"regular\",\"Boekie\",\"uncommon\",613,33,\"MOD_DAMAGE_ADD_PERC,0.75,0.01|MOD_ITEM_CHANCE_ON_KILL,-0.5,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/faces/mech_zombie.tres\",\"A9H7\",\"K8AL\"\r\n53,\"Morgul Slave\",\"regular\",\"Boekie\",\"uncommon\",247,11,\"MOD_ATTACKSPEED,0.01,0.001|MOD_DAMAGE_ADD_PERC,0.03,0.002|MOD_ATK_CRIT_CHANCE,0.005,0.0005\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/bat_02.tres\",\"QLZQ\",\"QI4V\"\r\n54,\"Tiny Rabbit\",\"regular\",\"Boekie\",\"uncommon\",117,3,\"MOD_EXP_RECEIVED,0.02,0|MOD_BOUNTY_RECEIVED,0.02,0|MOD_ITEM_CHANCE_ON_KILL,0.02,0|MOD_ITEM_QUALITY_ON_KILL,0.02,0|MOD_MANA_PERC,0.02,0|MOD_MANA_REGEN_PERC,0.02,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/rabbit.tres\",\"A7JW\",\"SSHV\"\r\n55,\"Flaming Arrow\",\"regular\",\"Boekie\",\"uncommon\",873,49,\"MOD_ATTACKSPEED,0.1,0.005|MOD_ATK_CRIT_DAMAGE,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/spears/many_spears_01.tres\",\"QZ8C\",\"AJ96\"\r\n56,\"Bhaal's Essence\",\"regular\",\"poussix\",\"unique\",2727,83,\"MOD_DEBUFF_DURATION,-0.6,0\",,\"91\",,\"res://src/items/item_behaviors/bhaals_essence.gd\",\"res://resources/icons/animals/dragon_04.tres\",\"U8MG\",\"WLLE\"\r\n57,\"Electrified Horseshoe\",\"regular\",\"Neotopia\",\"common\",1047,79,\"MOD_ATTACKSPEED,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rings/ring_07.tres\",\"G5Y7\",\"ENAN\"\r\n58,\"War Drum\",\"regular\",\"Neotopia\",\"unique\",1325,38,,,\"92\",,\"res://src/items/item_behaviors/war_drum.gd\",\"res://resources/icons/fire/fire_bowl_03.tres\",\"GPPH\",\"T6WU\"\r\n59,\"Silver Armor\",\"regular\",\"Boekie\",\"rare\",1410,58,\"MOD_ATTACKSPEED,0.05,0|MOD_DAMAGE_ADD_PERC,0.1,0\",\"621\",,,\"res://src/items/item_behaviors/silver_armor.gd\",\"res://resources/icons/armor/chest_plate.tres\",\"RCZ4\",\"PRU2\"\r\n60,\"Flag of the Allegiance\",\"regular\",\"Boekie\",\"unique\",800,21,,,\"93\",,\"res://src/items/item_behaviors/flag_of_the_allegiance.gd\",\"res://resources/icons/misc/flag_01.tres\",\"RECP\",\"ZSZC\"\r\n61,\"Golden Decoration\",\"regular\",\"Boekie\",\"unique\",851,23,\"MOD_BOUNTY_RECEIVED,0.1,0.004\",\"622\",,,\"res://src/items/item_behaviors/golden_decoration.gd\",\"res://resources/icons/trinkets/trinket_05.tres\",\"JLON\",\"QYFR\"\r\n62,\"Jewels of the Moon\",\"regular\",\"drol\",\"unique\",1132,32,\"MOD_TRIGGER_CHANCES,0.2,0\",\"623\",,,\"res://src/items/item_behaviors/jewels_of_the_moon.gd\",\"res://resources/icons/misc/balls_01.tres\",\"8UB3\",\"2BYR\"\r\n63,\"Magic Vial\",\"regular\",\"boekie\",\"uncommon\",402,20,\"MOD_MANA_REGEN_PERC,0.1,0.004|MOD_BUFF_DURATION,0.1,0.004\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_10.tres\",\"E2YS\",\"5SSQ\"\r\n64,\"Small Stone\",\"regular\",\"cedi\",\"common\",70,1,\"MOD_DAMAGE_ADD_PERC,0.01,0.004\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/stone_01.tres\",\"N1SB\",\"7A2V\"\r\n65,\"Fairy's Wand\",\"regular\",\"cedi\",\"common\",56,0,\"MOD_MANA_REGEN,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/wand_05.tres\",\"65N5\",\"52CN\"\r\n66,\"Fancy Lights\",\"regular\",\"cedi\",\"common\",67,1,\"MOD_MANA_REGEN_PERC,0.1,0.001\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/fire.tres\",\"IDBQ\",\"3OC4\"\r\n67,\"Floating Mark\",\"regular\",\"cedi\",\"common\",177,10,\"MOD_DAMAGE_ADD_PERC,0.02,0.001|MOD_ATK_CRIT_CHANCE,0.02,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/mechanical/compass.tres\",\"XCLK\",\"G4R1\"\r\n68,\"Blunt Club\",\"regular\",\"drol\",\"common\",79,2,\"MOD_DAMAGE_ADD_PERC,0.025,0|MOD_ATK_CRIT_CHANCE,0.01,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/clubs/club_01.tres\",\"R759\",\"6B2M\"\r\n69,\"Ledger\",\"regular\",\"drol\",\"common\",56,0,\"MOD_BOUNTY_RECEIVED,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/book_09.tres\",\"FCW3\",\"Y5V4\"\r\n70,\"Collection of Stories\",\"regular\",\"drol\",\"common\",60,0,\"MOD_EXP_RECEIVED,0.14,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/note_03.tres\",\"SZUJ\",\"CH5H\"\r\n71,\"Old Spear\",\"regular\",\"drol\",\"common\",60,0,\"MOD_ATK_CRIT_CHANCE,0.014,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/spears/spear_01.tres\",\"ES0C\",\"307L\"\r\n72,\"Primitive Flute\",\"regular\",\"drol\",\"common\",60,0,\"MOD_SPELL_DAMAGE_DEALT,0.06,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/misc/teapot_03.tres\",\"CKKT\",\"GSDC\"\r\n73,\"Wooden Leg\",\"regular\",\"drol\",\"common\",60,0,\"MOD_ATTACKSPEED,0.03,0\",,,,\"res://src/items/item_behaviors/wooden_leg.gd\",\"res://resources/icons/blunt_weapons/wood_02.tres\",\"UABJ\",\"XBAC\"\r\n74,\"Axe of Decapitation\",\"regular\",\"cedi\",\"uncommon\",293,14,\"MOD_DMG_TO_UNDEAD,-0.1,0|MOD_DMG_TO_MAGIC,-0.1,0|MOD_DMG_TO_NATURE,-0.1,0|MOD_DMG_TO_ORC,-0.1,0|MOD_DMG_TO_HUMANOID,1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/glaive_01.tres\",\"XVJ2\",\"6DZB\"\r\n75,\"Void Vial\",\"regular\",\"cedi\",\"common\",103,4,\"MOD_DMG_TO_MAGIC,0.5,0|MOD_MANA_REGEN_PERC,-0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_09.tres\",\"6EET\",\"9N7D\"\r\n76,\"Claws of Ursus\",\"regular\",\"drol\",\"rare\",1161,47,\"MOD_DAMAGE_ADD_PERC,0.25,0|MOD_MANA_PERC,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/trinket_07.tres\",\"PBZQ\",\"9NF3\"\r\n77,\"Claws of Wisdom\",\"regular\",\"drol\",\"uncommon\",14,0,\"MOD_ATTACKSPEED,-0.16,0|MOD_EXP_RECEIVED,0.8,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/trinket_08.tres\",\"MSQM\",\"VK4K\"\r\n78,\"Inscribed Bark\",\"regular\",\"drol\",\"common\",36,0,\"MOD_DMG_TO_MAGIC,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/shields/shield_wood_small.tres\",\"N4A2\",\"4YO7\"\r\n79,\"Rusted Rifle\",\"regular\",\"drol\",\"common\",36,0,\"MOD_DMG_TO_HUMANOID,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/gun_01.tres\",\"NLSH\",\"WB8M\"\r\n80,\"Short Sword\",\"regular\",\"Boekie\",\"common\",56,0,\"MOD_DAMAGE_ADD_PERC,0.05,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/swords/sword_01.tres\",\"D348\",\"5ZON\"\r\n81,\"Pillage Tools\",\"regular\",\"drol\",\"uncommon\",210,8,\"MOD_BOUNTY_RECEIVED,0,0.02\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/swords/greatsword_01.tres\",\"U5XS\",\"1M42\"\r\n82,\"Touch of a Spirit\",\"regular\",\"drol\",\"uncommon\",79,0,\"MOD_DAMAGE_ADD_PERC,-0.1,0|MOD_SPELL_DAMAGE_DEALT,-0.1,0|MOD_MANA_REGEN_PERC,0.5,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/fish_04.tres\",\"95D9\",\"KS0A\"\r\n83,\"Periscope\",\"regular\",\"drol\",\"uncommon\",79,0,\"MOD_TRIGGER_CHANCES,0.05,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/cannon_08.tres\",\"A39Y\",\"89OB\"\r\n84,\"Ancient Inscribed Bark\",\"regular\",\"drol\",\"uncommon\",63,0,\"MOD_DPS_ADD,5,0|MOD_DMG_TO_MAGIC,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/shields/shield_wood_small_glowing.tres\",\"YMX0\",\"8ZJX\"\r\n85,\"Blessed Holy Scepter\",\"regular\",\"drol\",\"uncommon\",63,0,\"MOD_DPS_ADD,5,0|MOD_DMG_TO_UNDEAD,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/holy/cross_03.tres\",\"KW6N\",\"M17F\"\r\n86,\"Blunderbuss Rifle\",\"regular\",\"drol\",\"uncommon\",63,0,\"MOD_DPS_ADD,5,0|MOD_DMG_TO_HUMANOID,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/gun_02.tres\",\"2UHB\",\"6ICT\"\r\n87,\"Thick Tree Branch\",\"regular\",\"drol\",\"uncommon\",63,0,\"MOD_DPS_ADD,5,0|MOD_DMG_TO_ORC,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/plants/stump.tres\",\"9I8Y\",\"DMIL\"\r\n88,\"Undead Spiked Claws\",\"regular\",\"drol\",\"uncommon\",63,0,\"MOD_DPS_ADD,5,0|MOD_DMG_TO_NATURE,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/undead/skull_wand_03.tres\",\"0P87\",\"7T2P\"\r\n89,\"Dull Axe\",\"regular\",\"Majildian\",\"common\",154,8,\"MOD_ATK_CRIT_DAMAGE,0.325,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/axe_01.tres\",\"KQQC\",\"TFJT\"\r\n90,\"Hunting Map\",\"regular\",\"drol\",\"uncommon\",210,8,\"MOD_EXP_RECEIVED,0.12,0|MOD_ITEM_CHANCE_ON_KILL,0.06,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/dioramas/mountain.tres\",\"1H45\",\"GA4A\"\r\n91,\"Shimmerweed\",\"regular\",\"drol\",\"common\",964,73,\"MOD_DMG_TO_ORC,0.45,0|MOD_SPELL_DAMAGE_DEALT,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/trinket_03.tres\",\"IG25\",\"QREU\"\r\n92,\"Inscribed Pebble\",\"regular\",\"drol\",\"common\",1092,83,\"MOD_DMG_TO_MAGIC,0.24,0|MOD_SPELL_CRIT_CHANCE,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/orbs/orb_molten_dull.tres\",\"11NJ\",\"VF45\"\r\n93,\"Gift of the Wild\",\"regular\",\"drol\",\"common\",1019,77,\"MOD_DAMAGE_ADD_PERC,0.125,0|MOD_SPELL_DAMAGE_DEALT,0.125,0|MOD_EXP_RECEIVED,0.125,0|MOD_MANA_PERC,0.125,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/bowl_02.tres\",\"PG0V\",\"LPK5\"\r\n94,\"Mining Lamp\",\"regular\",\"drol\",\"common\",1047,79,\"MOD_ITEM_CHANCE_ON_KILL,0.28,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/mechanical/lamp.tres\",\"RC6E\",\"ZO86\"\r\n95,\"Voodoo Doll\",\"regular\",\"drol\",\"uncommon\",172,6,\"MOD_ATTACKSPEED,0,0.005\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/undead/skull_doll.tres\",\"NTSK\",\"SCQE\"\r\n96,\"Spiked Club\",\"regular\",\"drol\",\"uncommon\",207,8,\"MOD_DAMAGE_ADD_PERC,0.025,0|MOD_ATK_CRIT_CHANCE,0.025,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/clubs/club_03.tres\",\"K3L9\",\"CYRX\"\r\n97,\"Mini Tank\",\"regular\",\"cedi\",\"uncommon\",1466,86,\"MOD_DPS_ADD,1000,0|MOD_MANA_REGEN_PERC,0.2,0.002\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/mech_toad.tres\",\"APSD\",\"EY9W\"\r\n98,\"Faded Gloves\",\"regular\",\"Majildian\",\"common\",151,8,\"MOD_ATTACKSPEED,0.055,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gloves/gloves_01.tres\",\"MQZ9\",\"POVC\"\r\n99,\"Rusty Mining Pick\",\"regular\",\"Boekie\",\"common\",36,0,\"MOD_ITEM_CHANCE_ON_KILL,0.12,0|MOD_ITEM_QUALITY_ON_KILL,-0.12,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/mining_pick_01.tres\",\"60AW\",\"ZBDM\"\r\n100,\"Arcane Eye\",\"regular\",\"cedi\",\"uncommon\",1377,80,\"MOD_SPELL_DAMAGE_DEALT,0.48,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/eye_blue.tres\",\"8GA6\",\"R2Y8\"\r\n101,\"Thunder Gloves\",\"regular\",\"cedi\",\"rare\",1924,81,\"MOD_ATTACKSPEED,0.2,0|MOD_SPELL_CRIT_DAMAGE,0.7,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gloves/gloves_07.tres\",\"0CGR\",\"8RPW\"\r\n102,\"Polarisator\",\"regular\",\"cedi\",\"uncommon\",1161,67,\"MOD_ATK_CRIT_CHANCE,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/lock_03.tres\",\"8DF1\",\"NY95\"\r\n103,\"Priest Figurine\",\"regular\",\"Boekie\",\"unique\",250,4,,\"624\",,,\"res://src/items/item_behaviors/priest_figurine.gd\",\"res://resources/icons/holy/altar.tres\",\"9TNT\",\"Z0RH\"\r\n104,\"Old Crystal Ball\",\"regular\",\"Majildian\",\"common\",151,8,\"MOD_ITEM_CHANCE_ON_KILL,0.077,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/orbs/orb_ice.tres\",\"1S6L\",\"NX5B\"\r\n105,\"Spiderling\",\"regular\",\"Boekie\",\"rare\",50,0,,\"625\",,,\"res://src/items/item_behaviors/spiderling.gd\",\"res://resources/icons/animals/spider_03.tres\",\"I2CQ\",\"86CU\"\r\n106,\"Spider Silk\",\"regular\",\"Neotopia\",\"common\",263,17,\"MOD_DMG_TO_AIR,0.5,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/spider_01.tres\",\"43KF\",\"J5Z4\"\r\n107,\"Troll Voodoo Mask\",\"regular\",\"Neotopia\",\"common\",831,62,\"MOD_MANA_PERC,0.3,0|MOD_MANA_REGEN_PERC,0.3,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/masks/mask_01.tres\",\"HUOE\",\"XN8W\"\r\n108,\"Expanding Mind\",\"regular\",\"drol\",\"uncommon\",154,5,\"MOD_EXP_RECEIVED,0.5,-0.02\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/mechanical/alchemy_kit_01.tres\",\"N460\",\"JC2E\"\r\n109,\"Magic Flower\",\"regular\",\"drol\",\"uncommon\",172,6,\"MOD_SPELL_DAMAGE_DEALT,0,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/plants/flower_01.tres\",\"0ZK2\",\"EQGD\"\r\n110,\"Mark of the Talon\",\"regular\",\"drol\",\"uncommon\",172,6,\"MOD_ATTACKSPEED,0.04,0|MOD_SPELL_DAMAGE_DEALT,0.04,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/rooster_warrior.tres\",\"G0DX\",\"SDLA\"\r\n111,\"Mark of the Claw\",\"regular\",\"drol\",\"uncommon\",172,6,\"MOD_DAMAGE_ADD_PERC,0.07,0|MOD_SPELL_DAMAGE_DEALT,0.04,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/claw_03.tres\",\"GP7N\",\"Q9BX\"\r\n112,\"Flawless Sapphire\",\"regular\",\"drol\",\"uncommon\",386,19,\"MOD_BOUNTY_RECEIVED,0,0.03\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/earring_01.tres\",\"DIHS\",\"IV0L\"\r\n113,\"Small Orb\",\"regular\",\"Majildian\",\"common\",154,8,\"MOD_SPELL_CRIT_DAMAGE,0.39,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/orbs/orb_small.tres\",\"9BH6\",\"AC8C\"\r\n114,\"Support Column\",\"regular\",\"drol\",\"uncommon\",244,11,\"MOD_ITEM_CHANCE_ON_KILL,0.05,0|MOD_ITEM_QUALITY_ON_KILL,0.075,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/blunt_weapons/wood_04.tres\",\"RYOA\",\"XSEA\"\r\n115,\"Obsidian Figurine\",\"regular\",\"drol\",\"uncommon\",240,10,\"MOD_DEBUFF_DURATION,-0.175,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/statues/statue_03.tres\",\"8QJN\",\"B1BQ\"\r\n116,\"Shadowfoot's Mantle\",\"regular\",\"drol\",\"uncommon\",1386,81,\"MOD_ITEM_QUALITY_ON_KILL,0.45,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/helmets/helmet_05.tres\",\"893D\",\"JNFE\"\r\n117,\"Blood Crown\",\"regular\",\"drol\",\"uncommon\",1401,82,\"MOD_DAMAGE_ADD_PERC,0.15,0|MOD_BOUNTY_RECEIVED,0.55,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/helmets/crown_01.tres\",\"KADB\",\"QMQ8\"\r\n118,\"Sage's Mask\",\"regular\",\"drol\",\"uncommon\",1426,83,\"MOD_MANA_REGEN_PERC,0.86,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/masks/mask_03.tres\",\"N0EW\",\"EFXV\"\r\n119,\"Knowing Mind\",\"regular\",\"drol\",\"uncommon\",1340,78,\"MOD_EXP_RECEIVED,1.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/magic/lantern.tres\",\"RYDJ\",\"I61O\"\r\n120,\"Purifying Gloves\",\"regular\",\"drol\",\"rare\",150,2,,\"626\",,,\"res://src/items/item_behaviors/purifying_gloves.gd\",\"res://resources/icons/gloves/gloves_05.tres\",\"VR0B\",\"2BPH\"\r\n121,\"Basic Wand\",\"regular\",\"Majildian\",\"common\",157,8,\"MOD_SPELL_CRIT_CHANCE,0.033,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/wand_04.tres\",\"IYJ1\",\"QI44\"\r\n122,\"Medallion of Opulence\",\"regular\",\"Chronos\",\"rare\",250,7,,\"627\",,,\"res://src/items/item_behaviors/medallion_of_opulence.gd\",\"res://resources/icons/amulets/amulet_03.tres\",\"WUWK\",\"3KK7\"\r\n123,\"Troll Charm\",\"regular\",\"SirCoqaLot.\",\"uncommon\",1340,78,\"MOD_ATK_CRIT_CHANCE,0.05,0|MOD_BUFF_DURATION,0.3,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/trinket_01.tres\",\"VQVV\",\"EGI5\"\r\n124,\"Scroll of Piercing Magic\",\"regular\",\"drol\",\"uncommon\",300,14,,\"628\",,,\"res://src/items/item_behaviors/scroll_of_piercing_magic.gd\",\"res://resources/icons/scrolls/scroll_03.tres\",\"M4Y0\",\"UPWE\"\r\n125,\"Mystical Shell\",\"regular\",\"drol\",\"uncommon\",150,5,,\"629\",,,\"res://src/items/item_behaviors/mystical_shell.gd\",\"res://resources/icons/orbs/orb_ice_melting.tres\",\"UGTS\",\"4VV1\"\r\n126,\"Forcefield Generator\",\"regular\",\"drol\",\"rare\",1600,67,,,\"94\",,\"res://src/items/item_behaviors/forcefield_generator.gd\",\"res://resources/icons/tower_icons/energy_junction.tres\",\"4G3T\",\"V40A\"\r\n127,\"Crescent Stone\",\"regular\",\"drol\",\"rare\",400,13,,\"630\",,,\"res://src/items/item_behaviors/crescent_stone.gd\",\"res://resources/icons/orbs/moon.tres\",\"LTMA\",\"Q55V\"\r\n128,\"Dumpster\",\"regular\",\"Monolith\",\"uncommon\",293,14,\"MOD_ITEM_CHANCE_ON_KILL,0.3,0.01|MOD_ITEM_QUALITY_ON_KILL,-0.4,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/misc/toolbox_01.tres\",\"2HO9\",\"MKAZ\"\r\n129,\"Plain Staff\",\"regular\",\"Majildian\",\"common\",151,8,\"MOD_SPELL_DAMAGE_DEALT,0.11,0\",,,,\"res://src/items/item_behaviors/plain_staff.gd\",\"res://resources/icons/staves/staff_02.tres\",\"0NGU\",\"WIJT\"\r\n130,\"Hippogryph Egg\",\"regular\",\"drol\",\"rare\",600,22,,\"631\",,,\"res://src/items/item_behaviors/hippogryph_egg.gd\",\"res://resources/icons/magic/magic_stone.tres\",\"QJJV\",\"HXLG\"\r\n131,\"Mana Stone\",\"regular\",\"F12ight\",\"rare\",800,31,,\"632, 633\",\"95\",,\"res://src/items/item_behaviors/mana_stone.gd\",\"res://resources/icons/gems/gem_03.tres\",\"P0DV\",\"0ICG\"\r\n132,\"Dagger of Bane\",\"regular\",\"F12ight\",\"unique\",700,18,,\"634\",,,\"res://src/items/item_behaviors/dagger_of_bane.gd\",\"res://resources/icons/daggers/dagger_07.tres\",\"Z65L\",\"HGFD\"\r\n133,\"The Sucona\",\"regular\",\"cedi\",\"rare\",1788,75,\"MOD_DMG_TO_NATURE,2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/mechanical/factory_gears.tres\",\"BX1A\",\"82QP\"\r\n134,\"Beast Head\",\"regular\",\"cedi\",\"uncommon\",1525,89,\"MOD_DPS_ADD,1230,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_icons/wild_warbeast.tres\",\"PEP7\",\"8UJP\"\r\n135,\"Training Manual\",\"regular\",\"Majildian\",\"common\",154,8,\"MOD_EXP_RECEIVED,0.26,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/shields/shield_with_gold_helmet.tres\",\"QJHT\",\"8TDE\"\r\n136,\"Grand Seal of Pickiness\",\"regular\",\"Glowackos\",\"uncommon\",1176,68,\"MOD_ITEM_CHANCE_ON_KILL,-0.35,0|MOD_ITEM_QUALITY_ON_KILL,0.75,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/trinket_09.tres\",\"F076\",\"GHPN\"\r\n137,\"Pendant of Promptness\",\"regular\",\"Glowackos\",\"unique\",2505,76,\"MOD_ATTACKSPEED,0.75,0.01\",\"635\",,,\"res://src/items/item_behaviors/pendant_of_promptness.gd\",\"res://resources/icons/amulets/amulet_02.tres\",\"CSKE\",\"S39X\"\r\n138,\"Bartuc's Spirit\",\"regular\",\"Bartuck\",\"rare\",1000,40,,\"636\",,,\"res://src/items/item_behaviors/bartucs_spirit.gd\",\"res://resources/icons/faces/orc_02.tres\",\"943G\",\"EY9L\"\r\n139,\"Diamond of Greed\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_BOUNTY_RECEIVED,0.45,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/gem_06.tres\",\"YF4N\",\"5HSJ\"\r\n140,\"Chrono Jumper\",\"regular\",\"axllow\",\"unique\",770,20,,,,\"162\",\"res://src/items/item_behaviors/chrono_jumper.gd\",\"res://resources/icons/mechanical/mech_umbrella.tres\",\"FVLQ\",\"92O4\"\r\n141,\"Magician's Doorkey\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_SPELL_CRIT_CHANCE,0.075,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/key_02.tres\",\"9IIE\",\"S46V\"\r\n142,\"Jah'Rakal's Fury\",\"regular\",\"Der_kleine_Tomy\",\"unique\",1000,28,,\"637\",,,\"res://src/items/item_behaviors/jah_rakals_fury.gd\",\"res://resources/icons/faces/orc_01.tres\",\"QY11\",\"E4OU\"\r\n143,\"Blunt Dagger\",\"regular\",\"Majildian\",\"common\",145,7,\"MOD_ATK_CRIT_CHANCE,0.025,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/daggers/dagger_01.tres\",\"GCX5\",\"UP7E\"\r\n144,\"Wanted List\",\"regular\",\"Lapsus\",\"uncommon\",148,5,,\"638\",,,\"res://src/items/item_behaviors/wanted_list.gd\",\"res://resources/icons/books/note_02.tres\",\"7C7V\",\"04J0\"\r\n145,\"Shiny Emerald\",\"regular\",\"poussix\",\"uncommon\",406,20,\"MOD_ATTACKSPEED,-0.1,0|MOD_SPELL_DAMAGE_DEALT,0.05,0.01|MOD_TRIGGER_CHANCES,0.05,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/gem_04.tres\",\"ND8H\",\"3GNK\"\r\n146,\"Toy Boy\",\"regular\",\"cedi\",\"rare\",1970,83,\"MOD_DAMAGE_ADD_PERC,0.5,0.01\",\"639\",,,\"res://src/items/item_behaviors/toy_boy.gd\",\"res://resources/icons/animals/piglet_warrior.tres\",\"EGWN\",\"WSNH\"\r\n147,\"Dull Gem\",\"regular\",\"Majildian\",\"common\",154,8,\"MOD_BOUNTY_RECEIVED,0.195,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/earring_03.tres\",\"FK8S\",\"VN8D\"\r\n148,\"Naga Trident\",\"regular\",\"poussix\",\"uncommon\",1364,79,\"MOD_ATTACKSPEED,-0.07,0|MOD_ATK_CRIT_CHANCE,0.08,0|MOD_ATK_CRIT_DAMAGE,0.8,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/trident_02.tres\",\"824L\",\"VMS1\"\r\n149,\"Jungle Stalker's Doll\",\"regular\",\"poussix\",\"unique\",500,12,\"MOD_ATK_CRIT_CHANCE,0.025,0.001\",\"640\",,,\"res://src/items/item_behaviors/jungle_stalkers_doll.gd\",\"res://resources/icons/misc/spiky_totem_02.tres\",\"T4EL\",\"7F04\"\r\n150,\"Panda Dress\",\"regular\",\"poussix\",\"uncommon\",1414,83,\"MOD_SPELL_DAMAGE_DEALT,0.1,0|MOD_TRIGGER_CHANCES,0.05,0.01|MOD_BUFF_DURATION,0.05,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_icons/polar_bear_cub.tres\",\"J40U\",\"96NN\"\r\n151,\"Wise Man's Cooking Recipe\",\"regular\",\"SternBogen\",\"uncommon\",285,13,\"MOD_ATTACKSPEED,-0.05,0\",\"641\",,,\"res://src/items/item_behaviors/wise_mans_cooking_recipe.gd\",\"res://resources/icons/books/note_04.tres\",\"7WCC\",\"HEXL\"\r\n152,\"Writer's Knowledge\",\"regular\",\"poussix\",\"rare\",250,7,\"MOD_DAMAGE_ADD_PERC,0,-0.008|MOD_EXP_RECEIVED,0.4,-0.008\",\"642\",,,\"res://src/items/item_behaviors/writers_knowledge.gd\",\"res://resources/icons/faces/man_02.tres\",\"HLAH\",\"5LFI\"\r\n153,\"Ring of Luck\",\"regular\",\"Majildian\",\"common\",151,8,\"MOD_TRIGGER_CHANCES,0.077,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rings/ring_05.tres\",\"SMCK\",\"BTWT\"\r\n154,\"Elite Sharp Shooter\",\"regular\",\"SternBogen\",\"rare\",1656,69,\"MOD_ATTACKSPEED,-0.35,0|MOD_ATK_CRIT_CHANCE,0.05,0|MOD_ATK_CRIT_DAMAGE,0.5,0|MOD_MULTICRIT_COUNT,2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/cannon_06.tres\",\"3N6Z\",\"TMMB\"\r\n155,\"Holy Axe\",\"regular\",\"Boekie\",\"common\",36,0,\"MOD_DMG_TO_UNDEAD,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/holy/axe.tres\",\"9RGG\",\"5GQL\"\r\n156,\"Sign of Energy Infusion\",\"regular\",\"cedi\",\"rare\",630,24,,\"643\",,,\"res://src/items/item_behaviors/sign_of_energy_infusion.gd\",\"res://resources/icons/furniture/furniture.tres\",\"8BIM\",\"T5DX\"\r\n157,\"Enchanted Bird Figurine\",\"regular\",\"drol\",\"common\",1092,83,\"MOD_TRIGGER_CHANCES,0.12,0|MOD_BUFF_DURATION,0.28,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_icons/harpy_witch.tres\",\"A2TC\",\"AEFB\"\r\n158,\"Mining Tools\",\"regular\",\"drol\",\"uncommon\",20,0,,\"644\",,,\"res://src/items/item_behaviors/mining_tools.gd\",\"res://resources/icons/misc/toolbox_02.tres\",\"16L5\",\"D8G7\"\r\n159,\"Charged Disk\",\"regular\",\"drol\",\"uncommon\",50,0,,\"645\",,,\"res://src/items/item_behaviors/charged_disk.gd\",\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"OFMW\",\"YN6K\"\r\n160,\"Young Thief's Cloak\",\"regular\",\"Majildian\",\"common\",156,8,\"MOD_ITEM_QUALITY_ON_KILL,0.105,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/armor/coat.tres\",\"XBFN\",\"6GFR\"\r\n161,\"Commander\",\"regular\",\"SternBogen\",\"rare\",612,23,,\"646\",,,\"res://src/items/item_behaviors/commander.gd\",\"res://resources/icons/misc/red_knight.tres\",\"L64Z\",\"PI3D\"\r\n162,\"Glaive of Supreme Follow Up\",\"regular\",\"cedi\",\"unique\",2100,63,,\"647\",,,\"res://src/items/item_behaviors/glaive_of_supreme_follow_up.gd\",\"res://resources/icons/weapons_misc/glaive_02.tres\",\"G572\",\"ZRYC\"\r\n163,\"Skull Trophy\",\"regular\",\"drol\",\"common\",147,7,\"MOD_DPS_ADD,100,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/undead/skull_01.tres\",\"JX75\",\"7PUH\"\r\n164,\"Tooth Trophy\",\"regular\",\"drol\",\"common\",623,45,\"MOD_DPS_ADD,450,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/trinkets/claw_01.tres\",\"UOIS\",\"T6VW\"\r\n165,\"Basics of Calculus\",\"regular\",\"drol\",\"rare\",425,14,,,,\"163\",\"res://src/items/item_behaviors/basics_of_calculus.gd\",\"res://resources/icons/scrolls/scroll_07.tres\",\"6PC0\",\"YSCI\"\r\n166,\"Wand of Mana Zap\",\"regular\",\"drol\",\"rare\",700,27,,\"648\",,,\"res://src/items/item_behaviors/wand_of_mana_zap.gd\",\"res://resources/icons/tower_icons/genis_sage.tres\",\"R1MB\",\"9D5R\"\r\n167,\"Never-ending Keg\",\"regular\",\"cedi\",\"rare\",1177,48,\"MOD_ATK_CRIT_DAMAGE,0.65,0|MOD_MULTICRIT_COUNT,1,0\",\"649\",,,\"res://src/items/item_behaviors/never-ending_keg.gd\",\"res://resources/icons/food/barrel.tres\",\"WCZ2\",\"RI1P\"\r\n168,\"Scarab Amulet\",\"regular\",\"drol\",\"common\",210,12,\"MOD_DAMAGE_ADD_PERC,0.12,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_variations/undisturbed_crypt_gold.tres\",\"T5PV\",\"NSCF\"\r\n169,\"Tree Branch\",\"regular\",\"Boekie\",\"common\",36,0,\"MOD_DMG_TO_ORC,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/plants/branch_01.tres\",\"2CCE\",\"33MV\"\r\n170,\"Crystallized Scales\",\"regular\",\"drol\",\"uncommon\",386,19,\"MOD_EXP_RECEIVED,0.24,0|MOD_BOUNTY_RECEIVED,0.18,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gems/stone_02.tres\",\"YI1H\",\"J1FS\"\r\n171,\"Eternium Blade\",\"regular\",\"Majildian\",\"rare\",2135,90,\"MOD_DPS_ADD,1250,50\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/swords/sword_03.tres\",\"2N2I\",\"X2F5\"\r\n172,\"Sacred Halo\",\"regular\",\"drol\",\"common\",1092,83,\"MOD_DMG_TO_UNDEAD,0.84,0|MOD_DEBUFF_DURATION,-0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/helmets/crown_02.tres\",\"MILV\",\"SS6J\"\r\n173,\"Railgun\",\"regular\",\"drol\",\"common\",1047,79,\"MOD_DMG_TO_HUMANOID,0.6,0|MOD_DAMAGE_ADD_PERC,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/cannon_05.tres\",\"IYDV\",\"GZSX\"\r\n174,\"Essence of Rot\",\"regular\",\"Majildian\",\"rare\",1300,53,,,\"96,97\",,\"res://src/items/item_behaviors/essence_of_rot.gd\",\"res://resources/icons/misc/poison_02.tres\",\"LIZF\",\"VQ5N\"\r\n175,\"Toxic Chemicals\",\"regular\",\"Majildian\",\"uncommon\",386,19,\"MOD_DMG_TO_NATURE,0.72,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/misc/poison_01.tres\",\"V523\",\"NV40\"\r\n176,\"Runed Wood\",\"regular\",\"drol\",\"common\",1042,79,\"MOD_SPELL_DAMAGE_DEALT,0.27,0|MOD_ITEM_QUALITY_ON_KILL,0.12,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/blunt_weapons/wood_01.tres\",\"BM8C\",\"P4OK\"\r\n177,\"Undead Claws\",\"regular\",\"Boekie\",\"common\",36,0,\"MOD_DMG_TO_NATURE,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/undead/skull_wand_01.tres\",\"V15N\",\"4QKI\"\r\n178,\"Dark Matter Trident\",\"regular\",\"cedi\",\"unique\",410,9,,\"650\",,,\"res://src/items/item_behaviors/dark_matter_trident.gd\",\"res://resources/icons/bows/bow_06.tres\",\"OLSP\",\"IZT0\"\r\n179,\"Ritual Talisman\",\"regular\",\"drol\",\"rare\",576,21,,,,\"164\",\"res://src/items/item_behaviors/ritual_talisman.gd\",\"res://resources/icons/undead/skull_doll.tres\",\"XF5V\",\"IBNX\"\r\n180,\"Libram of Grace\",\"regular\",\"drol\",\"rare\",250,7,,,\"98\",,\"res://src/items/item_behaviors/libram_of_grace.gd\",\"res://resources/icons/tower_icons/basic_knowledge.tres\",\"TK8Q\",\"ZCLT\"\r\n181,\"Bloodthirsty Wheel of Fortune\",\"regular\",\"Palandu\",\"rare\",540,20,,\"651\",,,\"res://src/items/item_behaviors/bloodthirsty_wheel_of_fortune.gd\",\"res://resources/icons/undead/demon_emblem.tres\",\"ZSY2\",\"TCFF\"\r\n182,\"Spider Broach\",\"regular\",\"drol\",\"uncommon\",1250,72,,\"652\",,,\"res://src/items/item_behaviors/spider_broach.gd\",\"res://resources/icons/animals/spider_02.tres\",\"3R1F\",\"5IXW\"\r\n183,\"Mighty Tree's Acorns\",\"regular\",\"poussix\",\"unique\",250,\"because we all love them\",\"MOD_DAMAGE_ADD_PERC,-0.2,0|MOD_SPELL_DAMAGE_DEALT,-0.2,0\",,\"99\",,\"res://src/items/item_behaviors/mighty_trees_acorns.gd\",\"res://resources/icons/dioramas/church.tres\",\"QEQR\",\"QKJ1\"\r\n184,\"Soul Collectors Cloak\",\"regular\",\"cedi\",\"unique\",1000,28,,\"653\",,,\"res://src/items/item_behaviors/soul_collectors_cloak.gd\",\"res://resources/icons/shields/shield_skull.tres\",\"S7YY\",\"Z0N4\"\r\n185,\"Sniper\",\"regular\",\"Boekie\",\"common\",36,0,\"MOD_DMG_TO_BOSS,0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/cannon_01.tres\",\"IDOX\",\"OPGJ\"\r\n186,\"Liquid Gold\",\"regular\",\"drol\",\"rare\",447,15,\"MOD_DAMAGE_ADD_PERC,0.35,0\",\"654\",,,\"res://src/items/item_behaviors/liquid_gold.gd\",\"res://resources/icons/food/beer_01.tres\",\"1TJZ\",\"KRXZ\"\r\n187,\"Ogre Staff of Wisdom\",\"regular\",\"Palandu\",\"uncommon\",99,2,\"MOD_DAMAGE_ADD_PERC,0.2,0.004|MOD_EXP_RECEIVED,-0.2,0|MOD_BOUNTY_RECEIVED,-0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/staff_01.tres\",\"7RUV\",\"ESO7\"\r\n188,\"Staff of the Wild Equus\",\"regular\",\"drol\",\"rare\",350,11,,\"655\",,,\"res://src/items/item_behaviors/staff_of_the_wild_equus.gd\",\"res://resources/icons/staves/staff_04.tres\",\"IRYI\",\"XQ4K\"\r\n189,\"Heavy Crossbow\",\"regular\",\"drol\",\"common\",680,50,\"MOD_ATTACKSPEED,0.1,0|MOD_DPS_ADD,215,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/bows/bow_04.tres\",\"TKNH\",\"TJY1\"\r\n190,\"Demonic Orb\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_SPELL_CRIT_DAMAGE,0.9,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/orbs/orb_molten.tres\",\"95HR\",\"JWCO\"\r\n191,\"Speed Demon's Reward\",\"regular\",\"Palandu\",\"uncommon\",144,4,,\"656\",,,\"res://src/items/item_behaviors/speed_demons_reward.gd\",\"res://resources/icons/shields/shield_with_emblem.tres\",\"80LH\",\"0BRJ\"\r\n192,\"Deep Shadows\",\"regular\",\"cedi\",\"uncommon\",300,14,,\"657\",,,\"res://src/items/item_behaviors/deep_shadows.gd\",\"res://resources/icons/fire/flame_purple.tres\",\"BD7M\",\"0BFA\"\r\n193,\"Staff of Essence\",\"regular\",\"cedi\",\"unique\",2200,66,,\"658\",,,\"res://src/items/item_behaviors/staff_of_essence.gd\",\"res://resources/icons/staves/staff_03.tres\",\"6CUZ\",\"4USF\"\r\n194,\"Bones of Essence\",\"regular\",\"cedi\",\"uncommon\",500,26,,\"659\",,,\"res://src/items/item_behaviors/bones_of_essence.gd\",\"res://resources/icons/undead/skull_wand_04.tres\",\"T750\",\"G74F\"\r\n195,\"Aqueous Vapor\",\"regular\",\"cedi\",\"uncommon\",300,14,,\"660\",,,\"res://src/items/item_behaviors/aqueous_vapor.gd\",\"res://resources/icons/potions/beaker_03.tres\",\"86N8\",\"E8Q5\"\r\n196,\"Glowing Gauntlets\",\"regular\",\"Majildian\",\"uncommon\",486,25,\"MOD_ATTACKSPEED,0.12,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/gloves/gloves_02.tres\",\"U7NN\",\"CS21\"\r\n197,\"Magnetic Field\",\"regular\",\"DaveMatthews\",\"rare\",1000,40,,,\"100\",,\"res://src/items/item_behaviors/magnetic_field.gd\",\"res://resources/icons/dioramas/fountain.tres\",\"VXY9\",\"5QBJ\"\r\n198,\"Frog Pipe\",\"regular\",\"Deemzul\",\"unique\",1650,48,,\"661\",,,\"res://src/items/item_behaviors/frog_pipe.gd\",\"res://resources/icons/misc/teapot_02.tres\",\"1SVJ\",\"1JMV\"\r\n199,\"Dowsing Rod\",\"regular\",\"YouJizzTD\",\"uncommon\",223,9,\"MOD_DAMAGE_ADD_PERC,-0.1,0|MOD_SPELL_DAMAGE_DEALT,-0.1,0|MOD_ITEM_CHANCE_ON_KILL,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/daggers/dagger_05.tres\",\"8ZTQ\",\"HKNV\"\r\n200,\"Spellbook of Item Mastery\",\"regular\",\"Majildian\",\"unique\",1500,44,,\"662\",,,\"res://src/items/item_behaviors/spellbook_of_item_mastery.gd\",\"res://resources/icons/books/book_07.tres\",\"Y3QD\",\"EX7P\"\r\n201,\"Even More Magical Hammer\",\"regular\",\"cedi\",\"unique\",1000,28,,\"663\",,,\"res://src/items/item_behaviors/even_more_magical_hammer.gd\",\"res://resources/icons/blunt_weapons/hammer_04.tres\",\"KJV4\",\"QFBY\"\r\n202,\"Optimist's Preserved Face\",\"regular\",\"cedi\",\"rare\",650,24,,\"664\",,,\"res://src/items/item_behaviors/optimists_preserved_face.gd\",\"res://resources/icons/undead/skull_04.tres\",\"Q2O3\",\"KMGP\"\r\n203,\"Sword of Reckoning\",\"regular\",\"drol\",\"rare\",400,13,,,\"101\",,\"res://src/items/item_behaviors/sword_of_reckoning.gd\",\"res://resources/icons/swords/greatsword_05.tres\",\"VWRS\",\"RH4M\"\r\n204,\"Sparkling Staff\",\"regular\",\"Majildian\",\"uncommon\",517,27,\"MOD_SPELL_DAMAGE_DEALT,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/wand_03.tres\",\"2YZ0\",\"TOO8\"\r\n205,\"Sword of Decay\",\"regular\",\"drol\",\"rare\",400,13,,,\"102\",,\"res://src/items/item_behaviors/sword_of_decay.gd\",\"res://resources/icons/swords/greatsword_03.tres\",\"H1YN\",\"1JWW\"\r\n206,\"Mindleecher\",\"regular\",\"Majildian\",\"rare\",750,29,,,,\"165\",\"res://src/items/item_behaviors/mindleecher.gd\",\"res://resources/icons/undead/skull_02.tres\",\"QM8H\",\"ZGSC\"\r\n207,\"M.E.F.I.S. Rocket\",\"regular\",\"cedi\",\"unique\",1500,44,,\"665\",,,\"res://src/items/item_behaviors/mefis_rocket.gd\",\"res://resources/icons/rockets/rocket_05.tres\",\"YRS9\",\"3I9A\"\r\n208,\"Fragmentation Round\",\"regular\",\"cedi\",\"unique\",2000,60,,\"666\",,,\"res://src/items/item_behaviors/fragmentation_round.gd\",\"res://resources/icons/misc/grenade.tres\",\"IE8U\",\r\n209,\"Grounding Gloves\",\"regular\",\"SirCoqaLot.\",\"unique\",1500,44,,\"667\",,,\"res://src/items/item_behaviors/grounding_gloves.gd\",\"res://resources/icons/tower_variations/vulshok_the_berserker_blue.tres\",\"U6X3\",\r\n210,\"Orb of Souls\",\"regular\",\"Sunken\",\"uncommon\",180,7,,\"668\",,,\"res://src/items/item_behaviors/orb_of_souls.gd\",\"res://resources/icons/orbs/orb_shadow.tres\",\"URN0\",\"QOAK\"\r\n211,\"Bloodthirsty Axe\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_ATK_CRIT_DAMAGE,0.75,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/furniture/wooden_stand_with_nail.tres\",\"W8DV\",\"OPYI\"\r\n212,\"Shining Rock\",\"regular\",\"Deemzul\",\"rare\",320,10,,\"669\",,,\"res://src/items/item_behaviors/shining_rock.gd\",\"res://resources/icons/gems/stone_04.tres\",\"AFSR\",\"3G4I\"\r\n213,\"Lich Mask\",\"regular\",\"cedi\",\"rare\",450,16,,\"670\",,,\"res://src/items/item_behaviors/lich_mask.gd\",\"res://resources/icons/helmets/helmet_07.tres\",\"VCER\",\"DBLK\"\r\n214,\"Brimstone Helmet\",\"regular\",\"cedi\",\"rare\",450,16,,\"671\",,,\"res://src/items/item_behaviors/brimstone_helmet.gd\",\"res://resources/icons/helmets/helmet_01.tres\",\"6X0N\",\"URD5\"\r\n215,\"Overcharge Shot\",\"regular\",\"cedi\",\"unique\",800,21,,\"672\",,,\"res://src/items/item_behaviors/overcharge_shot.gd\",\"res://resources/icons/rockets/rocket_06.tres\",\"Q11Q\",\"7Q1X\"\r\n216,\"Pendant of Mana Supremacy\",\"regular\",\"cedi\",\"unique\",1672,49,\"MOD_ATTACKSPEED,-0.38,0.01|MOD_MANA_REGEN_PERC,1,0.01\",\"673\",,,\"res://src/items/item_behaviors/pendant_of_mana_supremacy.gd\",\"res://resources/icons/amulets/amulet_04.tres\",\"D6BS\",\"8AYK\"\r\n217,\"Share Knowledge\",\"regular\",\"SternBogen\",\"rare\",350,11,,\"674\",,,\"res://src/items/item_behaviors/share_knowledge.gd\",\"res://resources/icons/mechanical/gold_machine.tres\",\"MVCO\",\"0PXV\"\r\n218,\"Blaster Staff\",\"regular\",\"cedi\",\"uncommon\",60,0,,\"675\",,,\"res://src/items/item_behaviors/blaster_staff.gd\",\"res://resources/icons/trinkets/trinket_10.tres\",\"YB9C\",\"DWE6\"\r\n219,\"Enchanted Telescope\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_ITEM_CHANCE_ON_KILL,0.18,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/cannons/cannon_02.tres\",\"G60E\",\"48KB\"\r\n222,\"Book of Knowledge\",\"regular\",\"Boekie\",\"rare\",500,18,,\"678\",,,\"res://src/items/item_behaviors/book_of_knowledge.gd\",\"res://resources/icons/books/book_05.tres\",\"ZKHH\",\"C60P\"\r\n223,\"Iron Leg\",\"regular\",\"drol\",\"uncommon\",125,3,\"MOD_ATK_CRIT_DAMAGE,0.1,0|MOD_ATTACKSPEED,0.01,0|MOD_ATK_CRIT_CHANCE,0.01,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/blunt_weapons/wood_03.tres\",\"VG7L\",\"R91C\"\r\n224,\"Master Thief's Shroud\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_ITEM_QUALITY_ON_KILL,0.24,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/tower_icons/shadow.tres\",\"ZHWH\",\"Q6U2\"\r\n225,\"Fiery Assassination Arrow\",\"regular\",\"drol\",\"uncommon\",136,4,\"MOD_DMG_TO_CHAMPION,0.2,0|MOD_DMG_TO_BOSS,0.2,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/bows/arrow_02.tres\",\"DI5V\",\"X1A9\"\r\n226,\"Unstable Current\",\"regular\",\"Finger of Destiny\",\"uncommon\",300,14,,\"679\",,,\"res://src/items/item_behaviors/unstable_current.gd\",\"res://resources/icons/electricity/electricity_blue.tres\",\"8MKA\",\"IWC4\"\r\n227,\"Lunar Essence\",\"regular\",\"Finger of Destiny\",\"unique\",650,16,,\"680\",,,\"res://src/items/item_behaviors/lunar_essence.gd\",\"res://resources/icons/gems/crystal.tres\",\"O3RW\",\"LP87\"\r\n228,\"Bloody Key\",\"regular\",\"Finger of Destiny\",\"rare\",1000,40,\"MOD_EXP_RECEIVED,-0.7,0|MOD_BOUNTY_RECEIVED,-0.7,0\",,\"103\",,\"res://src/items/item_behaviors/bloody_key.gd\",\"res://resources/icons/trinkets/key_03.tres\",\"4M3J\",\"1AYL\"\r\n229,\"Razor Sharp Dagger\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_ATK_CRIT_CHANCE,0.06,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/daggers/dagger_06.tres\",\"GC5M\",\"JPLK\"\r\n230,\"The Divine Wings of Tragedy\",\"regular\",\"SymphonyX, Finger of Destiny\",\"unique\",2739,83,\"MOD_BUFF_DURATION,0.37,0\",,\"104\",,\"res://src/items/item_behaviors/the_divine_wings_of_tragedy.gd\",\"res://resources/icons/animals/wing.tres\",\"9RGK\",\"ND7N\"\r\n231,\"Currency Converter\",\"regular\",\"Finger of Destiny\",\"rare\",0,0,,\"681\",,,\"res://src/items/item_behaviors/currency_converter.gd\",\"res://resources/icons/mechanical/black_gold_calculator.tres\",\"KU11\",\"8IZN\"\r\n232,\"Ring of Chance\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_TRIGGER_CHANCES,0.18,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rings/ring_08.tres\",\"ZI6Z\",\"7O56\"\r\n233,\"Strange Item\",\"regular\",\"Deemzul\",\"common\",256,16,,\"682\",,,\"res://src/items/item_behaviors/strange_item.gd\",\"res://resources/icons/magic/bowl_01.tres\",\"HRXD\",\"2S9U\"\r\n234,\"Elegant Ring\",\"regular\",\"ShyGnome\",\"common\",495,35,\"MOD_ITEM_CHANCE_ON_KILL,0.04,0|MOD_ITEM_QUALITY_ON_KILL,0.04,0|MOD_TRIGGER_CHANCES,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rings/ring_01.tres\",\"8G8S\",\"NTNA\"\r\n235,\"Hermit Staff\",\"regular\",\"ShyGnome\",\"uncommon\",873,49,\"MOD_MANA_REGEN_PERC,0.125,0|MOD_BUFF_DURATION,0.33,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/staves/staff_07.tres\",\"TB7D\",\"8ZOM\"\r\n236,\"Veteran's Tome of Battle\",\"regular\",\"Majildian\",\"uncommon\",540,29,\"MOD_EXP_RECEIVED,0.6,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/book_06.tres\",\"NU7R\",\"UESH\"\r\n237,\"Enchanted Gear\",\"regular\",\"Boekie\",\"rare\",1656,69,\"MOD_ATTACKSPEED,0.2,0|MOD_TRIGGER_CHANCES,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/mechanical/mech_badge.tres\",\"WKFJ\",\"WDT5\"\r\n238,\"Secret Tome of Magic\",\"regular\",\"hokkei\",\"rare\",790,31,\"MOD_SPELL_CRIT_CHANCE,-0.15,-0.01|MOD_SPELL_CRIT_DAMAGE,2,0.2\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/book_04.tres\",\"T30T\",\"5FQQ\"\r\n239,\"Secret Tome of Mana\",\"regular\",\"hokkei\",\"rare\",1788,75,\"MOD_MANA_PERC,2,0|MOD_MANA_REGEN_PERC,-1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/books/book_08.tres\",\"5VRD\",\"359S\"\r\n240,\"Mini Forest Troll\",\"regular\",\"cedi\",\"unique\",875,24,,\"683\",,,\"res://src/items/item_behaviors/mini_forest_troll.gd\",\"res://resources/icons/tower_variations/forest_troll_small.tres\",\"UVJW\",\"18W5\"\r\n241,\"Holy Hand Grenade\",\"regular\",\"cedi\",\"unique\",2300,69,,\"684\",,,\"res://src/items/item_behaviors/holy_hand_grenade.gd\",\"res://resources/icons/holy/orb.tres\",\"PMHJ\",\"WC81\"\r\n242,\"Old Hunter\",\"regular\",\"Guennter\",\"rare\",1000,40,,\"685\",,,\"res://src/items/item_behaviors/old_hunter.gd\",\"res://resources/icons/tower_icons/cold_troll.tres\",\"VYZD\",\"YMBC\"\r\n243,\"Monocle\",\"regular\",\"Guennter\",\"uncommon\",704,39,\"MOD_ATTACKSPEED,-0.075,-0.007|MOD_ITEM_CHANCE_ON_KILL,0.25,0|MOD_ITEM_QUALITY_ON_KILL,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rings/ring_02.tres\",\"RCY0\",\"Z1L9\"\r\n244,\"Arms Dealer\",\"regular\",\"limfa\",\"rare\",80,0,\"MOD_DAMAGE_ADD_PERC,-0.2,0|MOD_SPELL_DAMAGE_DEALT,-0.2,0|MOD_BOUNTY_RECEIVED,0.5,0\",\"686\",,,\"res://src/items/item_behaviors/arms_dealer.gd\",\"res://resources/icons/faces/man_03.tres\",\"J3F3\",\"4IB1\"\r\n245,\"Circle of Power\",\"regular\",\"Deemzul\",\"unique\",450,10,,\"687\",,,\"res://src/items/item_behaviors/circle_of_power.gd\",\"res://resources/icons/rings/ring_06.tres\",\"CCCU\",\"IS2B\"\r\n246,\"Haunted Hand\",\"regular\",\"Sunken\",\"rare\",342,11,\"MOD_ATTACKSPEED,0.08,0.002\",\"688\",,,\"res://src/items/item_behaviors/haunted_hand.gd\",\"res://resources/icons/undead/monster_hand.tres\",\"95GY\",\"HKNI\"\r\n247,\"Chameleons Soul\",\"regular\",\"Boekie\",\"rare\",1161,47,,\"689\",,,\"res://src/items/item_behaviors/chameleons_soul.gd\",\"res://resources/icons/plants/leaf_01.tres\",\"3OT8\",\"K5FV\"\r\n248,\"Pocket Emporium\",\"regular\",\"ShyGnome\",\"unique\",777,20,,,,\"166\",\"res://src/items/item_behaviors/pocket_emporium.gd\",\"res://resources/icons/mechanical/battery.tres\",\"37QN\",\r\n249,\"Golden Trident\",\"regular\",\"Boekie\",\"unique\",60,0,,\"690\",,,\"res://src/items/item_behaviors/golden_trident.gd\",\"res://resources/icons/weapons_misc/trident_01.tres\",\"PSIS\",\"MPS9\"\r\n250,\"Crit Blade\",\"regular\",\"Ranakastrasz\",\"unique\",644,16,\"MOD_ATK_CRIT_DAMAGE,0.8,0\",\"691\",,,\"res://src/items/item_behaviors/crit_blade.gd\",\"res://resources/icons/swords/sword_swing_01.tres\",\"7T7Z\",\"8HGR\"\r\n251,\"Arcane Script\",\"regular\",\"Finger of Destiny\",\"rare\",200,4,,\"692\",,,\"res://src/items/item_behaviors/arcane_script.gd\",\"res://resources/icons/books/book_10.tres\",\"WYO8\",\"8LRS\"\r\n252,\"Soul Collector's Scythe\",\"regular\",\"hokkei\",\"unique\",1000,28,,\"693\",,,\"res://src/items/item_behaviors/soul_collectors_scythe.gd\",\"res://resources/icons/misc/spiky_totem_01.tres\",\"2JAD\",\"3TVQ\"\r\n253,\"Doom's Ensign\",\"regular\",\"cedi\",\"unique\",1500,44,,\"694\",,,\"res://src/items/item_behaviors/dooms_ensign.gd\",\"res://resources/icons/orbs/orb_fire.tres\",\"HG04\",\"GM29\"\r\n254,\"Distorted Idol\",\"regular\",\"Deemzul\",\"unique\",2750,84,\"MOD_ATTACKSPEED,-0.6,0\",\"695,696\",,,\"res://src/items/item_behaviors/distorted_idol.gd\",\"res://resources/icons/undead/skull_phazing.tres\",\"614J\",\"JJP8\"\r\n255,\"Ball Lightning\",\"regular\",\"axllow\",\"rare\",718,27,\"MOD_ATTACKSPEED,1.5,0\",\"697\",,,\"res://src/items/item_behaviors/ball_lightning.gd\",\"res://resources/icons/electricity/lightning_circle_cyan.tres\",\"IURE\",\"YE1I\"\r\n256,\"Dragon Claws\",\"regular\",\"Boekie\",\"uncommon\",1244,72,\"MOD_DAMAGE_ADD_PERC,0.1,0.005|MOD_ATK_CRIT_CHANCE,0.05,0.001\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/animals/dragon_02.tres\",\"OXSH\",\"G1VB\"\r\n257,\"Shrapnel Ammunition\",\"regular\",\"cedi\",\"uncommon\",300,14,,\"698\",,,\"res://src/items/item_behaviors/shrapnel_ammunition.gd\",\"res://resources/icons/orbs/orb_green.tres\",\"ZE4C\",\"VY6C\"\r\n258,\"Spear of the Malphai\",\"regular\",\"Khlox-NL-\",\"rare\",1826,77,\"MOD_ATK_CRIT_DAMAGE,0.2,0.02|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/undead/skull_wand_02.tres\",\"9WNU\",\"PZCO\"\r\n259,\"Quicktrigger Blade\",\"regular\",\"Velex\",\"uncommon\",150,5,\"MOD_ATTACKSPEED,0.15,0|MOD_DAMAGE_ADD_PERC,-0.15,0|MOD_SPELL_DAMAGE_DEALT,-0.15,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/swords/greatsword_04.tres\",\"G4ZH\",\"30ID\"\r\n260,\"Crystalline Arrow\",\"regular\",\"Boekie\",\"rare\",540,20,\"MOD_DAMAGE_ADD_PERC,-0.15,0|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rockets/rocket_04.tres\",\"D9BC\",\"FH0S\"\r\n261,\"Vampiric Skull\",\"regular\",\"Boekie\",\"unique\",150,0,,\"699\",,,\"res://src/items/item_behaviors/vampiric_skull.gd\",\"res://resources/icons/undead/skull_03.tres\",\"UBX1\",\"EIMX\"\r\n262,\"Granite Hammer\",\"regular\",\"Boekie\",\"rare\",1000,40,,\"700\",,,\"res://src/items/item_behaviors/granite_hammer.gd\",\"res://resources/icons/blunt_weapons/hammer_02.tres\",\"V0NM\",\"PLQP\"\r\n263,\"Ogre Battle Axe\",\"regular\",\"Boekie\",\"uncommon\",749,42,\"MOD_DMG_TO_HUMANOID,0.25,0.01|MOD_ATK_CRIT_CHANCE,0.05,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/weapons_misc/axe_02.tres\",\"A7WY\",\"W29U\"\r\n264,\"Spear of Loki\",\"regular\",\"Boekie\",\"unique\",1470,43,\"MOD_DAMAGE_ADD_PERC,0.5,0.01\",\"701\",,,\"res://src/items/item_behaviors/spear_of_loki.gd\",\"res://resources/icons/spears/spear_03.tres\",\"OFDL\",\"69JS\"\r\n265,\"Magic Link\",\"regular\",\"MasterCassim\",\"uncommon\",500,26,,,,\"167\",\"res://src/items/item_behaviors/magic_link.gd\",\"res://resources/icons/magic/claw_01.tres\",\"IJ9M\",\"4Y3J\"\r\n266,\"Elunes Bow\",\"regular\",\"cedi\",\"unique\",1000,28,,\"702\",,,\"res://src/items/item_behaviors/elunes_bow.gd\",\"res://resources/icons/bows/bow_05.tres\",\"8SA6\",\"D13M\"\r\n267,\"Elunes Quiver\",\"regular\",\"cedi\",\"unique\",2410,73,\"MOD_ATTACKSPEED,0.5,0.01|MOD_DAMAGE_ADD_PERC,-0.1,0|MOD_ATK_CRIT_CHANCE,-0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/misc/quiver.tres\",\"65OA\",\"QT2D\"\r\n268,\"Soul Extractor\",\"regular\",\"Boekie\",\"unique\",50,0,,\"703\",,,\"res://src/items/item_behaviors/soul_extractor.gd\",\"res://resources/icons/shields/shield_bronze.tres\",\"98FM\",\"U2A2\"\r\n269,\"Stunner\",\"regular\",\"Boekie\",\"rare\",1000,40,,\"704\",,,\"res://src/items/item_behaviors/stunner.gd\",\"res://resources/icons/furniture/exploding_mirror.tres\",\"0WM8\",\"FIXE\"\r\n270,\"El Bastardo\",\"regular\",\"cedi\",\"rare\",1604,67,\"MOD_DMG_TO_BOSS,0.1,0.01|MOD_DMG_TO_UNDEAD,0.05,0.01|MOD_DMG_TO_ORC,0.15,0.02|MOD_DAMAGE_ADD_PERC,0.15,0.01\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/helmets/helmet_04.tres\",\"EBKT\",\"J7KW\"\r\n271,\"Magic Gloves\",\"regular\",\"Boekie\",\"common\",150,8,,\"705\",,,\"res://src/items/item_behaviors/magic_gloves.gd\",\"res://resources/icons/gloves/gloves_04.tres\",\"MHYK\",\"BIR7\"\r\n272,\"Scroll of Strength\",\"regular\",\"Boekie\",\"rare\",500,18,,,,\"168\",\"res://src/items/item_behaviors/scroll_of_strength.gd\",\"res://resources/icons/scrolls/scroll_05.tres\",\"SS4M\",\r\n273,\"Scroll of Speed\",\"regular\",\"Boekie\",\"rare\",500,18,,,,\"169\",\"res://src/items/item_behaviors/scroll_of_speed.gd\",\"res://resources/icons/scrolls/scroll_06.tres\",\"ZWDZ\",\r\n274,\"Portable Tombstone\",\"regular\",\"Boekie\",\"unique\",50,0,,\"706\",,,\"res://src/items/item_behaviors/portable_tombstone.gd\",\"res://resources/icons/holy/tombstone.tres\",\"42F3\",\"H9BE\"\r\n275,\"Workbench\",\"regular\",\"Boekie\",\"unique\",300,5,,\"707\",,,\"res://src/items/item_behaviors/workbench.gd\",\"res://resources/icons/furniture/chest.tres\",\"9R87\",\"DS1D\"\r\n276,\"Phase Gloves\",\"regular\",\"Boekie\",\"rare\",550,20,,\"708\",,,\"res://src/items/item_behaviors/phase_gloves.gd\",\"res://resources/icons/gloves/gloves_08.tres\",\"J7VY\",\"GFOQ\"\r\n277,\"Assassination Arrow\",\"regular\",\"drol\",\"common\",133,6,\"MOD_DMG_TO_CHAMPION,0.1,0.004|MOD_DMG_TO_BOSS,0.1,0.004|MOD_ATK_CRIT_DAMAGE,0.05,0.002\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/bows/arrow_01.tres\",\"ZADA\",\"7T8V\"\r\n278,\"Amulet of Strength\",\"regular\",\"LordHellHunter\",\"rare\",2094,89,\"MOD_DPS_ADD,400,25|MOD_ATK_CRIT_CHANCE,0.112,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/amulets/amulet_01.tres\",\"2NV8\",\"6LWV\"\r\n279,\"Magic Conductor\",\"regular\",\"Boekie\",\"unique\",300,5,,\"709\",,,\"res://src/items/item_behaviors/magic_conductor.gd\",\"res://resources/icons/mechanical/alchemy_kit_03.tres\",\"RNNG\",\"LJJN\"\r\n280,\"Unyielding Maul\",\"regular\",\"drol\",\"uncommon\",437,22,\"MOD_DAMAGE_ADD_PERC,0.25,0\",\"710\",,,\"res://src/items/item_behaviors/unyielding_maul.gd\",\"res://resources/icons/clubs/club_02.tres\",\"EJI6\",\"ATS1\"\r\n281,\"Faithful Staff\",\"regular\",\"Boekie\",\"unique\",400,8,,\"711\",,,\"res://src/items/item_behaviors/faithful_staff.gd\",\"res://resources/icons/staves/wand_01.tres\",\"VPQB\",\"97FF\"\r\n282,\"Lucky Gem\",\"regular\",\"Boekie\",\"unique\",550,13,,\"712\",,,\"res://src/items/item_behaviors/lucky_gem.gd\",\"res://resources/icons/gems/gem_01.tres\",\"88AR\",\"FIHU\"\r\n283,\"Shackles of Time\",\"regular\",\"drol\",\"rare\",1340,55,\"MOD_TRIGGER_CHANCES,0.33,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/rings/ring_04.tres\",\"DUWT\",\"UEBK\"\r\n284,\"Chameleon Glaive\",\"regular\",\"Boekie\",\"unique\",1100,31,,\"713\",,,\"res://src/items/item_behaviors/chameleon_glaive.gd\",\"res://resources/icons/weapons_misc/glaive_03.tres\",\"YEQ3\",\"5W9U\"\r\n285,\"Helm of Insanity\",\"regular\",\"Boekie\",\"unique\",500,12,,,,\"170\",\"res://src/items/item_behaviors/helm_of_insanity.gd\",\"res://resources/icons/faces/green_demon.tres\",\"DQG9\",\"K7JG\"\r\n1001,\"Oil of Sharpness\",\"oil\",\"gEx\",\"common\",100,0,\"MOD_DAMAGE_BASE_PERC,0.04,0.0016\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_green_01.tres\",\"JL89\",\r\n1002,\"Arcane Oil of Sharpness\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_DAMAGE_BASE_PERC,0.08,0.0032\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_green_02.tres\",\"VL40\",\r\n1003,\"Divine Oil of Sharpness\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_DAMAGE_BASE_PERC,0.2,0.008\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_green_03.tres\",\"QWUR\",\r\n1004,\"Oil of Magic\",\"oil\",\"gEx\",\"common\",100,0,\"MOD_MANA_PERC,0.08,0|MOD_MANA_REGEN_PERC,0.08,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_blue_01.tres\",\"0HN9\",\r\n1005,\"Arcane Oil of Magic\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_MANA_PERC,0.16,0|MOD_MANA_REGEN_PERC,0.16,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_blue_02.tres\",\"QH4H\",\r\n1006,\"Divine Oil of Magic\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_MANA_PERC,0.4,0|MOD_MANA_REGEN_PERC,0.4,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_blue_03.tres\",\"XSML\",\r\n1007,\"Oil of Accuracy\",\"oil\",\"gEx\",\"common\",100,0,\"MOD_ATK_CRIT_CHANCE,0.008,0|MOD_ATK_CRIT_DAMAGE,0.05,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_red_01.tres\",\"34E8\",\r\n1008,\"Arcane Oil of Accuracy\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_ATK_CRIT_CHANCE,0.016,0|MOD_ATK_CRIT_DAMAGE,0.1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_red_02.tres\",\"MBSA\",\r\n1009,\"Divine Oil of Accuracy\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_ATK_CRIT_CHANCE,0.04,0|MOD_ATK_CRIT_DAMAGE,0.25,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_red_03.tres\",\"1GLM\",\r\n1010,\"Oil of Swiftness\",\"oil\",\"gEx\",\"common\",100,0,\"MOD_ATTACKSPEED,0.02,0.0008\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_orange_01.tres\",\"V4QJ\",\r\n1011,\"Arcane Oil of Swiftness\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_ATTACKSPEED,0.04,0.0016\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_orange_02.tres\",\"XP51\",\r\n1012,\"Divine Oil of Swiftness\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_ATTACKSPEED,0.1,0.004\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_orange_03.tres\",\"B7Y7\",\r\n1013,\"Oil of Sorcery\",\"oil\",\"gEx\",\"common\",100,0,\"MOD_SPELL_DAMAGE_DEALT,0.04,0|MOD_SPELL_CRIT_CHANCE,0.01,0|MOD_SPELL_CRIT_DAMAGE,0.08,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_purple_01.tres\",\"W4YX\",\r\n1014,\"Arcane Oil of Sorcery\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_SPELL_DAMAGE_DEALT,0.08,0|MOD_SPELL_CRIT_CHANCE,0.02,0|MOD_SPELL_CRIT_DAMAGE,0.16,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_purple_02.tres\",\"RHCB\",\r\n1015,\"Divine Oil of Sorcery\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_SPELL_DAMAGE_DEALT,0.2,0|MOD_SPELL_CRIT_CHANCE,0.05,0|MOD_SPELL_CRIT_DAMAGE,0.4,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_purple_03.tres\",\"2XYY\",\r\n1016,\"Oil of Exuberance\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_BOUNTY_RECEIVED,0.16,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_yellow_01.tres\",\"3LPG\",\r\n1017,\"Arcane Oil of Exuberance\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_BOUNTY_RECEIVED,0.4,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_yellow_02.tres\",\"X3DG\",\r\n1018,\"Seeker's Oil\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_ITEM_CHANCE_ON_KILL,0.02,0.0008|MOD_ITEM_QUALITY_ON_KILL,0.02,0.0008\",\"714\",,,\"res://src/items/item_behaviors/seekers_oil.gd\",\"res://resources/icons/potions/potion_cyan_02.tres\",\"TV6H\",\r\n1019,\"Seeker's Arcane Oil\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_ITEM_CHANCE_ON_KILL,0.05,0.002|MOD_ITEM_QUALITY_ON_KILL,0.05,0.002\",\"715\",,,\"res://src/items/item_behaviors/seekers_arcane_oil.gd\",\"res://resources/icons/potions/potion_cyan_03.tres\",\"DQ2F\",\r\n1020,\"Oil of Lore\",\"oil\",\"gEx\",\"uncommon\",100,0,\"MOD_EXP_RECEIVED,0.28,0\",\"716\",,,\"res://src/items/item_behaviors/oil_of_lore.gd\",\"res://resources/icons/potions/potion_blue_04.tres\",\"AE1O\",\r\n1021,\"Arcane Oil of Lore\",\"oil\",\"gEx\",\"rare\",100,0,\"MOD_EXP_RECEIVED,0.7,0\",\"717\",,,\"res://src/items/item_behaviors/arcane_oil_of_lore.gd\",\"res://resources/icons/potions/potion_blue_05.tres\",\"Z150\",\r\n1022,\"Tears of the Gods\",\"oil\",\"gEx\",\"unique\",100,0,\"MOD_DAMAGE_BASE_PERC,0.15,0|MOD_ATK_CRIT_CHANCE,0.05,0|MOD_ATK_CRIT_DAMAGE,0.35,0|MOD_DAMAGE_ADD_PERC,0.15,0|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_07.tres\",\"X1S0\",\r\n1023,\"Pure Aether\",\"oil\",\"gEx\",\"unique\",100,0,\"MOD_TRIGGER_CHANCES,0.12,0|MOD_BUFF_DURATION,0.12,0|MOD_DEBUFF_DURATION,-0.12,0|MOD_BOUNTY_RECEIVED,0.12,0|MOD_EXP_RECEIVED,0.12,0|MOD_ITEM_CHANCE_ON_KILL,0.12,0|MOD_ITEM_QUALITY_ON_KILL,0.12,0|MOD_ATTACKSPEED,0.12,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_01.tres\",\"9EMV\",\r\n1024,\"Wizard's Soul\",\"oil\",\"gEx\",\"unique\",100,0,\"MOD_SPELL_DAMAGE_DEALT,0.3,0|MOD_SPELL_CRIT_CHANCE,0.06,0|MOD_SPELL_CRIT_DAMAGE,0.5,0|MOD_MANA_PERC,0.5,0|MOD_MANA_REGEN_PERC,0.5,0\",,,,\"res://src/items/item_behaviors/empty_item_behavior.gd\",\"res://resources/icons/potions/potion_03.tres\",\"FQRR\",\r\n2001,\"Book of Force\",\"consumable\",\"gEx\",\"common\",100,0,,,,,\"res://src/items/item_behaviors/book_of_force.gd\",\"res://resources/icons/books/book_01.tres\",\"3EMV\",\"O6T3\"\r\n2002,\"Consumable Plant\",\"consumable\",\"gEx\",\"common\",100,0,,,,,\"res://src/items/item_behaviors/consumable_plant.gd\",\"res://resources/icons/plants/plant_in_pot.tres\",\"OLLU\",\"MSH4\"\r\n2003,\"Consumable Chicken\",\"consumable\",\"gEx\",\"uncommon\",100,0,,,,,\"res://src/items/item_behaviors/consumable_chicken.gd\",\"res://resources/icons/food/poultry.tres\",\"4ENT\",\"6MPA\"\r\n2004,\"Mine Cart\",\"consumable\",\"gEx\",\"rare\",100,0,,,,,\"res://src/items/item_behaviors/mine_cart.gd\",\"res://resources/icons/misc/gold_cart.tres\",\"O5EL\",\"I37A\"\r\n2005,\"Consumable Piggy\",\"consumable\",\"gEx\",\"rare\",100,0,,,,,\"res://src/items/item_behaviors/consumable_piggy.gd\",\"res://resources/icons/food/pork.tres\",\"2Q9S\",\"SCB1\"\r\n2006,\"Arcane Book of Power\",\"consumable\",\"gEx\",\"uncommon\",100,0,,,,,\"res://src/items/item_behaviors/arcane_book_of_power.gd\",\"res://resources/icons/books/book_02.tres\",\"D3ES\",\"5I9R\"\r\n2007,\"Divine Book of Omnipotence\",\"consumable\",\"gEx\",\"rare\",100,0,,,,,\"res://src/items/item_behaviors/divine_book_of_omnipotence.gd\",\"res://resources/icons/books/book_03.tres\",\"8FSC\",\"OB4I\"\r\n2008,\"Consumable Hobbit\",\"consumable\",\"gEx\",\"unique\",100,0,,,,,\"res://src/items/item_behaviors/consumable_hobbit.gd\",\"res://resources/icons/potions/potion_06.tres\",\"U47Z\",\"KJ25\"\r\n"
  },
  {
    "path": "data/item_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/mission_properties.csv",
    "content": "\"id\",\"section\",\"description\",\"script path\",\"wave count\",\"game mode\",\"difficulty\",\"builder\"\n100,\"general\",\"XUWP\",\"res://src/missions/instances/mission_empty.gd\",120,\"random_with_upgrades\",\"medium\",\"any\"\n101,\"general\",\"4WOG\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n102,\"general\",\"TM8M\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"hard\",\"any\"\n103,\"general\",\"B871\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"extreme\",\"any\"\n104,\"general\",\"D51V\",\"res://src/missions/instances/mission_empty.gd\",240,\"totally_random\",\"medium\",\"any\"\n105,\"general\",\"30BZ\",\"res://src/missions/instances/mission_empty.gd\",240,\"totally_random\",\"hard\",\"any\"\n106,\"general\",\"76II\",\"res://src/missions/instances/mission_empty.gd\",240,\"totally_random\",\"extreme\",\"any\"\n200,\"elements\",\"PWDK\",\"res://src/missions/instances/mission_only_ice_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n201,\"elements\",\"HHAJ\",\"res://src/missions/instances/mission_only_nature_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n202,\"elements\",\"OHUL\",\"res://src/missions/instances/mission_only_fire_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n203,\"elements\",\"K9GS\",\"res://src/missions/instances/mission_only_darkness_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n204,\"elements\",\"EOCH\",\"res://src/missions/instances/mission_only_astral_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n205,\"elements\",\"3JOH\",\"res://src/missions/instances/mission_only_iron_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n206,\"elements\",\"RH3R\",\"res://src/missions/instances/mission_only_storm_towers.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n300,\"builders\",\"J1G1\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"blademaster\"\n301,\"builders\",\"OTQW\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"queen\"\n302,\"builders\",\"JTD8\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"adventurer\"\n303,\"builders\",\"0RUH\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"iron_maiden\"\n304,\"builders\",\"6SS8\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"farseer\"\n305,\"builders\",\"ARZG\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"elementalist\"\n306,\"builders\",\"DV3W\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"veteran_pilot\"\n307,\"builders\",\"ELN9\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"royal_assassin\"\n308,\"builders\",\"JEG4\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"benevolent_witch\"\n309,\"builders\",\"F1Y9\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"spirit_warden\"\n310,\"builders\",\"01T8\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"master\"\n311,\"builders\",\"YRYD\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"fender\"\n312,\"builders\",\"1L5C\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"realist\"\n313,\"builders\",\"9FU9\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"arch_sorceress\"\n314,\"builders\",\"V71D\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"barbarian\"\n315,\"builders\",\"UXZZ\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"panda\"\n316,\"builders\",\"M7NA\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"naga\"\n317,\"builders\",\"SPN1\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"goblin\"\n318,\"builders\",\"4APE\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"backpacker\"\n319,\"builders\",\"XLC7\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"maverick\"\n320,\"builders\",\"MB8J\",\"res://src/missions/instances/mission_empty.gd\",240,\"random_with_upgrades\",\"medium\",\"antagonizer\"\n400,\"special\",\"JQOZ\",\"res://src/missions/instances/mission_no_oils.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n401,\"special\",\"YDVL\",\"res://src/missions/instances/mission_no_items.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n402,\"special\",\"KAB9\",\"res://src/missions/instances/mission_35_food_or_less.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n403,\"special\",\"2HCW\",\"res://src/missions/instances/mission_only_common_uncommon.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n404,\"special\",\"OPCQ\",\"res://src/missions/instances/mission_120_in_60min.gd\",120,\"random_with_upgrades\",\"medium\",\"any\"\n405,\"special\",\"GM13\",\"res://src/missions/instances/mission_240_in_120min.gd\",240,\"random_with_upgrades\",\"medium\",\"any\"\n"
  },
  {
    "path": "data/mission_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/player_exp_for_level.csv",
    "content": "\"level\",\"exp\"\n0,0\n1,12\n2,24\n3,37\n4,51\n5,66\n6,82\n7,99\n8,117\n9,136\n10,156\n11,177\n12,199\n13,222\n14,246\n15,271\n16,297\n17,324\n18,352\n19,381\n20,411\n21,442\n22,474\n23,507\n24,541\n25,576\n26,612\n27,649\n28,687\n29,726\n30,766\n31,807\n32,849\n33,892\n34,936\n35,981\n36,1027\n37,1074\n38,1122\n39,1171\n40,1221\n41,1272\n42,1324\n43,1377\n44,1431\n45,1486\n46,1542\n47,1599\n48,1657\n49,1716\n50,1776\n51,1837\n52,1899\n53,1962\n54,2026\n55,2091\n56,2157\n57,2224\n58,2292\n59,2361\n60,2431\n61,2502\n62,2574\n63,2647\n64,2721\n65,2796\n66,2872\n67,2949\n68,3027\n69,3106\n70,3186\n71,3267\n72,3349\n73,3432\n74,3516\n75,3601\n76,3687\n77,3774\n78,3862\n79,3951\n80,4041\n81,4132\n82,4224\n83,4317\n84,4411\n85,4506\n86,4602\n87,4699\n88,4797\n89,4896\n90,4996\n91,5097\n92,5199\n93,5302\n94,5406\n95,5511\n96,5617\n97,5724\n98,5832\n99,5941\n100,6051\n101,6162\n102,6274\n103,6387\n104,6501\n105,6616\n106,6732\n107,6849\n108,6967\n109,7086\n110,7206\n111,7327\n112,7449\n113,7572\n114,7696\n115,7821\n116,7947\n117,8074\n118,8202\n119,8331\n120,8461\n121,8592\n122,8724\n123,8857\n124,8991\n125,9126\n126,9262\n127,9399\n128,9537\n129,9676\n130,9816\n131,9957\n132,10099\n133,10242\n134,10386\n135,10531\n136,10677\n137,10824\n138,10972\n139,11121\n140,11271\n141,11422\n142,11574\n143,11727\n144,11881\n145,12036\n146,12192\n147,12349\n148,12507\n149,12666\n150,12826\n151,12987\n152,13149\n153,13312\n154,13476\n155,13641\n156,13807\n157,13974\n158,14142\n159,14311\n160,14481\n161,14652\n162,14824\n163,14997\n164,15171\n165,15346\n166,15522\n167,15699\n168,15877\n169,16056\n170,16236\n171,16417\n172,16599\n173,16782\n174,16966\n175,17151\n176,17337\n177,17524\n178,17712\n179,17901\n180,18091\n181,18282\n182,18474\n183,18667\n184,18861\n185,19056\n186,19252\n187,19449\n188,19647\n189,19846\n190,20046\n191,20247\n192,20449\n193,20652\n194,20856\n195,21061\n196,21267\n197,21474\n198,21682\n199,21891\n200,22101\n201,22312\n202,22524\n203,22737\n204,22951\n205,23166\n206,23382\n207,23599\n208,23817\n209,24036\n210,24256\n211,24477\n212,24699\n213,24922\n214,25146\n215,25371\n216,25597\n217,25824\n218,26052\n219,26281\n220,26511\n221,26742\n222,26974\n223,27207\n224,27441\n225,27676\n226,27912\n227,28149\n228,28387\n229,28626\n230,28866\n231,29107\n232,29349\n233,29592\n234,29836\n235,30081\n236,30327\n237,30574\n238,30822\n239,31071\n240,31321\n241,31572\n242,31824\n243,32077\n244,32331\n245,32586\n246,32842\n247,33099\n248,33357\n249,33616\n250,33876\n251,34137\n252,34399\n253,34662\n254,34926\n255,35191\n256,35457\n257,35724\n258,35992\n259,36261\n260,36531\n261,36802\n262,37074\n263,37347\n264,37621\n265,37896\n266,38172\n267,38449\n268,38727\n269,39006\n270,39286\n271,39567\n272,39849\n273,40132\n274,40416\n275,40701\n276,40987\n277,41274\n278,41562\n279,41851\n280,42141\n281,42432\n282,42724\n283,43017\n284,43311\n285,43606\n286,43902\n287,44199\n288,44497\n289,44796\n290,45096\n291,45397\n292,45699\n293,46002\n294,46306\n295,46611\n296,46917\n297,47224\n298,47532\n299,47841\n300,48151"
  },
  {
    "path": "data/player_exp_for_level.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/recipe_properties.csv",
    "content": "\"id\",\"name english\",\"permanent count\",\"usable count\",\"result item type\",\"result count\",\"rarity change\",\"lvl bonus min\",\"lvl bonus max\",\"unlocked by backpacker\",\"display name\",\"description\"\n0,\"None\",0,0,\"none\",0,0,0,0,\"FALSE\",,\n1,\"Rebrew\",0,2,\"usable\",1,0,0,0,\"FALSE\",\"RNFP\",\"1OLM\"\n2,\"Distill\",0,4,\"usable\",1,1,0,0,\"FALSE\",\"XZN3\",\"AZIV\"\n3,\"Reassemble\",3,0,\"permanent\",1,0,5,25,\"FALSE\",\"J9AZ\",\"EBKR\"\n4,\"Perfect\",5,0,\"permanent\",1,1,0,20,\"FALSE\",\"F6QZ\",\"BO7O\"\n5,\"Liquefy\",2,0,\"usable\",3,-2,0,0,\"TRUE\",\"RRCT\",\"1MT9\"\n6,\"Precipitate\",0,6,\"permanent\",1,2,0,0,\"TRUE\",\"3PF7\",\"GS1P\"\n7,\"Imbue\",1,4,\"permanent\",1,1,15,30,\"TRUE\",\"UH5C\",\"YCKO\"\n"
  },
  {
    "path": "data/recipe_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/tower_properties.csv",
    "content": "\"name english\",\"tier\",\"id\",\"family id\",\"author\",\"rarity\",\"element\",\"attack enabled\",\"attack type\",\"attack range\",\"attack cd\",\"dmg min\",\"dmg max\",\"mana\",\"mana regen\",\"cost\",\"missile speed\",\"missile arc\",\"missile uses lightning visual\",\"attack_target_type\",\"multishot\",\"splash attack\",\"bounce attack\",\"specials\",\"ability list\",\"aura list\",\"autocast list\",\"script path\",\"icon path\",\"sprite path\",\"name\",\"description\"\r\n\"Tiny Shrub\",1,1,1,\"gex\",\"common\",\"nature\",\"TRUE\",\"physical\",800,0.9,26,26,0,0,30,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0075,0.002|MOD_ATK_CRIT_DAMAGE,0,0\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tiny_shrub.tres\",\"res://src/towers/tower_sprites/tiny_shrub_1.tscn\",\"32LD\",\"OKJ6\"\r\n\"Shrub\",2,439,1,\"gex\",\"common\",\"nature\",\"TRUE\",\"physical\",840,0.9,113,113,0,0,140,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0275,0.003|MOD_ATK_CRIT_DAMAGE,0.15,0.03\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tiny_shrub.tres\",\"res://src/towers/tower_sprites/tiny_shrub_2.tscn\",\"ZNJU\",\"XNNL\"\r\n\"Greater Shrub\",3,459,1,\"gex\",\"common\",\"nature\",\"TRUE\",\"physical\",880,0.9,299,299,0,0,400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0375,0.004|MOD_ATK_CRIT_DAMAGE,0.25,0.04\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tiny_shrub.tres\",\"res://src/towers/tower_sprites/tiny_shrub_3.tscn\",\"WHCM\",\"XNNL\"\r\n\"Shrubfield\",4,511,1,\"gex\",\"common\",\"nature\",\"TRUE\",\"physical\",920,0.9,552,552,0,0,800,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0575,0.005|MOD_ATK_CRIT_DAMAGE,0.45,0.05\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tiny_shrub.tres\",\"res://src/towers/tower_sprites/tiny_shrub_4.tscn\",\"B5OL\",\"XNNL\"\r\n\"Greater Shrubfield\",5,542,1,\"gex\",\"common\",\"nature\",\"TRUE\",\"physical\",960,0.9,901,901,0,0,1400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0675,0.006|MOD_ATK_CRIT_DAMAGE,0.55,0.06\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tiny_shrub.tres\",\"res://src/towers/tower_sprites/tiny_shrub_5.tscn\",\"R8S7\",\"XNNL\"\r\n\"Xtreme Shrubfield\",6,565,1,\"gex\",\"common\",\"nature\",\"TRUE\",\"physical\",1000,0.9,1360,1360,0,0,2300,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0875,0.007|MOD_ATK_CRIT_DAMAGE,0.75,0.07\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tiny_shrub.tres\",\"res://src/towers/tower_sprites/tiny_shrub_6.tscn\",\"5EHW\",\"XNNL\"\r\n\"Mana-Touched Drake\",1,3,3,\"SirCoqalot.\",\"rare\",\"astral\",\"TRUE\",\"elemental\",950,3,509,609,250,12.5,500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,1\",\"1\",\"1\",,\"res://src/towers/tower_behaviors/mana-touched_drake.gd\",\"res://resources/icons/tower_icons/mana-touched_drake.tres\",\"res://src/towers/tower_sprites/mana-touched_drake_1.tscn\",\"4DYK\",\"AZCJ\"\r\n\"Mana-Bound Drake\",2,369,3,\"SirCoqalot.\",\"rare\",\"astral\",\"TRUE\",\"elemental\",950,3,1207,1307,600,30,1200,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,2.4\",\"2\",\"2\",,\"res://src/towers/tower_behaviors/mana-touched_drake.gd\",\"res://resources/icons/tower_icons/mana-touched_drake.tres\",\"res://src/towers/tower_sprites/mana-touched_drake_2.tscn\",\"RAY7\",\"AZCJ\"\r\n\"Mana-Infused Drake\",3,370,3,\"SirCoqalot.\",\"rare\",\"astral\",\"TRUE\",\"elemental\",950,3,2003,2103,1050,52.5,2100,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,4.2\",\"3\",\"3\",,\"res://src/towers/tower_behaviors/mana-touched_drake.gd\",\"res://resources/icons/tower_icons/mana-touched_drake.tres\",\"res://src/towers/tower_sprites/mana-touched_drake_3.tscn\",\"TG85\",\"AZCJ\"\r\n\"Mana-Overwhelmed Drake\",4,371,3,\"SirCoqalot.\",\"rare\",\"astral\",\"TRUE\",\"elemental\",950,3,2855,2955,1600,80,3200,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,6.4\",\"4\",\"4\",,\"res://src/towers/tower_behaviors/mana-touched_drake.gd\",\"res://resources/icons/tower_icons/mana-touched_drake.tres\",\"res://src/towers/tower_sprites/mana-touched_drake_4.tscn\",\"NHHR\",\"AZCJ\"\r\n\"Necromantic Altar\",1,4,4,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"energy\",875,1.6,287,287,30,2,300,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,,\"1\",\"res://src/towers/tower_behaviors/necromantic_altar.gd\",\"res://resources/icons/tower_icons/necromantic_altar.tres\",\"res://src/towers/tower_sprites/necromantic_altar_1.tscn\",\"EERU\",\"WJ30\"\r\n\"Necromantic Statue\",2,6,4,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"energy\",875,1.6,573,573,30,2,600,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,,\"2\",\"res://src/towers/tower_behaviors/necromantic_altar.gd\",\"res://resources/icons/tower_icons/necromantic_altar.tres\",\"res://src/towers/tower_sprites/necromantic_altar_2.tscn\",\"BGNU\",\"WJ30\"\r\n\"Necromantic Shrine\",3,7,4,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"energy\",875,1.6,1146,1146,30,2,1200,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,,\"3\",\"res://src/towers/tower_behaviors/necromantic_altar.gd\",\"res://resources/icons/tower_icons/necromantic_altar.tres\",\"res://src/towers/tower_sprites/necromantic_altar_3.tscn\",\"RRFV\",\"WJ30\"\r\n\"Necromantic Monument\",4,8,4,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"energy\",875,1.6,2484,2484,30,2,2600,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,,\"4\",\"res://src/towers/tower_behaviors/necromantic_altar.gd\",\"res://resources/icons/tower_icons/necromantic_altar.tres\",\"res://src/towers/tower_sprites/necromantic_altar_4.tscn\",\"6L5A\",\"WJ30\"\r\n\"Lunar Sentinel\",1,5,5,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",1200,2,17,37,0,0,60,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"5\",\"res://src/towers/tower_behaviors/lunar_sentinel.gd\",\"res://resources/icons/tower_icons/lunar_sentinel.tres\",\"res://src/towers/tower_sprites/lunar_sentinel_1.tscn\",\"1HIQ\",\"QFCJ\"\r\n\"Lunar Guardian\",2,49,5,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",1200,2,262,282,0,0,600,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"6\",\"res://src/towers/tower_behaviors/lunar_sentinel.gd\",\"res://resources/icons/tower_icons/lunar_sentinel.tres\",\"res://src/towers/tower_sprites/lunar_sentinel_2.tscn\",\"4BHR\",\"QFCJ\"\r\n\"Lunar Protector\",3,50,5,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",1200,2,806,826,0,0,1800,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"7\",\"res://src/towers/tower_behaviors/lunar_sentinel.gd\",\"res://resources/icons/tower_icons/lunar_sentinel.tres\",\"res://src/towers/tower_sprites/lunar_sentinel_3.tscn\",\"MGNM\",\"QFCJ\"\r\n\"Lunar Defender\",4,51,5,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",1200,2,1350,1370,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"8\",\"res://src/towers/tower_behaviors/lunar_sentinel.gd\",\"res://resources/icons/tower_icons/lunar_sentinel.tres\",\"res://src/towers/tower_sprites/lunar_sentinel_4.tscn\",\"RSA5\",\"QFCJ\"\r\n\"Minor Magic Ruin\",1,11,11,\"drol\",\"common\",\"astral\",\"TRUE\",\"elemental\",700,1,47,51,0,0,45,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"5\",,,\"res://src/towers/tower_behaviors/minor_magic_ruin.gd\",\"res://resources/icons/tower_icons/minor_magic_ruin.tres\",\"res://src/towers/tower_sprites/minor_magic_ruin_1.tscn\",\"VNJ0\",\"KLME\"\r\n\"Small Magic Ruin\",2,12,11,\"drol\",\"common\",\"astral\",\"TRUE\",\"elemental\",700,1,151,165,0,0,150,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"6\",,,\"res://src/towers/tower_behaviors/minor_magic_ruin.gd\",\"res://resources/icons/tower_icons/minor_magic_ruin.tres\",\"res://src/towers/tower_sprites/minor_magic_ruin_2.tscn\",\"RGAP\",\"KLME\"\r\n\"Magic Ruin\",3,13,11,\"drol\",\"common\",\"astral\",\"TRUE\",\"elemental\",700,1,317,349,0,0,325,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"7\",,,\"res://src/towers/tower_behaviors/minor_magic_ruin.gd\",\"res://resources/icons/tower_icons/minor_magic_ruin.tres\",\"res://src/towers/tower_sprites/minor_magic_ruin_3.tscn\",\"1ZNH\",\"KLME\"\r\n\"Large Magic Ruin\",4,14,11,\"drol\",\"common\",\"astral\",\"TRUE\",\"elemental\",700,1,663,732,0,0,700,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"8\",,,\"res://src/towers/tower_behaviors/minor_magic_ruin.gd\",\"res://resources/icons/tower_icons/minor_magic_ruin.tres\",\"res://src/towers/tower_sprites/minor_magic_ruin_4.tscn\",\"RO47\",\"KLME\"\r\n\"Major Magic Ruin\",5,15,11,\"drol\",\"common\",\"astral\",\"TRUE\",\"elemental\",700,1,1379,1528,0,0,1500,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"9\",,,\"res://src/towers/tower_behaviors/minor_magic_ruin.gd\",\"res://resources/icons/tower_icons/minor_magic_ruin.tres\",\"res://src/towers/tower_sprites/minor_magic_ruin_5.tscn\",\"Q8V4\",\"KLME\"\r\n\"Collosal Magic Ruin\",6,16,11,\"drol\",\"common\",\"astral\",\"TRUE\",\"elemental\",700,1,2228,2477,0,0,2500,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"10\",,,\"res://src/towers/tower_behaviors/minor_magic_ruin.gd\",\"res://resources/icons/tower_icons/minor_magic_ruin.tres\",\"res://src/towers/tower_sprites/minor_magic_ruin_6.tscn\",\"3P4S\",\"KLME\"\r\n\"Small Fire Sprayer\",1,17,17,\"Cyony\",\"common\",\"fire\",\"TRUE\",\"elemental\",750,0.5,21,21,0,0,35,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"11\",,,\"res://src/towers/tower_behaviors/small_fire_sprayer.gd\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"res://src/towers/tower_sprites/small_fire_sprayer_1.tscn\",\"4KYT\",\"1G42\"\r\n\"Medium Fire Sprayer\",2,18,17,\"Cyony\",\"common\",\"fire\",\"TRUE\",\"elemental\",750,0.5,109,109,0,0,180,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"12\",,,\"res://src/towers/tower_behaviors/small_fire_sprayer.gd\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"res://src/towers/tower_sprites/small_fire_sprayer_2.tscn\",\"PR3P\",\"PCVB\"\r\n\"Big Fire Sprayer\",3,19,17,\"Cyony\",\"common\",\"fire\",\"TRUE\",\"elemental\",750,0.5,220,220,0,0,370,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"13\",,,\"res://src/towers/tower_behaviors/small_fire_sprayer.gd\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"res://src/towers/tower_sprites/small_fire_sprayer_3.tscn\",\"VEM0\",\"6ES6\"\r\n\"Grand Fire Sprayer\",4,20,17,\"Cyony\",\"common\",\"fire\",\"TRUE\",\"elemental\",750,0.5,438,438,0,0,750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"14\",,,\"res://src/towers/tower_behaviors/small_fire_sprayer.gd\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"res://src/towers/tower_sprites/small_fire_sprayer_4.tscn\",\"PLTB\",\"TRJR\"\r\n\"Huge Fire Sprayer\",5,21,17,\"Cyony\",\"common\",\"fire\",\"TRUE\",\"elemental\",750,0.5,841,841,0,0,1450,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"15\",,,\"res://src/towers/tower_behaviors/small_fire_sprayer.gd\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"res://src/towers/tower_sprites/small_fire_sprayer_5.tscn\",\"KBJC\",\"Y2DY\"\r\n\"Titanic Fire Sprayer\",6,22,17,\"Cyony\",\"common\",\"fire\",\"TRUE\",\"elemental\",750,0.5,1370,1370,0,0,2400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"16\",,,\"res://src/towers/tower_behaviors/small_fire_sprayer.gd\",\"res://resources/icons/tower_icons/small_fire_sprayer.tres\",\"res://src/towers/tower_sprites/small_fire_sprayer_6.tscn\",\"IYA3\",\"UBQ4\"\r\n\"Time Manipulator\",1,23,23,\"Majildian\",\"unique\",\"astral\",\"TRUE\",\"arcane\",950,3,3994,3994,550,5,4000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"17\",\"5\",\"9\",\"res://src/towers/tower_behaviors/time_manipulator.gd\",\"res://resources/icons/tower_icons/time_manipulator.tres\",\"res://src/towers/tower_sprites/time_manipulator_1.tscn\",\"4LHH\",\"58RV\"\r\n\"Small Bug Nest\",1,24,24,\"Majildian\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",725,1.5,724,823,0,0,600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"18\",,,\"res://src/towers/tower_behaviors/small_bug_nest.gd\",\"res://resources/icons/tower_icons/small_bug_nest.tres\",\"res://src/towers/tower_sprites/small_bug_nest_1.tscn\",\"XINL\",\"YJ2Q\"\r\n\"Bug Nest\",2,25,24,\"Majildian\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",725,1.5,1433,1532,0,0,1150,1500,0,\"FALSE\",\"CREEPS\",,,,,\"19\",,,\"res://src/towers/tower_behaviors/small_bug_nest.gd\",\"res://resources/icons/tower_icons/small_bug_nest.tres\",\"res://src/towers/tower_sprites/small_bug_nest_2.tscn\",\"4VUL\",\"BON8\"\r\n\"Large Bug Nest\",3,26,24,\"Majildian\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",725,1.5,2464,2563,0,0,1950,1500,0,\"FALSE\",\"CREEPS\",,,,,\"20\",,,\"res://src/towers/tower_behaviors/small_bug_nest.gd\",\"res://resources/icons/tower_icons/small_bug_nest.tres\",\"res://src/towers/tower_sprites/small_bug_nest_3.tscn\",\"8YOF\",\"BI2Z\"\r\n\"Bug City\",4,27,24,\"Majildian\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",725,1.5,3818,3917,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"21\",,,\"res://src/towers/tower_behaviors/small_bug_nest.gd\",\"res://resources/icons/tower_icons/small_bug_nest.tres\",\"res://src/towers/tower_sprites/small_bug_nest_4.tscn\",\"OQXJ\",\"5KNN\"\r\n\"Small Ice Mine\",1,28,28,\"Velex\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",700,2,280,281,0,0,150,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"22\",,,\"res://src/towers/tower_behaviors/small_ice_mine.gd\",\"res://resources/icons/tower_icons/small_ice_mine.tres\",\"res://src/towers/tower_sprites/small_ice_mine_1.tscn\",\"S0L9\",\"ELV5\"\r\n\"Ice Mine\",2,29,28,\"Velex\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",700,2,921,922,0,0,500,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"23\",,,\"res://src/towers/tower_behaviors/small_ice_mine.gd\",\"res://resources/icons/tower_icons/small_ice_mine.tres\",\"res://src/towers/tower_sprites/small_ice_mine_2.tscn\",\"9FPU\",\"ELV5\"\r\n\"Deep Ice Mine\",3,30,28,\"Velex\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",700,2,2269,2270,0,0,1250,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"24\",,,\"res://src/towers/tower_behaviors/small_ice_mine.gd\",\"res://resources/icons/tower_icons/small_ice_mine.tres\",\"res://src/towers/tower_sprites/small_ice_mine_3.tscn\",\"YZER\",\"ELV5\"\r\n\"Bottomless Ice Mine\",4,58,28,\"Velex\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",700,2,4472,4473,0,0,2500,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"25\",,,\"res://src/towers/tower_behaviors/small_ice_mine.gd\",\"res://resources/icons/tower_icons/small_ice_mine.tres\",\"res://src/towers/tower_sprites/small_ice_mine_4.tscn\",\"OEVC\",\"ELV5\"\r\n\"Rundown Iron Sentry\",1,31,31,\"Glowackos\",\"rare\",\"iron\",\"TRUE\",\"physical\",925,1.4,710,710,0,0,950,1500,0,\"FALSE\",\"CREEPS\",,,,,\"26,27\",,,\"res://src/towers/tower_behaviors/rundown_iron_sentry.gd\",\"res://resources/icons/tower_icons/rundown_iron_sentry.tres\",\"res://src/towers/tower_sprites/rundown_iron_sentry_1.tscn\",\"XU3D\",\"P6KS\"\r\n\"Solid Iron Sentry\",2,32,31,\"Glowackos\",\"rare\",\"iron\",\"TRUE\",\"physical\",925,1.4,1195,1195,0,0,1600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"28,29\",,,\"res://src/towers/tower_behaviors/rundown_iron_sentry.gd\",\"res://resources/icons/tower_icons/rundown_iron_sentry.tres\",\"res://src/towers/tower_sprites/rundown_iron_sentry_2.tscn\",\"BILF\",\"P6KS\"\r\n\"Modern Iron Sentry\",3,33,31,\"Glowackos\",\"rare\",\"iron\",\"TRUE\",\"physical\",925,1.4,1942,1942,0,0,2600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"30,31\",,,\"res://src/towers/tower_behaviors/rundown_iron_sentry.gd\",\"res://resources/icons/tower_icons/rundown_iron_sentry.tres\",\"res://src/towers/tower_sprites/rundown_iron_sentry_3.tscn\",\"RVTA\",\"P6KS\"\r\n\"Grab-o-Bot\",1,34,34,\"cedi\",\"unique\",\"iron\",\"TRUE\",\"decay\",900,0.4,659,659,100,2.5,3500,900,0,\"FALSE\",\"CREEPS\",,\"75,1,100,0.66,125,0.33\",,,\"32\",,\"10\",\"res://src/towers/tower_behaviors/grab-o-bot.gd\",\"res://resources/icons/tower_icons/grab-o-bot.tres\",\"res://src/towers/tower_sprites/grab-o-bot_1.tscn\",\"Z2M5\",\"NWGO\"\r\n\"Monolith of Chaos\",1,36,36,\"cedi\",\"unique\",\"darkness\",\"TRUE\",\"decay\",750,0.8,1589,1589,0,0,3000,2000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_HUMANOID,0.25,0.01\",\"33\",,,\"res://src/towers/tower_behaviors/monolith_of_chaos.gd\",\"res://resources/icons/tower_icons/monolith_of_chaos.tres\",\"res://src/towers/tower_sprites/monolith_of_chaos_1.tscn\",\"W2CX\",\"63PT\"\r\n\"Timevault\",1,37,37,\"SirCoqalot./TrinkaLot.\",\"unique\",\"astral\",\"TRUE\",\"arcane\",850,6,13589,13688,0,0,2300,900,0,\"FALSE\",\"CREEPS\",,,,,\"34\",\"6\",,\"res://src/towers/tower_behaviors/timevault.gd\",\"res://resources/icons/tower_icons/timevault.tres\",\"res://src/towers/tower_sprites/timevault_1.tscn\",\"7XAS\",\"G0C6\"\r\n\"Cloudy Temple of Absorption\",1,38,38,\"Natac\",\"unique\",\"storm\",\"TRUE\",\"energy\",900,1.4,1659,1659,10000,0.01,2000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,500\",,\"7\",\"11,12\",\"res://src/towers/tower_behaviors/cloudy_temple_of_absorption.gd\",\"res://resources/icons/tower_icons/cloudy_temple_of_absorption.tres\",\"res://src/towers/tower_sprites/cloudy_temple_of_absorption_1.tscn\",\"99YK\",\"3VB9\"\r\n\"Silver Knight\",1,39,39,\"SirCoqalot.\",\"rare\",\"iron\",\"TRUE\",\"physical\",875,1.35,939,1019,0,0,1200,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.3,0.012\",\"35,36\",,,\"res://src/towers/tower_behaviors/silver_knight.gd\",\"res://resources/icons/tower_icons/silver_knight.tres\",\"res://src/towers/tower_sprites/silver_knight_1.tscn\",\"YIFN\",\"33CV\"\r\n\"Golden Queen\",2,40,39,\"SirCoqalot.\",\"rare\",\"iron\",\"TRUE\",\"physical\",875,1.35,2557,2637,0,0,3500,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.4,0.016\",\"37,38\",,,\"res://src/towers/tower_behaviors/silver_knight.gd\",\"res://resources/icons/tower_icons/silver_knight.tres\",\"res://src/towers/tower_sprites/silver_knight_2.tscn\",\"RL8N\",\"33CV\"\r\n\"Small Cactus\",1,41,41,\"Lapsus\",\"common\",\"nature\",\"TRUE\",\"essence\",820,2.5,58,58,0,0,30,1400,0.2,\"FALSE\",\"CREEPS\",,\"320,0.5\",,\"MOD_DMG_TO_MASS,0.15,0.01|MOD_DMG_TO_HUMANOID,0.15,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_cactus.tres\",\"res://src/towers/tower_sprites/small_cactus_1.tscn\",\"0RH3\",\"0UEM\"\r\n\"Budding Cactus\",2,52,41,\"Lapsus\",\"common\",\"nature\",\"TRUE\",\"essence\",820,2.5,287,287,0,0,150,1400,0.2,\"FALSE\",\"CREEPS\",,\"320,0.5\",,\"MOD_DMG_TO_MASS,0.17,0.011|MOD_DMG_TO_HUMANOID,0.17,0.011\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_cactus.tres\",\"res://src/towers/tower_sprites/small_cactus_2.tscn\",\"NKVP\",\"PRYW\"\r\n\"Average Cactus\",3,42,41,\"Lapsus\",\"common\",\"nature\",\"TRUE\",\"essence\",820,2.5,719,719,0,0,380,1400,0.2,\"FALSE\",\"CREEPS\",,\"320,0.5\",,\"MOD_DMG_TO_MASS,0.19,0.012|MOD_DMG_TO_HUMANOID,0.19,0.012\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_cactus.tres\",\"res://src/towers/tower_sprites/small_cactus_3.tscn\",\"W43C\",\"1CQH\"\r\n\"Grown Cactus\",4,43,41,\"Lapsus\",\"common\",\"nature\",\"TRUE\",\"essence\",820,2.5,1422,1422,0,0,760,1400,0.2,\"FALSE\",\"CREEPS\",,\"320,0.5\",,\"MOD_DMG_TO_MASS,0.21,0.013|MOD_DMG_TO_HUMANOID,0.21,0.013\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_cactus.tres\",\"res://src/towers/tower_sprites/small_cactus_4.tscn\",\"VGBC\",\"J6CW\"\r\n\"Blooming Cactus\",5,44,41,\"Lapsus\",\"common\",\"nature\",\"TRUE\",\"essence\",820,2.5,2496,2496,0,0,1350,1400,0.2,\"FALSE\",\"CREEPS\",,\"320,0.5\",,\"MOD_DMG_TO_MASS,0.23,0.014|MOD_DMG_TO_HUMANOID,0.23,0.014\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_cactus.tres\",\"res://src/towers/tower_sprites/small_cactus_5.tscn\",\"CAG7\",\"48B8\"\r\n\"Fully-Flowered Cactus\",6,45,41,\"Lapsus\",\"common\",\"nature\",\"TRUE\",\"essence\",820,2.5,4063,4063,0,0,2250,1400,0.2,\"FALSE\",\"CREEPS\",,\"320,0.5\",,\"MOD_DMG_TO_MASS,0.25,0.016|MOD_DMG_TO_HUMANOID,0.25,0.016\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_cactus.tres\",\"res://src/towers/tower_sprites/small_cactus_6.tscn\",\"8SJ7\",\"6E75\"\r\n\"Astral Rift\",1,46,46,\"i_m0ck_death\",\"unique\",\"astral\",\"TRUE\",\"energy\",750,1.5,2151,2151,180,2.5,3000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"39\",\"8\",,\"res://src/towers/tower_behaviors/astral_rift.gd\",\"res://resources/icons/tower_icons/astral_rift.tres\",\"res://src/towers/tower_sprites/astral_rift_1.tscn\",\"F1TU\",\"EVJV\"\r\n\"Mud Golem\",1,47,47,\"SirCoqalot.\",\"unique\",\"nature\",\"TRUE\",\"decay\",750,2.2,2327,2734,0,0,3000,1700,0,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,,,,\"40\",\"9\",,\"res://src/towers/tower_behaviors/mud_golem.gd\",\"res://resources/icons/tower_icons/mud_golem.tres\",\"res://src/towers/tower_sprites/mud_golem_1.tscn\",\"WQWP\",\"UE94\"\r\n\"Razorboar Thornweaver\",1,48,48,\"SirCoqalot.\",\"rare\",\"nature\",\"TRUE\",\"physical\",800,0.9,379,398,100,1,800,1300,0,\"FALSE\",\"CREEPS\",,,,,\"41\",,\"13\",\"res://src/towers/tower_behaviors/razorboar_thornweaver.gd\",\"res://resources/icons/tower_icons/razorboar_thornweaver.tres\",\"res://src/towers/tower_sprites/razorboar_thornweaver_1.tscn\",\"JPDB\",\"U3V2\"\r\n\"Razorboar Painbringer \",2,64,48,\"SirCoqalot.\",\"rare\",\"nature\",\"TRUE\",\"physical\",800,0.9,815,834,100,1,1700,1300,0,\"FALSE\",\"CREEPS\",,,,,\"42\",,\"14\",\"res://src/towers/tower_behaviors/razorboar_thornweaver.gd\",\"res://resources/icons/tower_icons/razorboar_thornweaver.tres\",\"res://src/towers/tower_sprites/razorboar_thornweaver_2.tscn\",\"YK86\",\"U3V2\"\r\n\"Razorboar Deathpig \",3,65,48,\"SirCoqalot.\",\"rare\",\"nature\",\"TRUE\",\"physical\",800,0.9,1590,1609,100,1,3300,1300,0,\"FALSE\",\"CREEPS\",,,,,\"43\",,\"15\",\"res://src/towers/tower_behaviors/razorboar_thornweaver.gd\",\"res://resources/icons/tower_icons/razorboar_thornweaver.tres\",\"res://src/towers/tower_sprites/razorboar_thornweaver_3.tscn\",\"31CV\",\"U3V2\"\r\n\"Star Gazer\",1,53,53,\"i_m0ck_death\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",875,1.55,127,127,0,0,160,1200,0.3,\"FALSE\",\"CREEPS\",,,,,\"44\",,,\"res://src/towers/tower_behaviors/star_gazer.gd\",\"res://resources/icons/tower_icons/star_gazer.tres\",\"res://src/towers/tower_sprites/star_gazer_1.tscn\",\"OCXC\",\"O8TG\"\r\n\"Star Watcher\",2,55,53,\"i_m0ck_death\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",875,1.55,474,474,0,0,630,1200,0.3,\"FALSE\",\"CREEPS\",,,,,\"45\",,,\"res://src/towers/tower_behaviors/star_gazer.gd\",\"res://resources/icons/tower_icons/star_gazer.tres\",\"res://src/towers/tower_sprites/star_gazer_2.tscn\",\"F25F\",\"O8TG\"\r\n\"Star Observer\",3,56,53,\"i_m0ck_death\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",875,1.55,990,990,0,0,1370,1200,0.3,\"FALSE\",\"CREEPS\",,,,,\"46\",,,\"res://src/towers/tower_behaviors/star_gazer.gd\",\"res://resources/icons/tower_icons/star_gazer.tres\",\"res://src/towers/tower_sprites/star_gazer_3.tscn\",\"705R\",\"O8TG\"\r\n\"Star Keeper\",4,57,53,\"i_m0ck_death\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",875,1.55,1781,1781,0,0,2560,1200,0.3,\"FALSE\",\"CREEPS\",,,,,\"47\",,,\"res://src/towers/tower_behaviors/star_gazer.gd\",\"res://resources/icons/tower_icons/star_gazer.tres\",\"res://src/towers/tower_sprites/star_gazer_4.tscn\",\"UIAY\",\"O8TG\"\r\n\"Charged Obelisk\",1,54,54,\"Boekie\",\"unique\",\"storm\",\"TRUE\",\"energy\",1200,1.5,748,748,30,1,1700,1500,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.04\",\"48\",,\"16\",\"res://src/towers/tower_behaviors/charged_obelisk.gd\",\"res://resources/icons/tower_icons/charged_obelisk.tres\",\"res://src/towers/tower_sprites/charged_obelisk_1.tscn\",\"TOGE\",\"XS11\"\r\n\"Initiate Elementalist\",1,59,59,\"Kel-Thuzad\",\"uncommon\",\"astral\",\"TRUE\",\"arcane\",900,2,25,25,0,0,150,1500,0.15,\"FALSE\",\"CREEPS\",,,,,\"49\",,,\"res://src/towers/tower_behaviors/initiate_elementalist.gd\",\"res://resources/icons/tower_icons/initiate_elementalist.tres\",\"res://src/towers/tower_sprites/initiate_elementalist_1.tscn\",\"BGLA\",\"FLKG\"\r\n\"Adept Elementalist\",2,62,59,\"Kel-Thuzad\",\"uncommon\",\"astral\",\"TRUE\",\"arcane\",900,2,83,83,0,0,500,1500,0.15,\"FALSE\",\"CREEPS\",,,,,\"50\",,,\"res://src/towers/tower_behaviors/initiate_elementalist.gd\",\"res://resources/icons/tower_icons/initiate_elementalist.tres\",\"res://src/towers/tower_sprites/initiate_elementalist_2.tscn\",\"W17Y\",\"F4NA\"\r\n\"Master Elementalist\",3,61,59,\"Kel-Thuzad\",\"uncommon\",\"astral\",\"TRUE\",\"arcane\",900,2,209,209,0,0,1250,1500,0.15,\"FALSE\",\"CREEPS\",,,,,\"51\",,,\"res://src/towers/tower_behaviors/initiate_elementalist.gd\",\"res://resources/icons/tower_icons/initiate_elementalist.tres\",\"res://src/towers/tower_sprites/initiate_elementalist_3.tscn\",\"AE8K\",\"QS4R\"\r\n\"Divine Elementalist\",4,60,59,\"Kel-Thuzad\",\"uncommon\",\"astral\",\"TRUE\",\"arcane\",900,2,417,417,0,0,2500,1500,0.15,\"FALSE\",\"CREEPS\",,,,,\"52,53\",,,\"res://src/towers/tower_behaviors/initiate_elementalist.gd\",\"res://resources/icons/tower_icons/initiate_elementalist.tres\",\"res://src/towers/tower_sprites/initiate_elementalist_4.tscn\",\"A84T\",\"1LPT\"\r\n\"Bronze Dragon Roost\",1,63,63,\"cedi\",\"unique\",\"iron\",\"TRUE\",\"essence\",800,2,1186,1190,0,0,1600,1000,0.1,\"FALSE\",\"CREEPS\",,,\"6,0.1\",,\"54\",,,\"res://src/towers/tower_behaviors/bronze_dragon_roost.gd\",\"res://resources/icons/tower_icons/bronze_dragon_roost.tres\",\"res://src/towers/tower_sprites/bronze_dragon_roost_1.tscn\",\"715A\",\"VRUB\"\r\n\"Black Rock Totem\",1,66,66,\"poussix\",\"unique\",\"fire\",\"TRUE\",\"elemental\",1200,2,1036,1036,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"55,56\",,\"17\",\"res://src/towers/tower_behaviors/black_rock_totem.gd\",\"res://resources/icons/tower_icons/black_rock_totem.tres\",\"res://src/towers/tower_sprites/black_rock_totem_1.tscn\",\"M5WU\",\"4QEB\"\r\n\"Area Roaster\",1,67,67,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",700,1.2,85,85,0,0,650,1500,0,\"FALSE\",\"CREEPS\",\"4\",,,,\"57\",,,\"res://src/towers/tower_behaviors/area_roaster.gd\",\"res://resources/icons/tower_icons/area_roaster.tres\",\"res://src/towers/tower_sprites/area_roaster_1.tscn\",\"3I9F\",\"95W4\"\r\n\"Area Igniter\",2,68,67,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",700,1.2,132,132,0,0,1300,1500,0,\"FALSE\",\"CREEPS\",\"4\",,,,\"58\",,,\"res://src/towers/tower_behaviors/area_roaster.gd\",\"res://resources/icons/tower_icons/area_roaster.tres\",\"res://src/towers/tower_sprites/area_roaster_2.tscn\",\"E3JO\",\"95W4\"\r\n\"Area Inflamer\",3,69,67,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",700,1.2,188,188,0,0,2600,1500,0,\"FALSE\",\"CREEPS\",\"4\",,,,\"59\",,,\"res://src/towers/tower_behaviors/area_roaster.gd\",\"res://resources/icons/tower_icons/area_roaster.tres\",\"res://src/towers/tower_sprites/area_roaster_3.tscn\",\"VLCG\",\"95W4\"\r\n\"Fiery Dog\",1,70,70,\"cedi\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,1.2,78,86,0,0,70,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0\",\"60\",,,\"res://src/towers/tower_behaviors/fiery_dog.gd\",\"res://resources/icons/tower_icons/fiery_dog.tres\",\"res://src/towers/tower_sprites/fiery_dog_1.tscn\",\"SQC6\",\"8GF2\"\r\n\"Burning Dog\",2,73,70,\"cedi\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,1.2,236,236,0,0,210,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.05\",\"61\",,,\"res://src/towers/tower_behaviors/fiery_dog.gd\",\"res://resources/icons/tower_icons/fiery_dog.tres\",\"res://src/towers/tower_sprites/fiery_dog_2.tscn\",\"0LYE\",\"8GF2\"\r\n\"Hellhound\",3,74,70,\"cedi\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,1.2,900,900,0,0,840,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.06\",\"62\",,,\"res://src/towers/tower_behaviors/fiery_dog.gd\",\"res://resources/icons/tower_icons/fiery_dog.tres\",\"res://src/towers/tower_sprites/fiery_dog_3.tscn\",\"3FKT\",\"8GF2\"\r\n\"Infernal Dog\",4,75,70,\"cedi\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,1.2,1712,1712,0,0,1680,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.07\",\"63\",,,\"res://src/towers/tower_behaviors/fiery_dog.gd\",\"res://resources/icons/tower_icons/fiery_dog.tres\",\"res://src/towers/tower_sprites/fiery_dog_4.tscn\",\"QDQS\",\"8GF2\"\r\n\"Hound of War\",5,76,70,\"cedi\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,1.2,3249,3249,0,0,3360,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.08\",\"64\",,,\"res://src/towers/tower_behaviors/fiery_dog.gd\",\"res://resources/icons/tower_icons/fiery_dog.tres\",\"res://src/towers/tower_sprites/fiery_dog_5.tscn\",\"VBDE\",\"8GF2\"\r\n\"Solar Emitter\",1,71,71,\"geX\",\"rare\",\"astral\",\"TRUE\",\"elemental\",800,1.4,990,990,0,0,1300,1000,0,\"FALSE\",\"CREEPS\",,\"50,1,350,0.4\",,,,\"10\",,\"res://src/towers/tower_behaviors/solar_emitter.gd\",\"res://resources/icons/tower_icons/solar_emitter.tres\",\"res://src/towers/tower_sprites/solar_emitter_1.tscn\",\"61GP\",\"96X3\"\r\n\"Ancient Solar Emitter\",2,72,71,\"geX\",\"rare\",\"astral\",\"TRUE\",\"elemental\",1100,1.4,2153,2153,0,0,3200,1000,0,\"FALSE\",\"CREEPS\",,\"50,1,350,0.4\",,,,\"11\",,\"res://src/towers/tower_behaviors/solar_emitter.gd\",\"res://resources/icons/tower_icons/solar_emitter.tres\",\"res://src/towers/tower_sprites/solar_emitter_2.tscn\",\"6D9I\",\"96X3\"\r\n\"Igloo\",1,77,77,\"Boekie\",\"rare\",\"ice\",\"TRUE\",\"energy\",1000,2.5,696,696,0,0,700,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.5,0\",\"65\",,,\"res://src/towers/tower_behaviors/igloo.gd\",\"res://resources/icons/tower_icons/igloo.tres\",\"res://src/towers/tower_sprites/igloo_1.tscn\",\"26AM\",\"XRZ7\"\r\n\"Frozen Igloo\",2,78,77,\"Boekie\",\"rare\",\"ice\",\"TRUE\",\"energy\",1000,2.5,1492,1492,0,0,1500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.5,0\",\"66\",,,\"res://src/towers/tower_behaviors/igloo.gd\",\"res://resources/icons/tower_icons/igloo.tres\",\"res://src/towers/tower_sprites/igloo_2.tscn\",\"E3IQ\",\"XRZ7\"\r\n\"Deep Frozen Igloo\",3,79,77,\"Boekie\",\"rare\",\"ice\",\"TRUE\",\"energy\",1000,2.5,2785,2785,0,0,2800,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.5,0\",\"67\",,,\"res://src/towers/tower_behaviors/igloo.gd\",\"res://resources/icons/tower_icons/igloo.tres\",\"res://src/towers/tower_sprites/igloo_3.tscn\",\"B62S\",\"XRZ7\"\r\n\"Small Light\",1,80,80,\"SternBogen\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",850,1,53,59,0,0,65,1900,0,\"FALSE\",\"CREEPS\",,,,,\"68\",,,\"res://src/towers/tower_behaviors/small_light.gd\",\"res://resources/icons/tower_icons/small_light.tres\",\"res://src/towers/tower_sprites/small_light_1.tscn\",\"EZUO\",\"25N3\"\r\n\"Shining Light\",2,82,80,\"SternBogen\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",850,1,189,195,0,0,230,1900,0,\"FALSE\",\"CREEPS\",,,,,\"69\",,,\"res://src/towers/tower_behaviors/small_light.gd\",\"res://resources/icons/tower_icons/small_light.tres\",\"res://src/towers/tower_sprites/small_light_2.tscn\",\"N9CH\",\"25N3\"\r\n\"Bright Light\",3,81,80,\"SternBogen\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",850,1,527,533,0,0,650,1900,0,\"FALSE\",\"CREEPS\",,,,,\"70\",,,\"res://src/towers/tower_behaviors/small_light.gd\",\"res://resources/icons/tower_icons/small_light.tres\",\"res://src/towers/tower_sprites/small_light_3.tscn\",\"GWH1\",\"25N3\"\r\n\"Holy Light\",4,355,80,\"SternBogen\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",850,1,992,998,0,0,1250,1900,0,\"FALSE\",\"CREEPS\",,,,,\"71\",,,\"res://src/towers/tower_behaviors/small_light.gd\",\"res://resources/icons/tower_icons/small_light.tres\",\"res://src/towers/tower_sprites/small_light_4.tscn\",\"BOPV\",\"25N3\"\r\n\"Holy Eternal Light\",5,356,80,\"SternBogen\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",850,1,2168,2174,0,0,2799,1900,0,\"FALSE\",\"CREEPS\",,,,,\"72\",,,\"res://src/towers/tower_behaviors/small_light.gd\",\"res://resources/icons/tower_icons/small_light.tres\",\"res://src/towers/tower_sprites/small_light_5.tscn\",\"RIU4\",\"D0JB\"\r\n\"Phantom\",1,83,83,\"drol\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",900,1.5,148,148,17,1,125,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.1\",,,\"18\",\"res://src/towers/tower_behaviors/phantom.gd\",\"res://resources/icons/tower_icons/phantom.tres\",\"res://src/towers/tower_sprites/phantom_1.tscn\",\"HKG0\",\"PP40\"\r\n\"Aery Phantom\",2,87,83,\"drol\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",900,1.5,414,414,17,1,375,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.1\",,,\"19\",\"res://src/towers/tower_behaviors/phantom.gd\",\"res://resources/icons/tower_icons/phantom.tres\",\"res://src/towers/tower_sprites/phantom_2.tscn\",\"XV0A\",\"PP40\"\r\n\"Swift Phantom\",3,88,83,\"drol\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",900,1.5,769,769,17,1,750,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.1\",,,\"20\",\"res://src/towers/tower_behaviors/phantom.gd\",\"res://resources/icons/tower_icons/phantom.tres\",\"res://src/towers/tower_sprites/phantom_3.tscn\",\"KYPH\",\"PP40\"\r\n\"Ethereal Phantom\",4,89,83,\"drol\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",900,1.5,1182,1182,17,1,1250,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.1\",,,\"21\",\"res://src/towers/tower_behaviors/phantom.gd\",\"res://resources/icons/tower_icons/phantom.tres\",\"res://src/towers/tower_sprites/phantom_4.tscn\",\"Y32L\",\"PP40\"\r\n\"Everlasting Phantom\",5,90,83,\"drol\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",900,1.5,1951,1951,17,1,2250,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.1\",,,\"22\",\"res://src/towers/tower_behaviors/phantom.gd\",\"res://resources/icons/tower_icons/phantom.tres\",\"res://src/towers/tower_sprites/phantom_5.tscn\",\"KTPC\",\"PP40\"\r\n\"Warrior of Light\",1,84,84,\"i_m0ck_death\",\"rare\",\"astral\",\"TRUE\",\"elemental\",900,1,406,406,0,0,1000,1000,0,\"FALSE\",\"CREEPS\",,,,,\"73\",\"12\",,\"res://src/towers/tower_behaviors/warrior_of_light.gd\",\"res://resources/icons/tower_icons/warrior_of_light.tres\",\"res://src/towers/tower_sprites/warrior_of_light_1.tscn\",\"YJ2P\",\"1ZK0\"\r\n\"Champion of Light\",2,85,84,\"i_m0ck_death\",\"rare\",\"astral\",\"TRUE\",\"elemental\",900,1,751,751,0,0,2000,1000,0,\"FALSE\",\"CREEPS\",,,,,\"74\",\"13\",,\"res://src/towers/tower_behaviors/warrior_of_light.gd\",\"res://resources/icons/tower_icons/warrior_of_light.tres\",\"res://src/towers/tower_sprites/warrior_of_light_2.tscn\",\"VFYL\",\"1ZK0\"\r\n\"Hero of Light\",3,86,84,\"i_m0ck_death\",\"rare\",\"astral\",\"TRUE\",\"elemental\",900,1,1036,1036,0,0,3000,1000,0,\"FALSE\",\"CREEPS\",,,,,\"75\",\"14\",,\"res://src/towers/tower_behaviors/warrior_of_light.gd\",\"res://resources/icons/tower_icons/warrior_of_light.tres\",\"res://src/towers/tower_sprites/warrior_of_light_3.tscn\",\"C8PX\",\"1ZK0\"\r\n\"Bone Shrine\",1,91,91,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",950,2,1155,1165,0,0,600,1300,0,\"FALSE\",\"CREEPS\",,,,,\"76\",,,\"res://src/towers/tower_behaviors/bone_shrine.gd\",\"res://resources/icons/tower_icons/bone_shrine.tres\",\"res://src/towers/tower_sprites/bone_shrine_1.tscn\",\"TUD2\",\"1ZMP\"\r\n\"Bone Temple\",2,92,91,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",950,1.9,1975,1985,0,0,1400,1300,0,\"FALSE\",\"CREEPS\",,,,,\"77\",,,\"res://src/towers/tower_behaviors/bone_shrine.gd\",\"res://resources/icons/tower_icons/bone_shrine.tres\",\"res://src/towers/tower_sprites/bone_shrine_2.tscn\",\"8GX4\",\"1ZMP\"\r\n\"Bone Monument\",3,93,91,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",950,1.8,2598,2608,0,0,2750,1300,0,\"FALSE\",\"CREEPS\",,,,,\"78\",,,\"res://src/towers/tower_behaviors/bone_shrine.gd\",\"res://resources/icons/tower_icons/bone_shrine.tres\",\"res://src/towers/tower_sprites/bone_shrine_3.tscn\",\"PYSC\",\"M7VX\"\r\n\"Small Serpent Ward\",1,94,94,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1050,1.35,374,374,12,1,350,900,0,\"FALSE\",\"CREEPS\",,,,,,,\"23\",\"res://src/towers/tower_behaviors/small_serpent_ward.gd\",\"res://resources/icons/tower_icons/small_serpent_ward.tres\",\"res://src/towers/tower_sprites/small_serpent_ward_1.tscn\",\"Y0WP\",\"EPKK\"\r\n\"Serpent Ward\",2,95,94,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1050,1.35,726,726,12,1,700,900,0,\"FALSE\",\"CREEPS\",,,,,,,\"24\",\"res://src/towers/tower_behaviors/small_serpent_ward.gd\",\"res://resources/icons/tower_icons/small_serpent_ward.tres\",\"res://src/towers/tower_sprites/small_serpent_ward_2.tscn\",\"QHHS\",\"EPKK\"\r\n\"Enchanted Serpent Ward\",3,96,94,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1050,1.35,1407,1407,12,1,1400,900,0,\"FALSE\",\"CREEPS\",,,,,,,\"25\",\"res://src/towers/tower_behaviors/small_serpent_ward.gd\",\"res://resources/icons/tower_icons/small_serpent_ward.tres\",\"res://src/towers/tower_sprites/small_serpent_ward_3.tscn\",\"3FBM\",\"EPKK\"\r\n\"Mythic Serpent Ward\",4,97,94,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1050,1.35,2727,2727,12,1,2800,900,0,\"FALSE\",\"CREEPS\",,,,,,,\"26\",\"res://src/towers/tower_behaviors/small_serpent_ward.gd\",\"res://resources/icons/tower_icons/small_serpent_ward.tres\",\"res://src/towers/tower_sprites/small_serpent_ward_4.tscn\",\"GWIW\",\"EPKK\"\r\n\"Tundra Stalker\",1,98,98,\"drol\",\"uncommon\",\"ice\",\"TRUE\",\"arcane\",850,1.3,136,155,12,1,175,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.04\",\"79\",,\"27\",\"res://src/towers/tower_behaviors/tundra_stalker.gd\",\"res://resources/icons/tower_icons/tundra_stalker.tres\",\"res://src/towers/tower_sprites/tundra_stalker_1.tscn\",\"60Q1\",\"XUHJ\"\r\n\"Northern Stalker\",2,103,98,\"drol\",\"uncommon\",\"ice\",\"TRUE\",\"arcane\",850,1.3,271,310,12,1,350,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.04\",\"80\",,\"28\",\"res://src/towers/tower_behaviors/tundra_stalker.gd\",\"res://resources/icons/tower_icons/tundra_stalker.tres\",\"res://src/towers/tower_sprites/tundra_stalker_2.tscn\",\"J0DJ\",\"P5OH\"\r\n\"Snow Stalker\",3,104,98,\"drol\",\"uncommon\",\"ice\",\"TRUE\",\"arcane\",850,1.3,541,620,12,1,700,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.04\",\"81\",,\"29\",\"res://src/towers/tower_behaviors/tundra_stalker.gd\",\"res://resources/icons/tower_icons/tundra_stalker.tres\",\"res://src/towers/tower_sprites/tundra_stalker_3.tscn\",\"KQKK\",\"P5OH\"\r\n\"Polar Stalker\",4,105,98,\"drol\",\"uncommon\",\"ice\",\"TRUE\",\"arcane\",850,1.3,1080,1239,12,1,1400,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.04\",\"82\",,\"30\",\"res://src/towers/tower_behaviors/tundra_stalker.gd\",\"res://resources/icons/tower_icons/tundra_stalker.tres\",\"res://src/towers/tower_sprites/tundra_stalker_4.tscn\",\"XX3I\",\"P5OH\"\r\n\"Arctic Stalker\",5,106,98,\"drol\",\"uncommon\",\"ice\",\"TRUE\",\"arcane\",850,1.3,1620,1859,12,1,2100,1700,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.04\",\"83\",,\"31\",\"res://src/towers/tower_behaviors/tundra_stalker.gd\",\"res://resources/icons/tower_icons/tundra_stalker.tres\",\"res://src/towers/tower_sprites/tundra_stalker_5.tscn\",\"Y8ZW\",\"P5OH\"\r\n\"Energy Junction\",1,99,99,\"SirCoqalot.\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",500,0.7,455,455,20,1,500,1500,0,\"FALSE\",\"CREEPS,SIZE_AIR\",,,,,,,\"32\",\"res://src/towers/tower_behaviors/energy_junction.gd\",\"res://resources/icons/tower_icons/energy_junction.tres\",\"res://src/towers/tower_sprites/energy_junction_1.tscn\",\"R5KA\",\"T1QF\"\r\n\"Energy Crossing\",2,177,99,\"SirCoqalot.\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",500,0.7,1182,1182,20,1,1300,1500,0,\"FALSE\",\"CREEPS,SIZE_AIR\",,,,,,,\"33\",\"res://src/towers/tower_behaviors/energy_junction.gd\",\"res://resources/icons/tower_icons/energy_junction.tres\",\"res://src/towers/tower_sprites/energy_junction_2.tscn\",\"1Z1E\",\"T1QF\"\r\n\"Energy Magnifier\",3,178,99,\"SirCoqalot.\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",500,0.7,1910,1910,20,1,2100,1500,0,\"FALSE\",\"CREEPS,SIZE_AIR\",,,,,,,\"34\",\"res://src/towers/tower_behaviors/energy_junction.gd\",\"res://resources/icons/tower_icons/energy_junction.tres\",\"res://src/towers/tower_sprites/energy_junction_3.tscn\",\"7060\",\"T1QF\"\r\n\"Frozen Well\",1,100,100,\"Boekie\",\"unique\",\"ice\",\"TRUE\",\"energy\",925,2,1261,1261,0,0,1600,1500,0,\"FALSE\",\"CREEPS\",,\"150,1,625,0.2\",,,\"84\",\"15\",,\"res://src/towers/tower_behaviors/frozen_well.gd\",\"res://resources/icons/tower_icons/frozen_well.tres\",\"res://src/towers/tower_sprites/frozen_well_1.tscn\",\"HSJZ\",\"T12G\"\r\n\"Nortrom the Silencer\",1,101,101,\"i_m0ck_death\",\"unique\",\"astral\",\"TRUE\",\"physical\",800,3,7063,7063,400,6,3500,1000,0,\"FALSE\",\"CREEPS\",,,,,\"85,86,87\",\"16\",,\"res://src/towers/tower_behaviors/nortrom_the_silencer.gd\",\"res://resources/icons/tower_icons/nortrom_the_silencer.tres\",\"res://src/towers/tower_sprites/nortrom_the_silencer_1.tscn\",\"QU29\",\"I6AG\"\r\n\"Cute Small Spider\",1,102,102,\"D1000\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",825,1.2,57,66,0,0,120,1000,0.4,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,-0.3,0|MOD_DMG_TO_ORC,0.1,0|MOD_DMG_TO_HUMANOID,0.2,0\",\"88\",,,\"res://src/towers/tower_behaviors/cute_small_spider.gd\",\"res://resources/icons/tower_icons/cute_small_spider.tres\",\"res://src/towers/tower_sprites/cute_small_spider_1.tscn\",\"8A08\",\"EWJE\"\r\n\"Ugly Small Spider\",2,174,102,\"D1000\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",825,1.2,180,189,0,0,360,1000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,-0.3,0|MOD_DMG_TO_ORC,0.1,0|MOD_DMG_TO_HUMANOID,0.2,0\",\"89\",,,\"res://src/towers/tower_behaviors/cute_small_spider.gd\",\"res://resources/icons/tower_icons/cute_small_spider.tres\",\"res://src/towers/tower_sprites/cute_small_spider_2.tscn\",\"ZUBQ\",\"01GH\"\r\n\"Adorable Young Spider\",3,175,102,\"D1000\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",825,1.2,549,558,0,0,1080,1000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,-0.3,0|MOD_DMG_TO_ORC,0.1,0|MOD_DMG_TO_HUMANOID,0.2,0\",\"90\",,,\"res://src/towers/tower_behaviors/cute_small_spider.gd\",\"res://resources/icons/tower_icons/cute_small_spider.tres\",\"res://src/towers/tower_sprites/cute_small_spider_3.tscn\",\"JJKV\",\"URQP\"\r\n\"Breeding Adult Spider\",4,176,102,\"D1000\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",825,1.2,1532,1541,0,0,3000,1000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,-0.3,0|MOD_DMG_TO_ORC,0.1,0|MOD_DMG_TO_HUMANOID,0.2,0\",\"91\",,,\"res://src/towers/tower_behaviors/cute_small_spider.gd\",\"res://resources/icons/tower_icons/cute_small_spider.tres\",\"res://src/towers/tower_sprites/cute_small_spider_4.tscn\",\"NTB8\",\"XA9P\"\r\n\"Dark Fire Pit\",1,107,107,\"i_m0ck_death\",\"common\",\"darkness\",\"TRUE\",\"decay\",850,1.1,42,42,0,0,50,1400,0,\"FALSE\",\"CREEPS\",\"2\",,,\"MOD_DMG_TO_UNDEAD,-0.2,0.004|MOD_DMG_TO_MAGIC,0.2,0.004\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/dark_fire_pit.tres\",\"res://src/towers/tower_sprites/dark_fire_pit_1.tscn\",\"WU3Y\",\"TZLN\"\r\n\"Enhanced Dark Fire Pit\",2,179,107,\"i_m0ck_death\",\"common\",\"darkness\",\"TRUE\",\"decay\",850,1.1,177,177,0,0,210,1400,0,\"FALSE\",\"CREEPS\",\"2\",,,\"MOD_DMG_TO_UNDEAD,-0.2,0.004|MOD_DMG_TO_MAGIC,0.2,0.005\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/dark_fire_pit.tres\",\"res://src/towers/tower_sprites/dark_fire_pit_2.tscn\",\"EUAT\",\"TZLN\"\r\n\"Enchanted Dark Fire Pit\",3,180,107,\"i_m0ck_death\",\"common\",\"darkness\",\"TRUE\",\"decay\",850,1.1,383,383,0,0,660,1400,0,\"FALSE\",\"CREEPS\",\"3\",,,\"MOD_DMG_TO_UNDEAD,-0.2,0.005|MOD_DMG_TO_MAGIC,0.2,0.006\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/dark_fire_pit.tres\",\"res://src/towers/tower_sprites/dark_fire_pit_3.tscn\",\"MXT8\",\"TZLN\"\r\n\"Engulfing Dark Fire Pit\",4,181,107,\"i_m0ck_death\",\"common\",\"darkness\",\"TRUE\",\"decay\",850,1.1,754,754,0,0,1300,1400,0,\"FALSE\",\"CREEPS\",\"3\",,,\"MOD_DMG_TO_UNDEAD,-0.2,0.005|MOD_DMG_TO_MAGIC,0.2,0.007\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/dark_fire_pit.tres\",\"res://src/towers/tower_sprites/dark_fire_pit_4.tscn\",\"O5ZE\",\"TZLN\"\r\n\"Consuming Dark Fire Pit\",5,182,107,\"i_m0ck_death\",\"common\",\"darkness\",\"TRUE\",\"decay\",850,1.1,1067,1067,0,0,2250,1400,0,\"FALSE\",\"CREEPS\",\"4\",,,\"MOD_DMG_TO_UNDEAD,-0.2,0.006|MOD_DMG_TO_MAGIC,0.2,0.008\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/dark_fire_pit.tres\",\"res://src/towers/tower_sprites/dark_fire_pit_5.tscn\",\"X6XG\",\"TZLN\"\r\n\"Thief Apprentice\",1,108,108,\"i_m0ck_death\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",800,1.5,103,103,0,0,65,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.1,0.004|MOD_BOUNTY_RECEIVED,0,0.005|MOD_ITEM_CHANCE_ON_KILL,0.05,0.002|MOD_ITEM_QUALITY_ON_KILL,0.05,0.002\",\"92\",,,\"res://src/towers/tower_behaviors/thief_apprentice.gd\",\"res://resources/icons/tower_icons/thief_apprentice.tres\",\"res://src/towers/tower_sprites/thief_apprentice_1.tscn\",\"E67B\",\"FORI\"\r\n\"Thief Novice\",2,109,108,\"i_m0ck_death\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",800,1.5,305,305,0,0,195,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.1,0.004|MOD_BOUNTY_RECEIVED,0,0.0075|MOD_ITEM_CHANCE_ON_KILL,0.06,0.0024|MOD_ITEM_QUALITY_ON_KILL,0.06,0.0024\",\"93\",,,\"res://src/towers/tower_behaviors/thief_apprentice.gd\",\"res://resources/icons/tower_icons/thief_apprentice.tres\",\"res://src/towers/tower_sprites/thief_apprentice_2.tscn\",\"1LMN\",\"FORI\"\r\n\"Thief\",3,110,108,\"i_m0ck_death\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",800,1.5,904,904,0,0,585,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.1,0.004|MOD_BOUNTY_RECEIVED,0,0.01|MOD_ITEM_CHANCE_ON_KILL,0.07,0.0028|MOD_ITEM_QUALITY_ON_KILL,0.07,0.0028\",\"94\",,,\"res://src/towers/tower_behaviors/thief_apprentice.gd\",\"res://resources/icons/tower_icons/thief_apprentice.tres\",\"res://src/towers/tower_sprites/thief_apprentice_3.tscn\",\"RYU9\",\"FORI\"\r\n\"Thief Master\",4,111,108,\"i_m0ck_death\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",800,1.5,1987,1987,0,0,1300,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.1,0.004|MOD_BOUNTY_RECEIVED,0,0.0125|MOD_ITEM_CHANCE_ON_KILL,0.08,0.0032|MOD_ITEM_QUALITY_ON_KILL,0.08,0.0032\",\"95\",,,\"res://src/towers/tower_behaviors/thief_apprentice.gd\",\"res://resources/icons/tower_icons/thief_apprentice.tres\",\"res://src/towers/tower_sprites/thief_apprentice_4.tscn\",\"O68K\",\"FORI\"\r\n\"Thief Grand Master\",5,113,108,\"i_m0ck_death\",\"uncommon\",\"darkness\",\"TRUE\",\"physical\",800,1.5,3930,3930,0,0,2600,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.1,0.004|MOD_BOUNTY_RECEIVED,0,0.015|MOD_ITEM_CHANCE_ON_KILL,0.09,0.0036|MOD_ITEM_QUALITY_ON_KILL,0.09,0.0036\",\"96\",,,\"res://src/towers/tower_behaviors/thief_apprentice.gd\",\"res://resources/icons/tower_icons/thief_apprentice.tres\",\"res://src/towers/tower_sprites/thief_apprentice_5.tscn\",\"244E\",\"FORI\"\r\n\"Tidewater Stream\",1,112,112,\"cedi\",\"unique\",\"ice\",\"TRUE\",\"elemental\",820,1.8,3388,3388,0,0,3150,1000,0.15,\"FALSE\",\"CREEPS\",,,,,\"97,98\",\"17\",,\"res://src/towers/tower_behaviors/tidewater_stream.gd\",\"res://resources/icons/tower_icons/tidewater_stream.tres\",\"res://src/towers/tower_sprites/tidewater_stream_1.tscn\",\"YQ8G\",\"4ML0\"\r\n\"Witch Doctor\",1,114,114,\"SirCoqalot.\",\"unique\",\"astral\",\"TRUE\",\"elemental\",800,2,4756,4756,40,1.5,4600,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03|MOD_DAMAGE_BASE_PERC,0,0.08\",\"99,100\",,\"35\",\"res://src/towers/tower_behaviors/witch_doctor.gd\",\"res://resources/icons/tower_icons/witch_doctor.tres\",\"res://src/towers/tower_sprites/witch_doctor_1.tscn\",\"OW37\",\"41PY\"\r\n\"Spell Collector\",1,115,115,\"cedi\",\"rare\",\"storm\",\"TRUE\",\"energy\",950,2,1080,1080,0,0,1600,1000,0,\"FALSE\",\"CREEPS\",,,,,\"101\",\"18\",,\"res://src/towers/tower_behaviors/spell_collector.gd\",\"res://resources/icons/tower_icons/spell_collector.tres\",\"res://src/towers/tower_sprites/spell_collector_1.tscn\",\"DGYS\",\"3JUE\"\r\n\"Spell Harvester\",2,116,115,\"cedi\",\"rare\",\"storm\",\"TRUE\",\"energy\",950,2,2161,2161,0,0,3200,1000,0,\"FALSE\",\"CREEPS\",,,,,\"102\",\"19\",,\"res://src/towers/tower_behaviors/spell_collector.gd\",\"res://resources/icons/tower_icons/spell_collector.tres\",\"res://src/towers/tower_sprites/spell_collector_2.tscn\",\"WXC0\",\"3JUE\"\r\n\"Astral Lantern\",1,117,117,\"Velex\",\"common\",\"astral\",\"TRUE\",\"arcane\",750,2.2,90,95,0,0,35,1000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/astral_lantern.gd\",\"res://resources/icons/tower_icons/astral_lantern.tres\",\"res://src/towers/tower_sprites/astral_lantern_1.tscn\",\"15X6\",\"P8SF\"\r\n\"Astral Guide\",2,118,117,\"Velex\",\"common\",\"astral\",\"TRUE\",\"arcane\",750,2.2,996,1080,0,0,400,1000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/astral_lantern.gd\",\"res://resources/icons/tower_icons/astral_lantern.tres\",\"res://src/towers/tower_sprites/astral_lantern_2.tscn\",\"YYX2\",\"P8SF\"\r\n\"Astral Beacon\",3,119,117,\"Velex\",\"common\",\"astral\",\"TRUE\",\"arcane\",750,2.2,3251,3425,0,0,1300,1000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/astral_lantern.gd\",\"res://resources/icons/tower_icons/astral_lantern.tres\",\"res://src/towers/tower_sprites/astral_lantern_3.tscn\",\"STPG\",\"P8SF\"\r\n\"Astral Lighthouse\",4,120,117,\"Velex\",\"common\",\"astral\",\"TRUE\",\"arcane\",750,2.2,5985,6209,0,0,2400,1000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/astral_lantern.gd\",\"res://resources/icons/tower_icons/astral_lantern.tres\",\"res://src/towers/tower_sprites/astral_lantern_4.tscn\",\"LDZ7\",\"P8SF\"\r\n\"Afflicted Obelisk\",1,121,121,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",1000,1.2,136,236,0,0,300,1500,0,\"FALSE\",\"CREEPS\",,,,,\"103\",,,\"res://src/towers/tower_behaviors/afflicted_obelisk.gd\",\"res://resources/icons/tower_icons/afflicted_obelisk.tres\",\"res://src/towers/tower_sprites/afflicted_obelisk_1.tscn\",\"I45R\",\"GH66\"\r\n\"Afflicted Monument\",2,360,121,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",1000,1.17,523,623,0,0,1000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"104\",,,\"res://src/towers/tower_behaviors/afflicted_obelisk.gd\",\"res://resources/icons/tower_icons/afflicted_obelisk.tres\",\"res://src/towers/tower_sprites/afflicted_obelisk_2.tscn\",\"CSAD\",\"GH66\"\r\n\"Afflicted Altar\",3,361,121,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",1000,1.13,944,1044,0,0,1900,1500,0,\"FALSE\",\"CREEPS\",,,,,\"105\",,,\"res://src/towers/tower_behaviors/afflicted_obelisk.gd\",\"res://resources/icons/tower_icons/afflicted_obelisk.tres\",\"res://src/towers/tower_sprites/afflicted_obelisk_3.tscn\",\"UEEF\",\"GH66\"\r\n\"Afflicted Shrine\",4,362,121,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",1000,1.1,1393,1493,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"106\",,,\"res://src/towers/tower_behaviors/afflicted_obelisk.gd\",\"res://resources/icons/tower_icons/afflicted_obelisk.tres\",\"res://src/towers/tower_sprites/afflicted_obelisk_4.tscn\",\"VEPX\",\"GH66\"\r\n\"Ball Lightning Accelerator\",1,123,123,\"cedi\",\"unique\",\"iron\",\"TRUE\",\"arcane\",1000,0.8,1,1,1000,8,2200,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,50|MOD_MANA_REGEN,0,1\",\"107\",,\"36\",\"res://src/towers/tower_behaviors/ball_lightning_accelerator.gd\",\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"res://src/towers/tower_sprites/ball_lightning_accelerator_1.tscn\",\"C2SC\",\"S41R\"\r\n\"Electric Death\",2,124,123,\"cedi\",\"unique\",\"iron\",\"TRUE\",\"arcane\",1000,0.7,1,1,2000,16,4400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,100|MOD_MANA_REGEN,0,3\",\"108\",,\"37\",\"res://src/towers/tower_behaviors/ball_lightning_accelerator.gd\",\"res://resources/icons/tower_icons/ball_lightning_accelerator.tres\",\"res://src/towers/tower_sprites/ball_lightning_accelerator_2.tscn\",\"CKI9\",\"4AFE\"\r\n\"Abandoned Pit\",1,125,125,\"drol\",\"common\",\"iron\",\"TRUE\",\"decay\",900,1.85,107,118,0,0,60,1500,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.005\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abandoned_pit.tres\",\"res://src/towers/tower_sprites/abandoned_pit_1.tscn\",\"2UZV\",\"GD6V\"\r\n\"Digging Hole\",2,126,125,\"drol\",\"common\",\"iron\",\"TRUE\",\"decay\",900,1.85,508,542,0,0,280,1500,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.006\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abandoned_pit.tres\",\"res://src/towers/tower_sprites/abandoned_pit_2.tscn\",\"C4LQ\",\"GD6V\"\r\n\"Small Quarry\",3,127,125,\"drol\",\"common\",\"iron\",\"TRUE\",\"decay\",900,1.85,1417,1488,0,0,775,1500,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.007\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abandoned_pit.tres\",\"res://src/towers/tower_sprites/abandoned_pit_3.tscn\",\"NFU9\",\"GD6V\"\r\n\"Mining Grounds\",4,128,125,\"drol\",\"common\",\"iron\",\"TRUE\",\"decay\",900,1.85,2534,2659,0,0,1400,1500,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.008\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abandoned_pit.tres\",\"res://src/towers/tower_sprites/abandoned_pit_4.tscn\",\"G1DV\",\"GD6V\"\r\n\"Gold Mine\",5,129,125,\"drol\",\"common\",\"iron\",\"TRUE\",\"decay\",900,1.85,4391,4693,0,0,2450,1500,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.009\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abandoned_pit.tres\",\"res://src/towers/tower_sprites/abandoned_pit_5.tscn\",\"NG0J\",\"GD6V\"\r\n\"Storm Focus\",1,130,130,\"SirCoqalot.\",\"unique\",\"storm\",\"TRUE\",\"energy\",1600,3,9222,14222,20,1.5,2800,1500,0,\"FALSE\",\"CREEPS,SIZE_AIR\",,,,\"MOD_DMG_TO_AIR,0.1,0\",,\"20\",\"38\",\"res://src/towers/tower_behaviors/storm_focus.gd\",\"res://resources/icons/tower_icons/storm_focus.tres\",\"res://src/towers/tower_sprites/storm_focus_1.tscn\",\"V8DH\",\"W883\"\r\n\"Genis Sage\",1,131,131,\"i_m0ck_death\",\"unique\",\"ice\",\"TRUE\",\"energy\",900,1.5,1892,1892,200,3,3500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"109,110,111,112\",,,\"res://src/towers/tower_behaviors/genis_sage.gd\",\"res://resources/icons/tower_icons/genis_sage.tres\",\"res://src/towers/tower_sprites/genis_sage_1.tscn\",\"37BS\",\"AGYA\"\r\n\"Chaos Warlock\",1,132,132,\"SirCoqalot.\",\"unique\",\"darkness\",\"TRUE\",\"essence\",890,3,1752,1753,0,0,2800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"113\",,\"39\",\"res://src/towers/tower_behaviors/chaos_warlock.gd\",\"res://resources/icons/tower_icons/chaos_warlock.tres\",\"res://src/towers/tower_sprites/chaos_warlock_1.tscn\",\"J90C\",\"3QVL\"\r\n\"Chaos Diabolist\",2,133,132,\"SirCoqalot.\",\"unique\",\"darkness\",\"TRUE\",\"essence\",890,3,2879,2880,0,0,4600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"114\",\"21\",\"40\",\"res://src/towers/tower_behaviors/chaos_warlock.gd\",\"res://resources/icons/tower_icons/chaos_warlock.tres\",\"res://src/towers/tower_sprites/chaos_warlock_2.tscn\",\"TK03\",\"3QVL\"\r\n\"Lesser Elemental Ghost\",1,134,134,\"Der_kleine_Tomy\",\"uncommon\",\"fire\",\"TRUE\",\"essence\",950,2,329,329,0,0,180,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_TRIGGER_CHANCES,0,0.005\",\"115,116\",,,\"res://src/towers/tower_behaviors/lesser_elemental_ghost.gd\",\"res://resources/icons/tower_icons/lesser_elemental_ghost.tres\",\"res://src/towers/tower_sprites/lesser_elemental_ghost_1.tscn\",\"4ZBB\",\"1UWL\"\r\n\"Elemental Ghost\",2,138,134,\"Der_kleine_Tomy\",\"uncommon\",\"fire\",\"TRUE\",\"essence\",950,2,838,838,0,0,470,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_TRIGGER_CHANCES,0,0.006\",\"117,118\",,,\"res://src/towers/tower_behaviors/lesser_elemental_ghost.gd\",\"res://resources/icons/tower_icons/lesser_elemental_ghost.tres\",\"res://src/towers/tower_sprites/lesser_elemental_ghost_2.tscn\",\"UH4V\",\"1UWL\"\r\n\"Greater Elemental Ghost\",3,135,134,\"Der_kleine_Tomy\",\"uncommon\",\"fire\",\"TRUE\",\"essence\",950,2,2001,2001,0,0,1150,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_TRIGGER_CHANCES,0,0.007\",\"119,120\",,,\"res://src/towers/tower_behaviors/lesser_elemental_ghost.gd\",\"res://resources/icons/tower_icons/lesser_elemental_ghost.tres\",\"res://src/towers/tower_sprites/lesser_elemental_ghost_3.tscn\",\"CHGD\",\"1UWL\"\r\n\"Mighty Elemental Ghost\",4,136,134,\"Der_kleine_Tomy\",\"uncommon\",\"fire\",\"TRUE\",\"essence\",950,2,3225,3225,0,0,1900,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_TRIGGER_CHANCES,0,0.008\",\"121,122\",,,\"res://src/towers/tower_behaviors/lesser_elemental_ghost.gd\",\"res://resources/icons/tower_icons/lesser_elemental_ghost.tres\",\"res://src/towers/tower_sprites/lesser_elemental_ghost_4.tscn\",\"JYSB\",\"1UWL\"\r\n\"Almighty Elemental Ghost\",5,137,134,\"Der_kleine_Tomy\",\"uncommon\",\"fire\",\"TRUE\",\"essence\",950,2,4715,4715,0,0,2850,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_TRIGGER_CHANCES,0,0.009\",\"123,124\",,,\"res://src/towers/tower_behaviors/lesser_elemental_ghost.gd\",\"res://resources/icons/tower_icons/lesser_elemental_ghost.tres\",\"res://src/towers/tower_sprites/lesser_elemental_ghost_5.tscn\",\"50EF\",\"1UWL\"\r\n\"Crimson Wyrm\",1,139,139,\"SirCoqalot.\",\"unique\",\"fire\",\"TRUE\",\"elemental\",950,2,90,10099,0,0,4800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"125,126\",,,\"res://src/towers/tower_behaviors/crimson_wyrm.gd\",\"res://resources/icons/tower_icons/crimson_wyrm.tres\",\"res://src/towers/tower_sprites/crimson_wyrm_1.tscn\",\"BQFY\",\"WTMA\"\r\n\"Vulshok, the Berserker\",1,140,140,\"Boekie\",\"unique\",\"fire\",\"TRUE\",\"physical\",1000,0.64,900,900,0,0,2400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_DAMAGE,0.75,0|MOD_ATTACKSPEED,0,0.03\",\"127,128\",,,\"res://src/towers/tower_behaviors/vulshok_the_berserker.gd\",\"res://resources/icons/tower_icons/vulshok_the_berserker.tres\",\"res://src/towers/tower_sprites/vulshok_the_berserker_1.tscn\",\"S8O4\",\"5ERT\"\r\n\"Gatling Gun\",1,141,141,\"Boekie\",\"unique\",\"iron\",\"TRUE\",\"physical\",1000,1,795,795,0,0,2750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.0875,0.005\",\"129,130\",,,\"res://src/towers/tower_behaviors/gatling_gun.gd\",\"res://resources/icons/tower_icons/gatling_gun.tres\",\"res://src/towers/tower_sprites/gatling_gun_1.tscn\",\"AXVT\",\"0RVF\"\r\n\"Baby Tuskin\",1,142,142,\"Palandu\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.9,1008,1008,0,0,535,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_CHAMPION,0.08,0.006|MOD_DMG_TO_BOSS,0.1,0.01|MOD_DMG_TO_AIR,-0.2,0\",\"131\",,,\"res://src/towers/tower_behaviors/baby_tuskin.gd\",\"res://resources/icons/tower_icons/baby_tuskin.tres\",\"res://src/towers/tower_sprites/baby_tuskin_1.tscn\",\"CSFY\",\"M6QV\"\r\n\"Teenage Tuskin\",2,143,142,\"Palandu\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.9,2403,2403,0,0,1350,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_CHAMPION,0.1,0.007|MOD_DMG_TO_BOSS,0.125,0.012|MOD_DMG_TO_AIR,-0.2,0\",\"132\",,,\"res://src/towers/tower_behaviors/baby_tuskin.gd\",\"res://resources/icons/tower_icons/baby_tuskin.tres\",\"res://src/towers/tower_sprites/baby_tuskin_2.tscn\",\"D2NR\",\"HKJL\"\r\n\"Fully Grown Tuskin\",3,144,142,\"Palandu\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.9,4918,4918,0,0,2900,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_CHAMPION,0.12,0.008|MOD_DMG_TO_BOSS,0.15,0.014|MOD_DMG_TO_AIR,-0.2,0\",\"133\",,,\"res://src/towers/tower_behaviors/baby_tuskin.gd\",\"res://resources/icons/tower_icons/baby_tuskin.tres\",\"res://src/towers/tower_sprites/baby_tuskin_3.tscn\",\"T7CP\",\"82V3\"\r\n\"Harpy Witch\",1,145,145,\"drol\",\"rare\",\"storm\",\"TRUE\",\"energy\",1000,2.5,1832,1994,30,2,1350,1500,0.1,\"FALSE\",\"CREEPS\",,,\"2,0.25\",,\"134\",,\"41\",\"res://src/towers/tower_behaviors/harpy_witch.gd\",\"res://resources/icons/tower_icons/harpy_witch.tres\",\"res://src/towers/tower_sprites/harpy_witch_1.tscn\",\"TW9X\",\"T756\"\r\n\"Harpy Queen\",2,146,145,\"drol\",\"rare\",\"storm\",\"TRUE\",\"energy\",1000,2.5,3107,3269,30,2,2700,1500,0.1,\"FALSE\",\"CREEPS\",,,\"2,0.25\",,\"135\",,\"42\",\"res://src/towers/tower_behaviors/harpy_witch.gd\",\"res://resources/icons/tower_icons/harpy_witch.tres\",\"res://src/towers/tower_sprites/harpy_witch_2.tscn\",\"G32J\",\"T756\"\r\n\"Little Phoenix\",1,147,147,\"Der_kleine_Tomy\",\"rare\",\"fire\",\"TRUE\",\"elemental\",850,2.5,832,832,0,0,700,800,0.4,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,0.2,0.01\",\"136,137,138\",,\"43\",\"res://src/towers/tower_behaviors/little_phoenix.gd\",\"res://resources/icons/tower_icons/little_phoenix.tres\",\"res://src/towers/tower_sprites/little_phoenix_1.tscn\",\"TDB2\",\"51LJ\"\r\n\"Phoenix\",2,148,147,\"Der_kleine_Tomy\",\"rare\",\"fire\",\"TRUE\",\"elemental\",850,2.5,1307,1307,0,0,1650,800,0.4,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,0.2,0.01\",\"139,140,141\",,\"44\",\"res://src/towers/tower_behaviors/little_phoenix.gd\",\"res://resources/icons/tower_icons/little_phoenix.tres\",\"res://src/towers/tower_sprites/little_phoenix_2.tscn\",\"I2K1\",\"51LJ\"\r\n\"Mighty Phoenix\",3,149,147,\"Der_kleine_Tomy\",\"rare\",\"fire\",\"TRUE\",\"elemental\",850,2.5,1659,1659,0,0,2800,800,0.4,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,0.2,0.01\",\"142,143,144\",,\"45\",\"res://src/towers/tower_behaviors/little_phoenix.gd\",\"res://resources/icons/tower_icons/little_phoenix.tres\",\"res://src/towers/tower_sprites/little_phoenix_3.tscn\",\"P4PS\",\"51LJ\"\r\n\"Frost Root\",1,150,150,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",750,0.75,17,21,0,0,30,1700,0.1,\"FALSE\",\"CREEPS\",,,,,\"145\",,,\"res://src/towers/tower_behaviors/frost_root.gd\",\"res://resources/icons/tower_icons/frost_root.tres\",\"res://src/towers/tower_sprites/frost_root_1.tscn\",\"Z8I7\",\"ATFH\"\r\n\"Ice Weed\",2,151,150,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",750,0.75,48,67,0,0,100,1700,0.1,\"FALSE\",\"CREEPS\",,,,,\"146\",,,\"res://src/towers/tower_behaviors/frost_root.gd\",\"res://resources/icons/tower_icons/frost_root.tres\",\"res://src/towers/tower_sprites/frost_root_2.tscn\",\"IP83\",\"ATFH\"\r\n\"Frozen Vines\",3,152,150,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",750,0.75,146,195,0,0,300,1700,0.1,\"FALSE\",\"CREEPS\",,,,,\"147\",,,\"res://src/towers/tower_behaviors/frost_root.gd\",\"res://resources/icons/tower_icons/frost_root.tres\",\"res://src/towers/tower_sprites/frost_root_3.tscn\",\"X9DI\",\"ATFH\"\r\n\"Crystalized Tendrils\",4,153,150,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",750,0.75,291,390,0,0,600,1700,0.1,\"FALSE\",\"CREEPS\",,,,,\"148\",,,\"res://src/towers/tower_behaviors/frost_root.gd\",\"res://resources/icons/tower_icons/frost_root.tres\",\"res://src/towers/tower_sprites/frost_root_4.tscn\",\"UBAX\",\"ATFH\"\r\n\"Glacial Creeper\",5,154,150,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",750,0.75,592,766,0,0,1200,1700,0.1,\"FALSE\",\"CREEPS\",,,,,\"149\",,,\"res://src/towers/tower_behaviors/frost_root.gd\",\"res://resources/icons/tower_icons/frost_root.tres\",\"res://src/towers/tower_sprites/frost_root_5.tscn\",\"RJNS\",\"ATFH\"\r\n\"Polar Ivy\",6,155,150,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",750,0.75,1020,1244,0,0,2000,1700,0.1,\"FALSE\",\"CREEPS\",,,,,\"150\",,,\"res://src/towers/tower_behaviors/frost_root.gd\",\"res://resources/icons/tower_icons/frost_root.tres\",\"res://src/towers/tower_sprites/frost_root_6.tscn\",\"PBHG\",\"ATFH\"\r\n\"Ruined Wind Tower\",1,156,156,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1000,2.8,1343,1393,0,0,400,1500,0,\"FALSE\",\"CREEPS\",,,,,\"151\",,,\"res://src/towers/tower_behaviors/ruined_wind_tower.gd\",\"res://resources/icons/tower_icons/ruined_wind_tower.tres\",\"res://src/towers/tower_sprites/ruined_wind_tower_1.tscn\",\"16MG\",\"JJ2N\"\r\n\"Ruined Storm Tower\",2,341,156,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1000,2.8,3409,3459,0,0,975,1500,0,\"FALSE\",\"CREEPS\",,,,,\"152\",,,\"res://src/towers/tower_behaviors/ruined_wind_tower.gd\",\"res://resources/icons/tower_icons/ruined_wind_tower.tres\",\"res://src/towers/tower_sprites/ruined_wind_tower_2.tscn\",\"QWGP\",\"JJ2N\"\r\n\"Ruined Tempest Tower\",3,342,156,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1000,2.8,6683,6733,0,0,1850,1500,0,\"FALSE\",\"CREEPS\",,,,,\"153\",,,\"res://src/towers/tower_behaviors/ruined_wind_tower.gd\",\"res://resources/icons/tower_icons/ruined_wind_tower.tres\",\"res://src/towers/tower_sprites/ruined_wind_tower_3.tscn\",\"KKLM\",\"JJ2N\"\r\n\"Ruined Hurricane Tower\",4,343,156,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1000,2.8,9859,9909,0,0,2650,1500,0,\"FALSE\",\"CREEPS\",,,,,\"154\",,,\"res://src/towers/tower_behaviors/ruined_wind_tower.gd\",\"res://resources/icons/tower_icons/ruined_wind_tower.tres\",\"res://src/towers/tower_sprites/ruined_wind_tower_4.tscn\",\"9DPG\",\"JJ2N\"\r\n\"Gryphon Rider\",1,157,157,\"cedi\",\"unique\",\"storm\",\"TRUE\",\"energy\",900,2,5040,5050,55,2,3050,1800,0.15,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.08\",\"155,156\",,\"46\",\"res://src/towers/tower_behaviors/gryphon_rider.gd\",\"res://resources/icons/tower_icons/gryphon_rider.tres\",\"res://src/towers/tower_sprites/gryphon_rider_1.tscn\",\"3F3D\",\"3TIY\"\r\n\"Xeno Research Facility\",1,158,158,\"Palandu\",\"unique\",\"iron\",\"TRUE\",\"physical\",1200,1.8,1812,1812,0,0,1984,1500,0,\"FALSE\",\"CREEPS\",,,,,\"157\",\"22\",,\"res://src/towers/tower_behaviors/xeno_research_facility.gd\",\"res://resources/icons/tower_icons/xeno_research_facility.tres\",\"res://src/towers/tower_sprites/xeno_research_facility_1.tscn\",\"8S3S\",\"NM2Y\"\r\n\"The Omnislasher\",1,159,159,\"KublaiKhan1\",\"unique\",\"fire\",\"TRUE\",\"physical\",1200,5,7109,7109,0,0,3400,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.1\",\"158\",,,\"res://src/towers/tower_behaviors/the_omnislasher.gd\",\"res://resources/icons/tower_icons/the_omnislasher.tres\",\"res://src/towers/tower_sprites/the_omnislasher_1.tscn\",\"HXOR\",\"438G\"\r\n\"Sorceress\",1,160,160,\"cedi\",\"unique\",\"astral\",\"TRUE\",\"arcane\",1200,3,5760,5771,0,0,3800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"159\",,\"47,48,49\",\"res://src/towers/tower_behaviors/sorceress.gd\",\"res://resources/icons/tower_icons/sorceress.tres\",\"res://src/towers/tower_sprites/sorceress_1.tscn\",\"HSWI\",\"YQN1\"\r\n\"Mossy Acid Sprayer\",1,161,161,\"cedi\",\"common\",\"iron\",\"TRUE\",\"decay\",800,1,11,31,0,0,40,1500,0.15,\"FALSE\",\"CREEPS\",,,\"3,0.15\",,\"160\",,,\"res://src/towers/tower_behaviors/mossy_acid_sprayer.gd\",\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"res://src/towers/tower_sprites/mossy_acid_sprayer_1.tscn\",\"D4JR\",\"LFP7\"\r\n\"Toxic Mossy Acid Sprayer\",2,162,161,\"cedi\",\"common\",\"iron\",\"TRUE\",\"decay\",800,1,70,90,0,0,160,1500,0.15,\"FALSE\",\"CREEPS\",,,\"3,0.15\",,\"161\",,,\"res://src/towers/tower_behaviors/mossy_acid_sprayer.gd\",\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"res://src/towers/tower_sprites/mossy_acid_sprayer_2.tscn\",\"BIMI\",\"LFP7\"\r\n\"Toxic Acid Factory\",3,163,161,\"cedi\",\"common\",\"iron\",\"TRUE\",\"decay\",800,1,223,243,0,0,400,1500,0.15,\"FALSE\",\"CREEPS\",,,\"3,0.15\",,\"162\",,,\"res://src/towers/tower_behaviors/mossy_acid_sprayer.gd\",\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"res://src/towers/tower_sprites/mossy_acid_sprayer_3.tscn\",\"T6UN\",\"LFP7\"\r\n\"Mutating Acid Factory\",4,164,161,\"cedi\",\"common\",\"iron\",\"TRUE\",\"decay\",800,1,452,472,0,0,1000,1500,0.15,\"FALSE\",\"CREEPS\",,,\"3,0.15\",,\"163\",,,\"res://src/towers/tower_behaviors/mossy_acid_sprayer.gd\",\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"res://src/towers/tower_sprites/mossy_acid_sprayer_4.tscn\",\"Q985\",\"LFP7\"\r\n\"Infested Mutating Acid Factory\",5,337,161,\"cedi\",\"common\",\"iron\",\"TRUE\",\"decay\",800,1,879,899,0,0,2000,1500,0.15,\"FALSE\",\"CREEPS\",,,\"3,0.15\",,\"164\",,,\"res://src/towers/tower_behaviors/mossy_acid_sprayer.gd\",\"res://resources/icons/tower_icons/mossy_acid_sprayer.tres\",\"res://src/towers/tower_sprites/mossy_acid_sprayer_5.tscn\",\"5FIG\",\"LFP7\"\r\n\"Undisturbed Crypt\",1,165,165,\"eMoo\",\"rare\",\"darkness\",\"TRUE\",\"decay\",1000,1.95,696,696,0,0,600,1000,0,\"FALSE\",\"CREEPS\",,,,,\"165,166\",,,\"res://src/towers/tower_behaviors/undisturbed_crypt.gd\",\"res://resources/icons/tower_icons/undisturbed_crypt.tres\",\"res://src/towers/tower_sprites/undisturbed_crypt_1.tscn\",\"CJPH\",\"YLI9\"\r\n\"Forsaken Crypt\",2,171,165,\"eMoo\",\"rare\",\"darkness\",\"TRUE\",\"decay\",1000,1.95,1481,1481,0,0,1300,1000,0,\"FALSE\",\"CREEPS\",,,,,\"167,168\",,,\"res://src/towers/tower_behaviors/undisturbed_crypt.gd\",\"res://resources/icons/tower_icons/undisturbed_crypt.tres\",\"res://src/towers/tower_sprites/undisturbed_crypt_2.tscn\",\"L7EF\",\"YLI9\"\r\n\"Undeathly Crypt\",3,172,165,\"eMoo\",\"rare\",\"darkness\",\"TRUE\",\"decay\",1000,1.95,2413,2413,0,0,2200,1000,0,\"FALSE\",\"CREEPS\",,,,,\"169,170\",,,\"res://src/towers/tower_behaviors/undisturbed_crypt.gd\",\"res://resources/icons/tower_icons/undisturbed_crypt.tres\",\"res://src/towers/tower_sprites/undisturbed_crypt_3.tscn\",\"I472\",\"YLI9\"\r\n\"Unforgiving Crypt\",4,173,165,\"eMoo\",\"rare\",\"darkness\",\"TRUE\",\"decay\",1000,1.95,3586,3586,0,0,3400,1000,0,\"FALSE\",\"CREEPS\",,,,,\"171,172\",,,\"res://src/towers/tower_behaviors/undisturbed_crypt.gd\",\"res://resources/icons/tower_icons/undisturbed_crypt.tres\",\"res://src/towers/tower_sprites/undisturbed_crypt_4.tscn\",\"CHQB\",\"YLI9\"\r\n\"Haunted Rubble\",1,166,166,\"Velex\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,2,61,62,0,0,34,900,0.6,\"FALSE\",\"CREEPS\",,,,,\"173\",,,\"res://src/towers/tower_behaviors/haunted_rubble.gd\",\"res://resources/icons/tower_icons/haunted_rubble.tres\",\"res://src/towers/tower_sprites/haunted_rubble_1.tscn\",\"58FI\",\"71SH\"\r\n\"Haunted Debris\",2,271,166,\"Velex\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,2,368,369,0,0,204,900,0.6,\"FALSE\",\"CREEPS\",,,,,\"174\",,,\"res://src/towers/tower_behaviors/haunted_rubble.gd\",\"res://resources/icons/tower_icons/haunted_rubble.tres\",\"res://src/towers/tower_sprites/haunted_rubble_2.tscn\",\"90WL\",\"71SH\"\r\n\"Haunted Ruins\",3,270,166,\"Velex\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,2,1020,1021,0,0,566,900,0.6,\"FALSE\",\"CREEPS\",,,,,\"175\",,,\"res://src/towers/tower_behaviors/haunted_rubble.gd\",\"res://resources/icons/tower_icons/haunted_rubble.tres\",\"res://src/towers/tower_sprites/haunted_rubble_3.tscn\",\"2EI7\",\"71SH\"\r\n\"Haunted Silo\",4,269,166,\"Velex\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,2,2433,2434,0,0,1350,900,0.6,\"FALSE\",\"CREEPS\",,,,,\"176\",,,\"res://src/towers/tower_behaviors/haunted_rubble.gd\",\"res://resources/icons/tower_icons/haunted_rubble.tres\",\"res://src/towers/tower_sprites/haunted_rubble_4.tscn\",\"Q3OG\",\"71SH\"\r\n\"Haunted Soul Mill\",5,268,166,\"Velex\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,2,3966,3967,0,0,2200,900,0.6,\"FALSE\",\"CREEPS\",,,,,\"177\",,,\"res://src/towers/tower_behaviors/haunted_rubble.gd\",\"res://resources/icons/tower_icons/haunted_rubble.tres\",\"res://src/towers/tower_sprites/haunted_rubble_5.tscn\",\"RMMO\",\"71SH\"\r\n\"Lightning Eye\",1,167,167,\"i_m0ck_death\",\"unique\",\"storm\",\"TRUE\",\"energy\",800,1.5,1757,1757,200,4,3000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,-0.1,0\",\"178\",\"23\",,\"res://src/towers/tower_behaviors/lightning_eye.gd\",\"res://resources/icons/tower_icons/lightning_eye.tres\",\"res://src/towers/tower_sprites/lightning_eye_1.tscn\",\"LT77\",\"CNY6\"\r\n\"Tentacle Spawn\",1,169,169,\"drol\",\"common\",\"darkness\",\"TRUE\",\"physical\",850,1.5,65,76,0,0,60,1600,0,\"FALSE\",\"CREEPS\",,,,,\"179\",,,\"res://src/towers/tower_behaviors/tentacle_spawn.gd\",\"res://resources/icons/tower_icons/tentacle_spawn.tres\",\"res://src/towers/tower_sprites/tentacle_spawn_1.tscn\",\"20BK\",\"ND83\"\r\n\"Tentacle\",2,612,169,\"drol\",\"common\",\"darkness\",\"TRUE\",\"physical\",850,1.5,176,235,0,0,180,1600,0,\"FALSE\",\"CREEPS\",,,,,\"180\",,,\"res://src/towers/tower_behaviors/tentacle_spawn.gd\",\"res://resources/icons/tower_icons/tentacle_spawn.tres\",\"res://src/towers/tower_sprites/tentacle_spawn_2.tscn\",\"665Z\",\"ND83\"\r\n\"Starving Tentacle\",3,613,169,\"drol\",\"common\",\"darkness\",\"TRUE\",\"physical\",850,1.5,345,464,0,0,360,1600,0,\"FALSE\",\"CREEPS\",,,,,\"181\",,,\"res://src/towers/tower_behaviors/tentacle_spawn.gd\",\"res://resources/icons/tower_icons/tentacle_spawn.tres\",\"res://src/towers/tower_sprites/tentacle_spawn_3.tscn\",\"5ORT\",\"ND83\"\r\n\"Rending Tentacle\",4,614,169,\"drol\",\"common\",\"darkness\",\"TRUE\",\"physical\",850,1.5,679,918,0,0,720,1600,0,\"FALSE\",\"CREEPS\",,,,,\"182\",,,\"res://src/towers/tower_behaviors/tentacle_spawn.gd\",\"res://resources/icons/tower_icons/tentacle_spawn.tres\",\"res://src/towers/tower_sprites/tentacle_spawn_4.tscn\",\"HQF9\",\"ND83\"\r\n\"Revenging Tentacle\",5,615,169,\"drol\",\"common\",\"darkness\",\"TRUE\",\"physical\",850,1.5,1334,1813,0,0,1440,1600,0,\"FALSE\",\"CREEPS\",,,,,\"183\",,,\"res://src/towers/tower_behaviors/tentacle_spawn.gd\",\"res://resources/icons/tower_icons/tentacle_spawn.tres\",\"res://src/towers/tower_sprites/tentacle_spawn_5.tscn\",\"XCZ1\",\"ND83\"\r\n\"Giant Tentacle\",6,616,169,\"drol\",\"common\",\"darkness\",\"TRUE\",\"physical\",850,1.5,2267,3082,0,0,2448,1600,0,\"FALSE\",\"CREEPS\",,,,,\"184\",,,\"res://src/towers/tower_behaviors/tentacle_spawn.gd\",\"res://resources/icons/tower_icons/tentacle_spawn.tres\",\"res://src/towers/tower_sprites/tentacle_spawn_6.tscn\",\"DELC\",\"ND83\"\r\n\"Wild Warbeast\",1,170,170,\"SirCoqalot.\",\"unique\",\"nature\",\"TRUE\",\"decay\",800,2,1361,2361,0,0,2700,20000,0,\"TRUE\",\"CREEPS\",,,,,\"185\",\"24\",,\"res://src/towers/tower_behaviors/wild_warbeast.gd\",\"res://resources/icons/tower_icons/wild_warbeast.tres\",\"res://src/towers/tower_sprites/wild_warbeast_1.tscn\",\"VCX1\",\"QOUG\"\r\n\"Village Witch\",1,183,183,\"cedi\",\"uncommon\",\"darkness\",\"TRUE\",\"essence\",1100,1.6,135,135,30,1.5,150,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,1|MOD_MANA_REGEN,0,0.1\",\"186\",,\"50\",\"res://src/towers/tower_behaviors/village_witch.gd\",\"res://resources/icons/tower_icons/village_witch.tres\",\"res://src/towers/tower_sprites/village_witch_1.tscn\",\"2E5N\",\"KKNS\"\r\n\"Adept Witch\",2,375,183,\"cedi\",\"uncommon\",\"darkness\",\"TRUE\",\"essence\",1100,1.6,538,538,30,1.5,600,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,1|MOD_MANA_REGEN,0,0.1\",\"187\",,\"51\",\"res://src/towers/tower_behaviors/village_witch.gd\",\"res://resources/icons/tower_icons/village_witch.tres\",\"res://src/towers/tower_sprites/village_witch_2.tscn\",\"KUQL\",\"VP4D\"\r\n\"Skilled Witch\",3,184,183,\"cedi\",\"uncommon\",\"darkness\",\"TRUE\",\"essence\",1100,1.6,1076,1076,30,1.5,1200,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,1|MOD_MANA_REGEN,0,0.1\",\"188\",,\"52\",\"res://src/towers/tower_behaviors/village_witch.gd\",\"res://resources/icons/tower_icons/village_witch.tres\",\"res://src/towers/tower_sprites/village_witch_3.tscn\",\"BZWY\",\"4EOA\"\r\n\"Witch Queen\",4,185,183,\"cedi\",\"uncommon\",\"darkness\",\"TRUE\",\"essence\",1100,1.6,2153,2153,30,1.5,2400,1100,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,1|MOD_MANA_REGEN,0,0.1\",\"189\",,\"53\",\"res://src/towers/tower_behaviors/village_witch.gd\",\"res://resources/icons/tower_icons/village_witch.tres\",\"res://src/towers/tower_sprites/village_witch_4.tscn\",\"VGKA\",\"5BQS\"\r\n\"Burrow\",1,186,186,\"tolleder\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",700,3,289,289,0,0,70,1500,0,\"FALSE\",\"CREEPS\",,,,,\"190\",,,\"res://src/towers/tower_behaviors/burrow.gd\",\"res://resources/icons/tower_icons/burrow.tres\",\"res://src/towers/tower_sprites/burrow_1.tscn\",\"XB4X\",\"B1OU\"\r\n\"Reinforced Burrow\",2,189,186,\"tolleder\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",700,3,1546,1546,0,0,400,1500,0,\"FALSE\",\"CREEPS\",,,,,\"191\",,,\"res://src/towers/tower_behaviors/burrow.gd\",\"res://resources/icons/tower_icons/burrow.tres\",\"res://src/towers/tower_sprites/burrow_2.tscn\",\"SXDC\",\"KJ6S\"\r\n\"Fortified Burrow\",3,187,186,\"tolleder\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",700,3,4274,4274,0,0,1200,1500,0,\"FALSE\",\"CREEPS\",,,,,\"192\",,,\"res://src/towers/tower_behaviors/burrow.gd\",\"res://resources/icons/tower_icons/burrow.tres\",\"res://src/towers/tower_sprites/burrow_3.tscn\",\"G0BT\",\"B3NM\"\r\n\"Magic Enhanced Burrow\",4,188,186,\"tolleder\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",700,3,8035,8035,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"193\",,,\"res://src/towers/tower_behaviors/burrow.gd\",\"res://resources/icons/tower_icons/burrow.tres\",\"res://src/towers/tower_sprites/burrow_4.tscn\",\"Z4W1\",\"49ET\"\r\n\"Owl of Wisdom\",1,190,190,\"Der_kleine_Tomy\",\"unique\",\"astral\",\"TRUE\",\"energy\",900,2,1756,1756,0,0,2300,1000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_SPELL_CRIT_CHANCE,0.0375,0.0015|MOD_SPELL_DAMAGE_DEALT,0,0.01\",\"194,195,196\",,,\"res://src/towers/tower_behaviors/owl_of_wisdom.gd\",\"res://resources/icons/tower_icons/owl_of_wisdom.tres\",\"res://src/towers/tower_sprites/owl_of_wisdom_1.tscn\",\"4N7Y\",\"MT9R\"\r\n\"Ancient Owl of Wisdom\",2,191,190,\"Der_kleine_Tomy\",\"unique\",\"astral\",\"TRUE\",\"energy\",900,2,2977,2977,0,0,3900,1000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_SPELL_CRIT_CHANCE,0.0375,0.0015|MOD_SPELL_DAMAGE_DEALT,0,0.01\",\"197,198,199\",,,\"res://src/towers/tower_behaviors/owl_of_wisdom.gd\",\"res://resources/icons/tower_icons/owl_of_wisdom.tres\",\"res://src/towers/tower_sprites/owl_of_wisdom_2.tscn\",\"HZ37\",\"MT9R\"\r\n\"Zealot\",1,192,192,\"dzk87\",\"rare\",\"storm\",\"TRUE\",\"physical\",875,2,1051,1161,0,0,500,1800,0.05,\"FALSE\",\"CREEPS\",,,,,\"200,201,202\",,,\"res://src/towers/tower_behaviors/zealot.gd\",\"res://resources/icons/tower_icons/zealot.tres\",\"res://src/towers/tower_sprites/zealot_1.tscn\",\"1K8O\",\"35GJ\"\r\n\"Devoted Zealot\",2,193,192,\"dzk87\",\"rare\",\"storm\",\"TRUE\",\"physical\",875,2,2371,2554,0,0,1150,1800,0,\"FALSE\",\"CREEPS\",,,,,\"203,204,205\",,,\"res://src/towers/tower_behaviors/zealot.gd\",\"res://resources/icons/tower_icons/zealot.tres\",\"res://src/towers/tower_sprites/zealot_2.tscn\",\"VNQ2\",\"35GJ\"\r\n\"Frenzied Zealot\",3,194,192,\"dzk87\",\"rare\",\"storm\",\"TRUE\",\"physical\",875,2,3798,4065,0,0,1900,1800,0,\"FALSE\",\"CREEPS\",,,,,\"206,207,208\",,,\"res://src/towers/tower_behaviors/zealot.gd\",\"res://resources/icons/tower_icons/zealot.tres\",\"res://src/towers/tower_sprites/zealot_3.tscn\",\"9NJY\",\"35GJ\"\r\n\"Fanatical Zealot\",4,195,192,\"dzk87\",\"rare\",\"storm\",\"TRUE\",\"physical\",875,2,5767,6219,0,0,3000,1800,0,\"FALSE\",\"CREEPS\",,,,,\"209,210,211\",,,\"res://src/towers/tower_behaviors/zealot.gd\",\"res://resources/icons/tower_icons/zealot.tres\",\"res://src/towers/tower_sprites/zealot_4.tscn\",\"SPZ5\",\"35GJ\"\r\n\"Void Drake\",1,196,196,\"Chronos\",\"rare\",\"darkness\",\"TRUE\",\"essence\",1000,1.35,3633,3965,0,0,2000,1500,0.1,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,-0.5,-0.06|MOD_ATTACKSPEED,0,0.04|MOD_DAMAGE_BASE_PERC,0,0.12\",\"212,213\",,,\"res://src/towers/tower_behaviors/void_drake.gd\",\"res://resources/icons/tower_icons/void_drake.tres\",\"res://src/towers/tower_sprites/void_drake_1.tscn\",\"X12A\",\"D5TM\"\r\n\"Void Dragon\",2,248,196,\"Chronos\",\"rare\",\"darkness\",\"TRUE\",\"essence\",1000,1.35,7769,8001,0,0,3500,1500,0.1,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,-0.8,-0.1|MOD_ATTACKSPEED,0,0.04|MOD_DAMAGE_BASE_PERC,0,0.2\",\"214,215\",,,\"res://src/towers/tower_behaviors/void_drake.gd\",\"res://resources/icons/tower_icons/void_drake.tres\",\"res://src/towers/tower_sprites/void_drake_2.tscn\",\"TWGC\",\"D5TM\"\r\n\"Solar Collector\",1,197,197,\"Boekie/D1000\",\"rare\",\"iron\",\"TRUE\",\"energy\",800,1,468,468,17,1.5,850,1500,0.1,\"FALSE\",\"CREEPS\",,,,\"MOD_SPELL_CRIT_CHANCE,0.0875,0.005|MOD_SPELL_CRIT_DAMAGE,0.75,0|MOD_MANA,0,1|MOD_MANA_REGEN,0,0.02\",\"216\",,\"54\",\"res://src/towers/tower_behaviors/solar_collector.gd\",\"res://resources/icons/tower_icons/solar_collector.tres\",\"res://src/towers/tower_sprites/solar_collector_1.tscn\",\"BRC3\",\"4G6X\"\r\n\"Solar Conductor\",2,198,197,\"Boekie/D1001\",\"rare\",\"iron\",\"TRUE\",\"energy\",800,1,1375,1375,17,3,2500,1500,0.1,\"FALSE\",\"CREEPS\",,,,\"MOD_SPELL_CRIT_CHANCE,0.0875,0.005|MOD_SPELL_CRIT_DAMAGE,0.75,0|MOD_MANA,0,2|MOD_MANA_REGEN,0,0.02\",\"217\",,\"55\",\"res://src/towers/tower_behaviors/solar_collector.gd\",\"res://resources/icons/tower_icons/solar_collector.tres\",\"res://src/towers/tower_sprites/solar_collector_2.tscn\",\"ODIL\",\"4G6X\"\r\n\"Zeus\",1,199,199,\"Boekie\",\"unique\",\"storm\",\"TRUE\",\"energy\",1200,2,2581,2600,100,1,2500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,5\",\"218,219\",,\"56\",\"res://src/towers/tower_behaviors/zeus.gd\",\"res://resources/icons/tower_icons/zeus.tres\",\"res://src/towers/tower_sprites/zeus_1.tscn\",\"DQYD\",\"0106\"\r\n\"Bonk, the Living Mountain\",1,200,200,\"Boekie\",\"unique\",\"nature\",\"TRUE\",\"physical\",750,3,3670,3670,0,0,2500,1000,0,\"FALSE\",\"CREEPS\",,\"100,1\",,\"MOD_DMG_TO_MASS,0.25,0.005\",\"220,221,222\",,,\"res://src/towers/tower_behaviors/bonk_the_living_mountain.gd\",\"res://resources/icons/tower_icons/bonk_the_living_mountain.tres\",\"res://src/towers/tower_sprites/bonk_the_living_mountain_1.tscn\",\"TQOT\",\"1KYG\"\r\n\"Marine\",1,201,201,\"Boekie\",\"rare\",\"iron\",\"TRUE\",\"decay\",1200,0.6,336,336,30,1.2,1500,2000,0,\"FALSE\",\"CREEPS\",,,,,\"223\",,\"57\",\"res://src/towers/tower_behaviors/marine.gd\",\"res://resources/icons/tower_icons/marine.tres\",\"res://src/towers/tower_sprites/marine_1.tscn\",\"190M\",\"AU49\"\r\n\"Experienced Marine\",2,294,201,\"Boekie\",\"rare\",\"iron\",\"TRUE\",\"decay\",1200,0.6,560,560,35,1.3,2500,2000,0,\"FALSE\",\"CREEPS\",,,,,\"224\",,\"58\",\"res://src/towers/tower_behaviors/marine.gd\",\"res://resources/icons/tower_icons/marine.tres\",\"res://src/towers/tower_sprites/marine_2.tscn\",\"DXCT\",\"A5V5\"\r\n\"Ancient Energy Converter\",1,202,202,\"geX\",\"unique\",\"storm\",\"TRUE\",\"energy\",1600,1.1,72,2472,1200,20,3500,900,0,\"FALSE\",\"CREEPS\",,,\"3,0.7\",\"MOD_MANA,0,25\",,,\"59\",\"res://src/towers/tower_behaviors/ancient_energy_converter.gd\",\"res://resources/icons/tower_icons/ancient_energy_converter.tres\",\"res://src/towers/tower_sprites/ancient_energy_converter_1.tscn\",\"YLHO\",\"3C06\"\r\n\"Caged Fire\",1,203,203,\"cedi\",\"rare\",\"fire\",\"TRUE\",\"elemental\",900,0.4,266,266,0,0,1750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,-0.5,0|MOD_DMG_TO_NATURE,0.5,0.01\",,\"25\",,\"res://src/towers/tower_behaviors/caged_fire.gd\",\"res://resources/icons/tower_icons/caged_fire.tres\",\"res://src/towers/tower_sprites/caged_fire_1.tscn\",\"WW0T\",\"9HGT\"\r\n\"Caged Inferno\",2,204,203,\"cedi\",\"rare\",\"fire\",\"TRUE\",\"elemental\",900,0.4,533,533,0,0,3500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,-0.5,0|MOD_DMG_TO_NATURE,0.5,0.01\",,\"26\",,\"res://src/towers/tower_behaviors/caged_fire.gd\",\"res://resources/icons/tower_icons/caged_fire.tres\",\"res://src/towers/tower_sprites/caged_fire_2.tscn\",\"HWLB\",\"9HGT\"\r\n\"Obelisk of Fortuity\",1,205,205,\"D1000\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1.5,62,66,0,0,30,1100,1,\"FALSE\",\"CREEPS\",,,,,\"225\",,,\"res://src/towers/tower_behaviors/obelisk_of_fortuity.gd\",\"res://resources/icons/tower_icons/obelisk_of_fortuity.tres\",\"res://src/towers/tower_sprites/obelisk_of_fortuity_1.tscn\",\"MS35\",\"ZUF4\"\r\n\"Altar of Fortuity\",2,206,205,\"Neotopia\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1.5,337,347,0,0,140,1100,1,\"FALSE\",\"CREEPS\",,,,,\"226\",,,\"res://src/towers/tower_behaviors/obelisk_of_fortuity.gd\",\"res://resources/icons/tower_icons/obelisk_of_fortuity.tres\",\"res://src/towers/tower_sprites/obelisk_of_fortuity_2.tscn\",\"J9DH\",\"C17Y\"\r\n\"Shrine of Fortuity\",3,207,205,\"Neotopia\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1.5,1396,1415,0,0,400,1100,1,\"FALSE\",\"CREEPS\",,,,,\"227\",,,\"res://src/towers/tower_behaviors/obelisk_of_fortuity.gd\",\"res://resources/icons/tower_icons/obelisk_of_fortuity.tres\",\"res://src/towers/tower_sprites/obelisk_of_fortuity_3.tscn\",\"E6PK\",\"JZY3\"\r\n\"Dome of Fortuity\",4,208,205,\"Neotopia\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1.5,4934,4973,0,0,1450,1100,1,\"FALSE\",\"CREEPS\",,,,,\"228\",,,\"res://src/towers/tower_behaviors/obelisk_of_fortuity.gd\",\"res://resources/icons/tower_icons/obelisk_of_fortuity.tres\",\"res://src/towers/tower_sprites/obelisk_of_fortuity_4.tscn\",\"47U5\",\"W4TP\"\r\n\"Sanctuary of Fortuity\",5,209,205,\"Neotopia\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1.5,10732,10791,0,0,2450,1100,1,\"FALSE\",\"CREEPS\",,,,,\"229\",,,\"res://src/towers/tower_behaviors/obelisk_of_fortuity.gd\",\"res://resources/icons/tower_icons/obelisk_of_fortuity.tres\",\"res://src/towers/tower_sprites/obelisk_of_fortuity_5.tscn\",\"WUJJ\",\"JBZB\"\r\n\"Scales\",1,210,210,\"cedu\",\"unique\",\"storm\",\"TRUE\",\"energy\",1500,1.5,843,851,1100,10,3500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.2,0.008\",\"230,231,232\",,\"60\",\"res://src/towers/tower_behaviors/scales.gd\",\"res://resources/icons/tower_icons/scales.tres\",\"res://src/towers/tower_sprites/scales_1.tscn\",\"IS37\",\"L6WB\"\r\n\"Fisherman\",1,211,211,\"cedi\",\"unique\",\"ice\",\"TRUE\",\"physical\",1100,1,1983,1983,0,0,3000,1200,0.05,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.08\",\"233,234,235\",,,\"res://src/towers/tower_behaviors/fisherman.gd\",\"res://resources/icons/tower_icons/fisherman.tres\",\"res://src/towers/tower_sprites/fisherman_1.tscn\",\"4H8G\",\"4ZXS\"\r\n\"Servant of the Twin Flames\",1,212,212,\"DaveMatthews\",\"unique\",\"fire\",\"TRUE\",\"physical\",900,1.1,2043,2043,0,0,2350,1500,0,\"FALSE\",\"CREEPS\",,,,,\"236,237,238\",,,\"res://src/towers/tower_behaviors/servant_of_the_twin_flames.gd\",\"res://resources/icons/tower_icons/servant_of_the_twin_flames.tres\",\"res://src/towers/tower_sprites/servant_of_the_twin_flames_1.tscn\",\"9USF\",\"5KX2\"\r\n\"Keeper of the Twin Flames\",2,213,212,\"DaveMatthews\",\"unique\",\"fire\",\"TRUE\",\"physical\",900,1.1,2825,2825,0,0,3500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"239,240,241\",,,\"res://src/towers/tower_behaviors/servant_of_the_twin_flames.gd\",\"res://resources/icons/tower_icons/servant_of_the_twin_flames.tres\",\"res://src/towers/tower_sprites/servant_of_the_twin_flames_2.tscn\",\"PDUP\",\"5KX2\"\r\n\"Holy Energy\",1,214,214,\"DaveMatthews\",\"rare\",\"astral\",\"TRUE\",\"energy\",1000,1.4,744,744,100,1.5,1500,1500,0,\"FALSE\",\"CREEPS\",\"3\",,,\"MOD_MANA_REGEN,0,0.1|MOD_BUFF_DURATION,0,0.01\",,\"27\",\"61\",\"res://src/towers/tower_behaviors/holy_energy.gd\",\"res://resources/icons/tower_icons/holy_energy.tres\",\"res://src/towers/tower_sprites/holy_energy_1.tscn\",\"3S83\",\"M6BC\"\r\n\"Taita, The Hermit\",1,215,215,\"DaveMatthews\",\"unique\",\"ice\",\"TRUE\",\"elemental\",1000,1.3,3112,3112,0,0,4000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"242,243,244\",,,\"res://src/towers/tower_behaviors/taita_the_hermit.gd\",\"res://resources/icons/tower_icons/taita_the_hermit.tres\",\"res://src/towers/tower_sprites/taita_the_hermit_1.tscn\",\"PL5N\",\"2OAT\"\r\n\"It\",1,216,216,\"axllow\",\"unique\",\"darkness\",\"TRUE\",\"decay\",800,2,8684,8684,0,0,4500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_SPELL_CRIT_CHANCE,0.0875,0.005\",\"245,246\",,\"62,63\",\"res://src/towers/tower_behaviors/it.gd\",\"res://resources/icons/tower_icons/it.tres\",\"res://src/towers/tower_sprites/it_1.tscn\",\"D5ND\",\"MCJS\"\r\n\"Bomb Turret\",1,217,217,\"DaveMatthews\",\"rare\",\"iron\",\"TRUE\",\"physical\",900,2.6,2429,2429,0,0,950,1300,0,\"FALSE\",\"CREEPS\",,,,,,,\"64,65,66\",\"res://src/towers/tower_behaviors/bomb_turret.gd\",\"res://resources/icons/tower_icons/bomb_turret.tres\",\"res://src/towers/tower_sprites/bomb_turret_1.tscn\",\"5POA\",\"70HK\"\r\n\"Grand Bomb Turret\",2,218,217,\"DaveMatthews\",\"rare\",\"iron\",\"TRUE\",\"physical\",900,2.6,5113,5113,0,0,2000,1300,0,\"FALSE\",\"CREEPS\",,,,,,,\"67,68,69\",\"res://src/towers/tower_behaviors/bomb_turret.gd\",\"res://resources/icons/tower_icons/bomb_turret.tres\",\"res://src/towers/tower_sprites/bomb_turret_2.tscn\",\"I68Q\",\"70HK\"\r\n\"Contraption\",1,219,219,\"Deemzul\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",800,1,160,160,0,0,160,2000,0.1,\"FALSE\",\"CREEPS\",,,,,\"247\",,,\"res://src/towers/tower_behaviors/contraption.gd\",\"res://resources/icons/tower_icons/contraption.tres\",\"res://src/towers/tower_sprites/contraption_1.tscn\",\"PXUM\",\"WUWB\"\r\n\"Studded Contraption\",2,285,219,\"Deemzul\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",900,1,330,330,0,0,400,2000,0.15,\"FALSE\",\"CREEPS\",,,,,\"248\",,,\"res://src/towers/tower_behaviors/contraption.gd\",\"res://resources/icons/tower_icons/contraption.tres\",\"res://src/towers/tower_sprites/contraption_2.tscn\",\"9ZW5\",\"WUWB\"\r\n\"Dimensional Contraption\",3,286,219,\"Deemzul\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",950,1,842,842,0,0,1200,2000,0.2,\"FALSE\",\"CREEPS\",,,,,\"249\",,,\"res://src/towers/tower_behaviors/contraption.gd\",\"res://resources/icons/tower_icons/contraption.tres\",\"res://src/towers/tower_sprites/contraption_3.tscn\",\"PBIL\",\"WUWB\"\r\n\"Extra Dimensional Contraption\",4,287,219,\"Deemzul\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",1000,1,1518,1518,0,0,2400,2000,0.24,\"FALSE\",\"CREEPS\",,,,,\"250\",,,\"res://src/towers/tower_behaviors/contraption.gd\",\"res://resources/icons/tower_icons/contraption.tres\",\"res://src/towers/tower_sprites/contraption_4.tscn\",\"841X\",\"WUWB\"\r\n\"Shard of Souls\",1,220,220,\"Der_kleine_Tomy\",\"rare\",\"darkness\",\"FALSE\",\"physical\",1000,1,1,1,75,4,750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_BUFF_DURATION,0,0.02\",\"251\",,\"70\",\"res://src/towers/tower_behaviors/shard_of_souls.gd\",\"res://resources/icons/tower_icons/shard_of_souls.tres\",\"res://src/towers/tower_sprites/shard_of_souls_1.tscn\",\"28HL\",\"NC1S\"\r\n\"Crystal of Souls\",2,222,220,\"Der_kleine_Tomy\",\"rare\",\"darkness\",\"FALSE\",\"physical\",1000,1,1,1,75,4,2250,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_BUFF_DURATION,0,0.02\",\"252\",,\"71\",\"res://src/towers/tower_behaviors/shard_of_souls.gd\",\"res://resources/icons/tower_icons/shard_of_souls.tres\",\"res://src/towers/tower_sprites/shard_of_souls_2.tscn\",\"VJYV\",\"NC1S\"\r\n\"Geothermal Extractor\",1,221,221,\"Velex\",\"rare\",\"fire\",\"TRUE\",\"elemental\",700,0.5,185,185,0,0,500,800,0.7,\"FALSE\",\"CREEPS\",,,,,,\"28\",,\"res://src/towers/tower_behaviors/geothermal_extractor.gd\",\"res://resources/icons/tower_icons/geothermal_extractor.tres\",\"res://src/towers/tower_sprites/geothermal_extractor_1.tscn\",\"SAN6\",\"31RL\"\r\n\"Geothermal Refinery\",2,224,221,\"Velex\",\"rare\",\"fire\",\"TRUE\",\"elemental\",700,0.5,848,848,0,0,2000,800,0.7,\"FALSE\",\"CREEPS\",,,,,,\"29\",,\"res://src/towers/tower_behaviors/geothermal_extractor.gd\",\"res://resources/icons/tower_icons/geothermal_extractor.tres\",\"res://src/towers/tower_sprites/geothermal_extractor_2.tscn\",\"DMYC\",\"31RL\"\r\n\"Black Dragon Roost\",1,223,223,\"cedi\",\"unique\",\"darkness\",\"TRUE\",\"essence\",800,2,1501,1501,0,0,1600,1000,0.4,\"FALSE\",\"CREEPS\",,,,,\"253\",,,\"res://src/towers/tower_behaviors/black_dragon_roost.gd\",\"res://resources/icons/tower_icons/black_dragon_roost.tres\",\"res://src/towers/tower_sprites/black_dragon_roost_1.tscn\",\"1EV5\",\"1BH7\"\r\n\"Small Torch\",1,226,226,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,0.9,48,48,25,2,70,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"72\",\"res://src/towers/tower_behaviors/small_torch.gd\",\"res://resources/icons/tower_icons/small_torch.tres\",\"res://src/towers/tower_sprites/small_torch_1.tscn\",\"1O66\",\"IWGJ\"\r\n\"Torch\",2,225,226,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,0.9,173,173,30,2,250,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"73\",\"res://src/towers/tower_behaviors/small_torch.gd\",\"res://resources/icons/tower_icons/small_torch.tres\",\"res://src/towers/tower_sprites/small_torch_2.tscn\",\"7E0K\",\"IWGJ\"\r\n\"Burning Torch\",3,228,226,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,0.9,484,484,35,2,700,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"74\",\"res://src/towers/tower_behaviors/small_torch.gd\",\"res://resources/icons/tower_icons/small_torch.tres\",\"res://src/towers/tower_sprites/small_torch_3.tscn\",\"W53T\",\"IWGJ\"\r\n\"Burning Beacon\",4,229,226,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,0.9,968,968,40,2,1400,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"75\",\"res://src/towers/tower_behaviors/small_torch.gd\",\"res://resources/icons/tower_icons/small_torch.tres\",\"res://src/towers/tower_sprites/small_torch_4.tscn\",\"W7S1\",\"IWGJ\"\r\n\"Inferno Beacon\",5,227,226,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,0.9,1729,1729,45,2,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"76\",\"res://src/towers/tower_behaviors/small_torch.gd\",\"res://resources/icons/tower_icons/small_torch.tres\",\"res://src/towers/tower_sprites/small_torch_5.tscn\",\"BNBA\",\"IWGJ\"\r\n\"Broken Lightning Rod\",1,231,231,\"Boekie\",\"common\",\"storm\",\"TRUE\",\"energy\",1200,1.2,47,66,25,2,70,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"77\",\"res://src/towers/tower_behaviors/broken_lightning_rod.gd\",\"res://resources/icons/tower_icons/broken_lightning_rod.tres\",\"res://src/towers/tower_sprites/broken_lightning_rod_1.tscn\",\"G9WI\",\"867J\"\r\n\"Small Lightning Rod\",2,234,231,\"Boekie\",\"common\",\"storm\",\"TRUE\",\"energy\",1200,1.2,190,209,30,2,250,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"78\",\"res://src/towers/tower_behaviors/broken_lightning_rod.gd\",\"res://resources/icons/tower_icons/broken_lightning_rod.tres\",\"res://src/towers/tower_sprites/broken_lightning_rod_2.tscn\",\"S7O5\",\"867J\"\r\n\"Lightning Rod\",3,233,231,\"Boekie\",\"common\",\"storm\",\"TRUE\",\"energy\",1200,1.2,548,567,35,2,700,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"79\",\"res://src/towers/tower_behaviors/broken_lightning_rod.gd\",\"res://resources/icons/tower_icons/broken_lightning_rod.tres\",\"res://src/towers/tower_sprites/broken_lightning_rod_3.tscn\",\"63BR\",\"867J\"\r\n\"Greater Lightning Rod\",4,232,231,\"Boekie\",\"common\",\"storm\",\"TRUE\",\"energy\",1200,1.2,1104,1123,40,2,1400,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"80\",\"res://src/towers/tower_behaviors/broken_lightning_rod.gd\",\"res://resources/icons/tower_icons/broken_lightning_rod.tres\",\"res://src/towers/tower_sprites/broken_lightning_rod_4.tscn\",\"6YFN\",\"867J\"\r\n\"Big Lightning Rod\",5,230,231,\"Boekie\",\"common\",\"storm\",\"TRUE\",\"energy\",1200,1.2,1979,1998,45,2,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"81\",\"res://src/towers/tower_behaviors/broken_lightning_rod.gd\",\"res://resources/icons/tower_icons/broken_lightning_rod.tres\",\"res://src/towers/tower_sprites/broken_lightning_rod_5.tscn\",\"9FVR\",\"867J\"\r\n\"Magna Warrior\",1,235,235,\"drol/im0ckdeath\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.7,110,121,0,0,70,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"254\",,,\"res://src/towers/tower_behaviors/magna_warrior.gd\",\"res://resources/icons/tower_icons/magna_warrior.tres\",\"res://src/towers/tower_sprites/magna_warrior_1.tscn\",\"T0NZ\",\"YAN8\"\r\n\"Magna Hunter\",2,236,235,\"drol/im0ckdeath\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.7,481,492,0,0,300,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"255\",,,\"res://src/towers/tower_behaviors/magna_warrior.gd\",\"res://resources/icons/tower_icons/magna_warrior.tres\",\"res://src/towers/tower_sprites/magna_warrior_2.tscn\",\"0FIG\",\"YAN8\"\r\n\"Magna Destroyer\",3,237,235,\"drol/im0ckdeath\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.7,1111,1122,0,0,700,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"256\",,,\"res://src/towers/tower_behaviors/magna_warrior.gd\",\"res://resources/icons/tower_icons/magna_warrior.tres\",\"res://src/towers/tower_sprites/magna_warrior_3.tscn\",\"JIL8\",\"YAN8\"\r\n\"Magna Spirit Hunter\",4,238,235,\"drol/im0ckdeath\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.7,2501,2512,0,0,1600,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"257\",,,\"res://src/towers/tower_behaviors/magna_warrior.gd\",\"res://resources/icons/tower_icons/magna_warrior.tres\",\"res://src/towers/tower_sprites/magna_warrior_4.tscn\",\"U04B\",\"YAN8\"\r\n\"Magna Celestial Hunter\",5,239,235,\"drol/im0ckdeath\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.7,4304,4315,0,0,2800,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"258\",,,\"res://src/towers/tower_behaviors/magna_warrior.gd\",\"res://resources/icons/tower_icons/magna_warrior.tres\",\"res://src/towers/tower_sprites/magna_warrior_5.tscn\",\"FMJ5\",\"YAN8\"\r\n\"Forest Troll\",1,240,240,\"geX\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",900,2,685,1385,0,0,700,1500,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0\",\"259\",,,\"res://src/towers/tower_behaviors/forest_troll.gd\",\"res://resources/icons/tower_icons/forest_troll.tres\",\"res://src/towers/tower_sprites/forest_troll_1.tscn\",\"5G2E\",\"O6GY\"\r\n\"Raging Forest Troll\",2,246,240,\"geX\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",900,1.9,1225,2625,0,0,1500,1500,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0\",\"260\",,,\"res://src/towers/tower_behaviors/forest_troll.gd\",\"res://resources/icons/tower_icons/forest_troll.tres\",\"res://src/towers/tower_sprites/forest_troll_2.tscn\",\"QWHC\",\"UVIS\"\r\n\"Rampaging Forest Troll\",3,252,240,\"geX\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",900,1.8,1631,4431,0,0,2750,1500,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0\",\"261\",,,\"res://src/towers/tower_behaviors/forest_troll.gd\",\"res://resources/icons/tower_icons/forest_troll.tres\",\"res://src/towers/tower_sprites/forest_troll_3.tscn\",\"EE3Q\",\"XBEW\"\r\n\"Inflamed Stone\",1,241,241,\"SirCoqalot.\",\"rare\",\"fire\",\"TRUE\",\"arcane\",850,1,1,192,40,5,1000,2000,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.02\",\"262,263\",,,\"res://src/towers/tower_behaviors/inflamed_stone.gd\",\"res://resources/icons/tower_icons/inflamed_stone.tres\",\"res://src/towers/tower_sprites/inflamed_stone_1.tscn\",\"SZKU\",\"CJKK\"\r\n\"Inflamed Stone Spires\",2,301,241,\"SirCoqalot.\",\"rare\",\"fire\",\"TRUE\",\"arcane\",850,1,1,382,45,6.25,2250,2000,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.02\",\"264,265\",,,\"res://src/towers/tower_behaviors/inflamed_stone.gd\",\"res://resources/icons/tower_icons/inflamed_stone.tres\",\"res://src/towers/tower_sprites/inflamed_stone_2.tscn\",\"WQR7\",\"CJKK\"\r\n\"Inflamed Stone Pillars\",3,302,241,\"SirCoqalot.\",\"rare\",\"fire\",\"TRUE\",\"arcane\",850,1,1,518,50,7.5,3500,2000,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.02\",\"266,267\",,,\"res://src/towers/tower_behaviors/inflamed_stone.gd\",\"res://resources/icons/tower_icons/inflamed_stone.tres\",\"res://src/towers/tower_sprites/inflamed_stone_3.tscn\",\"0B6X\",\"CJKK\"\r\n\"Stormy Dog\",1,242,242,\"cedi\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",900,1.5,95,103,0,0,70,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0\",\"268\",,,\"res://src/towers/tower_behaviors/stormy_dog.gd\",\"res://resources/icons/tower_icons/stormy_dog.tres\",\"res://src/towers/tower_sprites/stormy_dog_1.tscn\",\"AU34\",\"V32H\"\r\n\"Thunderous Dog\",2,243,242,\"cedi\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",900,1.5,281,289,0,0,210,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.015\",\"269\",,,\"res://src/towers/tower_behaviors/stormy_dog.gd\",\"res://resources/icons/tower_icons/stormy_dog.tres\",\"res://src/towers/tower_sprites/stormy_dog_2.tscn\",\"R6K6\",\"V32H\"\r\n\"Stormhound\",3,244,242,\"cedi\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",900,1.5,1082,1090,0,0,840,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.018\",\"270\",,,\"res://src/towers/tower_behaviors/stormy_dog.gd\",\"res://resources/icons/tower_icons/stormy_dog.tres\",\"res://src/towers/tower_sprites/stormy_dog_3.tscn\",\"PRXU\",\"V32H\"\r\n\"Hurricane Dog\",4,245,242,\"cedi\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",900,1.5,2062,2070,0,0,1680,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.021\",\"271\",,,\"res://src/towers/tower_behaviors/stormy_dog.gd\",\"res://resources/icons/tower_icons/stormy_dog.tres\",\"res://src/towers/tower_sprites/stormy_dog_4.tscn\",\"Q19Y\",\"V32H\"\r\n\"Hound of Storms\",5,247,242,\"cedi\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",900,1.5,3916,3924,0,0,3360,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.024\",\"272\",,,\"res://src/towers/tower_behaviors/stormy_dog.gd\",\"res://resources/icons/tower_icons/stormy_dog.tres\",\"res://src/towers/tower_sprites/stormy_dog_5.tscn\",\"I7BO\",\"V32H\"\r\n\"Young Northern Troll\",1,249,249,\"DaveMatthews\",\"rare\",\"ice\",\"TRUE\",\"elemental\",800,2,1933,1933,0,0,900,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.1,0.002|MOD_DMG_TO_HUMANOID,0.1,0.002\",\"273,274\",,,\"res://src/towers/tower_behaviors/young_northern_troll.gd\",\"res://resources/icons/tower_icons/young_northern_troll.tres\",\"res://src/towers/tower_sprites/young_northern_troll_1.tscn\",\"W4Y1\",\"VKXW\"\r\n\"Adult Northern Troll\",2,250,249,\"DaveMatthews\",\"rare\",\"ice\",\"TRUE\",\"elemental\",800,2,3697,3697,0,0,1900,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.15,0.003|MOD_DMG_TO_HUMANOID,0.15,0.003\",\"275,276\",,,\"res://src/towers/tower_behaviors/young_northern_troll.gd\",\"res://resources/icons/tower_icons/young_northern_troll.tres\",\"res://src/towers/tower_sprites/young_northern_troll_2.tscn\",\"CJ25\",\"VKXW\"\r\n\"Elder Northern Troll\",3,251,249,\"DaveMatthews\",\"rare\",\"ice\",\"TRUE\",\"elemental\",800,2,5459,5459,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0.004|MOD_DMG_TO_HUMANOID,0.2,0.004\",\"277,278\",,,\"res://src/towers/tower_behaviors/young_northern_troll.gd\",\"res://resources/icons/tower_icons/young_northern_troll.tres\",\"res://src/towers/tower_sprites/young_northern_troll_3.tscn\",\"C9GK\",\"VKXW\"\r\n\"Cenarion\",1,253,253,\"cedi\",\"unique\",\"nature\",\"TRUE\",\"decay\",950,1.4,1344,1344,100,3,2800,1500,0.15,\"FALSE\",\"CREEPS\",,,,,\"279,280\",\"30\",\"82\",\"res://src/towers/tower_behaviors/cenarion.gd\",\"res://resources/icons/tower_icons/cenarion.tres\",\"res://src/towers/tower_sprites/cenarion_1.tscn\",\"Q2CV\",\"Q626\"\r\n\"Skink\",1,254,254,\"cedi\",\"uncommon\",\"nature\",\"TRUE\",\"decay\",800,1,28,34,0,0,75,1200,0,\"FALSE\",\"CREEPS\",,,,,,\"31\",,\"res://src/towers/tower_behaviors/skink.gd\",\"res://resources/icons/tower_icons/skink.tres\",\"res://src/towers/tower_sprites/skink_1.tscn\",\"HUST\",\"WNX3\"\r\n\"Aged Skink\",2,255,254,\"cedi\",\"uncommon\",\"nature\",\"TRUE\",\"decay\",800,1,112,125,0,0,280,1200,0,\"FALSE\",\"CREEPS\",,,,,,\"32\",,\"res://src/towers/tower_behaviors/skink.gd\",\"res://resources/icons/tower_icons/skink.tres\",\"res://src/towers/tower_sprites/skink_2.tscn\",\"TUI3\",\"WNX3\"\r\n\"Yellowskin Skink\",3,256,254,\"cedi\",\"uncommon\",\"nature\",\"TRUE\",\"decay\",800,1,326,346,0,0,800,1200,0,\"FALSE\",\"CREEPS\",,,,,,\"33\",,\"res://src/towers/tower_behaviors/skink.gd\",\"res://resources/icons/tower_icons/skink.tres\",\"res://src/towers/tower_sprites/skink_3.tscn\",\"EV3R\",\"WNX3\"\r\n\"Viviparous Skink\",4,257,254,\"cedi\",\"uncommon\",\"nature\",\"TRUE\",\"decay\",800,1,743,770,0,0,1800,1200,0,\"FALSE\",\"CREEPS\",,,,,,\"34\",,\"res://src/towers/tower_behaviors/skink.gd\",\"res://resources/icons/tower_icons/skink.tres\",\"res://src/towers/tower_sprites/skink_4.tscn\",\"548I\",\"WNX3\"\r\n\"Starskin Skink\",5,258,254,\"cedi\",\"uncommon\",\"nature\",\"TRUE\",\"decay\",800,1,1243,1277,0,0,3000,1200,0,\"FALSE\",\"CREEPS\",,,,,,\"35\",,\"res://src/towers/tower_behaviors/skink.gd\",\"res://resources/icons/tower_icons/skink.tres\",\"res://src/towers/tower_sprites/skink_5.tscn\",\"XSY9\",\"WNX3\"\r\n\"Valor\",1,262,262,\"cedi\",\"unique\",\"iron\",\"FALSE\",\"physical\",800,1,1,1,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"281,282\",\"36\",,\"res://src/towers/tower_behaviors/valor.gd\",\"res://resources/icons/tower_icons/valor.tres\",\"res://src/towers/tower_sprites/valor_1.tscn\",\"BJSZ\",\"N93Y\"\r\n\"Shadow\",1,266,266,\"i_m0ck_death\",\"unique\",\"darkness\",\"TRUE\",\"decay\",800,1.6,1023,8022,0,0,3330,1500,0,\"FALSE\",\"CREEPS\",,,,,\"283,284\",\"37\",,\"res://src/towers/tower_behaviors/shadow.gd\",\"res://resources/icons/tower_icons/shadow.tres\",\"res://src/towers/tower_sprites/shadow_1.tscn\",\"4UYD\",\"PX6K\"\r\n\"Harby\",1,267,267,\"Glowackos\",\"unique\",\"darkness\",\"TRUE\",\"decay\",800,1.4,2785,2785,450,7.5,3100,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_SPELL_CRIT_DAMAGE,0.2,0.05|MOD_DEBUFF_DURATION,-0.55,-0.01|MOD_MANA,0,10\",\"285,286\",\"38\",,\"res://src/towers/tower_behaviors/harby.gd\",\"res://resources/icons/tower_icons/harby.tres\",\"res://src/towers/tower_sprites/harby_1.tscn\",\"UFUT\",\"P7ZF\"\r\n\"Cloud Warrior\",1,272,272,\"i_m0ck_death\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",840,2.1,58,127,0,0,70,2000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"287\",,,\"res://src/towers/tower_behaviors/cloud_warrior.gd\",\"res://resources/icons/tower_icons/cloud_warrior.tres\",\"res://src/towers/tower_sprites/cloud_warrior_1.tscn\",\"FZGR\",\"DB8T\"\r\n\"Stratus Warrior\",2,273,272,\"i_m0ck_death\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",840,2.1,173,382,0,0,210,2000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"288\",,,\"res://src/towers/tower_behaviors/cloud_warrior.gd\",\"res://resources/icons/tower_icons/cloud_warrior.tres\",\"res://src/towers/tower_sprites/cloud_warrior_2.tscn\",\"Z8LT\",\"DB8T\"\r\n\"Cumulus Warrior\",3,274,272,\"i_m0ck_death\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",840,2.1,431,955,0,0,525,2000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"289\",,,\"res://src/towers/tower_behaviors/cloud_warrior.gd\",\"res://resources/icons/tower_icons/cloud_warrior.tres\",\"res://src/towers/tower_sprites/cloud_warrior_3.tscn\",\"BWQL\",\"DB8T\"\r\n\"Cirrus Warrior\",4,275,272,\"i_m0ck_death\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",840,2.1,1076,2387,0,0,1312,2000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"290\",,,\"res://src/towers/tower_behaviors/cloud_warrior.gd\",\"res://resources/icons/tower_icons/cloud_warrior.tres\",\"res://src/towers/tower_sprites/cloud_warrior_4.tscn\",\"5B50\",\"DB8T\"\r\n\"Cumulonimbus Warrior\",5,276,272,\"i_m0ck_death\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",840,2.1,2151,4776,0,0,2625,2000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"291\",,,\"res://src/towers/tower_behaviors/cloud_warrior.gd\",\"res://resources/icons/tower_icons/cloud_warrior.tres\",\"res://src/towers/tower_sprites/cloud_warrior_5.tscn\",\"LT4E\",\"DB8T\"\r\n\"Essence of Fury\",1,277,277,\"Killamasta\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",800,2,16,16,0,0,100,1500,0,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"292\",,,\"res://src/towers/tower_behaviors/essence_of_fury.gd\",\"res://resources/icons/tower_icons/essence_of_fury.tres\",\"res://src/towers/tower_sprites/essence_of_fury_1.tscn\",\"HUC0\",\"4BQP\"\r\n\"Essence of Rage\",2,290,277,\"Killamasta\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",800,2,38,38,0,0,300,1500,0,\"FALSE\",\"CREEPS\",,,\"3,0\",,\"293\",,,\"res://src/towers/tower_behaviors/essence_of_fury.gd\",\"res://resources/icons/tower_icons/essence_of_fury.tres\",\"res://src/towers/tower_sprites/essence_of_fury_2.tscn\",\"8V54\",\"4BQP\"\r\n\"Essence of Anger\",3,291,277,\"Killamasta\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",800,2,63,63,0,0,600,1500,0,\"FALSE\",\"CREEPS\",,,\"4,0\",,\"294\",,,\"res://src/towers/tower_behaviors/essence_of_fury.gd\",\"res://resources/icons/tower_icons/essence_of_fury.tres\",\"res://src/towers/tower_sprites/essence_of_fury_3.tscn\",\"9AHZ\",\"4BQP\"\r\n\"Essence of Hate\",4,292,277,\"Killamasta\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",800,2,101,101,0,0,1200,1500,0,\"FALSE\",\"CREEPS\",,,\"6,0\",,\"295\",,,\"res://src/towers/tower_behaviors/essence_of_fury.gd\",\"res://resources/icons/tower_icons/essence_of_fury.tres\",\"res://src/towers/tower_sprites/essence_of_fury_4.tscn\",\"IWH9\",\"4BQP\"\r\n\"Core of Dark Emotions\",5,293,277,\"Killamasta\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",800,2,185,185,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,\"8,0\",,\"296\",,,\"res://src/towers/tower_behaviors/essence_of_fury.gd\",\"res://resources/icons/tower_icons/essence_of_fury.tres\",\"res://src/towers/tower_sprites/essence_of_fury_5.tscn\",\"0Y10\",\"KX76\"\r\n\"Small Brazier\",1,279,279,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",865,0.7,149,169,0,0,350,2000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0.015|MOD_ATK_CRIT_DAMAGE,0.45,0.03|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_brazier.tres\",\"res://src/towers/tower_sprites/small_brazier_1.tscn\",\"RJZ7\",\"Z0LN\"\r\n\"Old Brazier\",2,278,279,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",865,0.7,389,429,0,0,900,2000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0.015|MOD_ATK_CRIT_DAMAGE,0.45,0.03|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_brazier.tres\",\"res://src/towers/tower_sprites/small_brazier_2.tscn\",\"DP6S\",\"Z0LN\"\r\n\"Ancient Brazier\",3,280,279,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",865,0.7,765,825,0,0,1750,2000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0.015|MOD_ATK_CRIT_DAMAGE,0.45,0.03|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_brazier.tres\",\"res://src/towers/tower_sprites/small_brazier_3.tscn\",\"DCLM\",\"Z0LN\"\r\n\"Adored Brazier\",4,281,279,\"SirCoqalot.\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",865,0.7,1278,1358,0,0,2900,2000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0.015|MOD_ATK_CRIT_DAMAGE,0.45,0.03|MOD_MULTICRIT_COUNT,1,0\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_brazier.tres\",\"res://src/towers/tower_sprites/small_brazier_4.tscn\",\"31KF\",\"Z0LN\"\r\n\"Sea Turtle\",1,282,282,\"i_m0ck_death\",\"rare\",\"ice\",\"TRUE\",\"energy\",900,0.8,1,1,1600,0,1000,1900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,64\",\"297,298,299\",,,\"res://src/towers/tower_behaviors/sea_turtle.gd\",\"res://resources/icons/tower_icons/sea_turtle.tres\",\"res://src/towers/tower_sprites/sea_turtle_1.tscn\",\"T5Z2\",\"LE3V\"\r\n\"Freezing Sea Turtle\",2,283,282,\"i_m0ck_death\",\"rare\",\"ice\",\"TRUE\",\"energy\",900,0.8,1,1,3200,0,2000,1900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,128\",\"300,301,302\",,,\"res://src/towers/tower_behaviors/sea_turtle.gd\",\"res://resources/icons/tower_icons/sea_turtle.tres\",\"res://src/towers/tower_sprites/sea_turtle_2.tscn\",\"7R5A\",\"LE3V\"\r\n\"Glacial Sea Turtle\",3,284,282,\"i_m0ck_death\",\"rare\",\"ice\",\"TRUE\",\"energy\",900,0.8,1,1,4800,0,3000,1900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,192\",\"303,304,305\",,,\"res://src/towers/tower_behaviors/sea_turtle.gd\",\"res://resources/icons/tower_icons/sea_turtle.tres\",\"res://src/towers/tower_sprites/sea_turtle_3.tscn\",\"AGEX\",\"LE3V\"\r\n\"Red Ball Lightning\",1,288,288,\"SirCoqalot.\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,1.65,228,677,0,0,1200,1500,0,\"FALSE\",\"CREEPS\",,,\"2,0.6\",,\"306\",\"39\",,\"res://src/towers/tower_behaviors/red_ball_lightning.gd\",\"res://resources/icons/tower_icons/red_ball_lightning.tres\",\"res://src/towers/tower_sprites/red_ball_lightning_1.tscn\",\"Q7PL\",\"H5WY\"\r\n\"Red Lightning Conductor\",2,289,288,\"SirCoqalot.\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,1.65,384,1283,0,0,3500,1500,0,\"FALSE\",\"CREEPS\",,,\"3,0.6\",,\"307\",\"40\",,\"res://src/towers/tower_behaviors/red_ball_lightning.gd\",\"res://resources/icons/tower_icons/red_ball_lightning.tres\",\"res://src/towers/tower_sprites/red_ball_lightning_2.tscn\",\"WP64\",\"BL7R\"\r\n\"The Council of Demons\",1,295,295,\"DaveMatthews\",\"unique\",\"darkness\",\"TRUE\",\"arcane\",850,1,1335,1335,100,2,2900,1300,0,\"FALSE\",\"CREEPS\",,,,,\"308\",\"41\",\"83\",\"res://src/towers/tower_behaviors/the_council_of_demons.gd\",\"res://resources/icons/tower_icons/the_council_of_demons.tres\",\"res://src/towers/tower_sprites/the_council_of_demons_1.tscn\",\"NTI7\",\"0U76\"\r\n\"Lunar Emitter\",1,296,296,\"geX\",\"rare\",\"darkness\",\"TRUE\",\"elemental\",800,1.4,990,990,0,0,1300,1000,0,\"FALSE\",\"CREEPS\",,\"50,1,350,0.4\",,,,\"42\",,\"res://src/towers/tower_behaviors/lunar_emitter.gd\",\"res://resources/icons/tower_icons/lunar_emitter.tres\",\"res://src/towers/tower_sprites/lunar_emitter_1.tscn\",\"6EFT\",\"L42W\"\r\n\"Ancient Lunar Emitter\",2,297,296,\"geX\",\"rare\",\"darkness\",\"TRUE\",\"elemental\",1100,1.4,2153,2153,0,0,3200,1000,0,\"FALSE\",\"CREEPS\",,\"50,1,350,0.4\",,,,\"43\",,\"res://src/towers/tower_behaviors/lunar_emitter.gd\",\"res://resources/icons/tower_icons/lunar_emitter.tres\",\"res://src/towers/tower_sprites/lunar_emitter_2.tscn\",\"IEJD\",\"L42W\"\r\n\"Portal to Swine Purgatory\",1,298,298,\"Deemzul\",\"rare\",\"fire\",\"TRUE\",\"elemental\",950,2.5,600,600,0,0,800,10000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.2,0\",\"309,310\",,,\"res://src/towers/tower_behaviors/portal_to_swine_purgatory.gd\",\"res://resources/icons/tower_icons/portal_to_swine_purgatory.tres\",\"res://src/towers/tower_sprites/portal_to_swine_purgatory_1.tscn\",\"Z1S4\",\"KPTG\"\r\n\"Portal to Swine Hell\",2,299,298,\"Deemzul\",\"rare\",\"fire\",\"TRUE\",\"elemental\",950,3,1500,1500,0,0,1800,10000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.25,0\",\"311,312\",,,\"res://src/towers/tower_behaviors/portal_to_swine_purgatory.gd\",\"res://resources/icons/tower_icons/portal_to_swine_purgatory.tres\",\"res://src/towers/tower_sprites/portal_to_swine_purgatory_2.tscn\",\"ZG7Z\",\"KPTG\"\r\n\"Portal to Swine Inferno\",3,300,298,\"Deemzul\",\"rare\",\"fire\",\"TRUE\",\"elemental\",950,4,3200,3200,0,0,2800,10000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.25,0\",\"313,314\",,,\"res://src/towers/tower_behaviors/portal_to_swine_purgatory.gd\",\"res://resources/icons/tower_icons/portal_to_swine_purgatory.tres\",\"res://src/towers/tower_sprites/portal_to_swine_purgatory_3.tscn\",\"CJ1R\",\"KPTG\"\r\n\"Chaining Storm\",1,303,303,,\"unique\",\"storm\",\"TRUE\",\"energy\",1100,1.5,946,952,100,10,4000,1500,0.3,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.5,0.02|MOD_MANA,0,15|MOD_MANA_REGEN,0,0.1\",\"315,316\",\"44\",,\"res://src/towers/tower_behaviors/chaining_storm.gd\",\"res://resources/icons/tower_icons/chaining_storm.tres\",\"res://src/towers/tower_sprites/chaining_storm_1.tscn\",\"GNYU\",\"5F7Y\"\r\n\"Chilled Spire\",1,304,304,\"SirCoqalot.\",\"rare\",\"ice\",\"TRUE\",\"elemental\",1100,1.4,801,801,0,0,800,1100,0,\"FALSE\",\"CREEPS\",,,,,\"317\",,,\"res://src/towers/tower_behaviors/chilled_spire.gd\",\"res://resources/icons/tower_icons/chilled_spire.tres\",\"res://src/towers/tower_sprites/chilled_spire_1.tscn\",\"Y11K\",\"UA19\"\r\n\"Icy Spires\",2,323,304,\"SirCoqalot.\",\"rare\",\"ice\",\"TRUE\",\"elemental\",1100,1.4,2402,2402,0,0,2400,1100,0,\"FALSE\",\"CREEPS\",,,,,\"318\",,,\"res://src/towers/tower_behaviors/chilled_spire.gd\",\"res://resources/icons/tower_icons/chilled_spire.tres\",\"res://src/towers/tower_sprites/chilled_spire_2.tscn\",\"Q6GU\",\"UA19\"\r\n\"Small Ray Blaster\",1,305,305,\"i_m0ck_death\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",800,1.4,79,98,0,0,70,1500,0,\"FALSE\",\"CREEPS\",,,,,\"319\",,,\"res://src/towers/tower_behaviors/small_ray_blaster.gd\",\"res://resources/icons/tower_icons/small_ray_blaster.tres\",\"res://src/towers/tower_sprites/small_ray_blaster_1.tscn\",\"PNEI\",\"0ZIN\"\r\n\"Ray Blaster\",2,308,305,\"i_m0ck_death\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",800,1.4,268,287,0,0,235,1500,0,\"FALSE\",\"CREEPS\",,,,,\"320\",,,\"res://src/towers/tower_behaviors/small_ray_blaster.gd\",\"res://resources/icons/tower_icons/small_ray_blaster.tres\",\"res://src/towers/tower_sprites/small_ray_blaster_2.tscn\",\"423V\",\"0ZIN\"\r\n\"Large Ray Blaster\",3,309,305,\"i_m0ck_death\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",800,1.4,743,762,0,0,695,1500,0,\"FALSE\",\"CREEPS\",,,,,\"321\",,,\"res://src/towers/tower_behaviors/small_ray_blaster.gd\",\"res://resources/icons/tower_icons/small_ray_blaster.tres\",\"res://src/towers/tower_sprites/small_ray_blaster_3.tscn\",\"P5XI\",\"0ZIN\"\r\n\"Custom Ray Blaster\",4,310,305,\"i_m0ck_death\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",800,1.4,1377,1396,0,0,1390,1500,0,\"FALSE\",\"CREEPS\",,,,,\"322\",,,\"res://src/towers/tower_behaviors/small_ray_blaster.gd\",\"res://resources/icons/tower_icons/small_ray_blaster.tres\",\"res://src/towers/tower_sprites/small_ray_blaster_4.tscn\",\"JWE4\",\"0ZIN\"\r\n\"Ray Blaster 2.0\",5,311,305,\"i_m0ck_death\",\"uncommon\",\"iron\",\"TRUE\",\"energy\",800,1.4,2370,2409,0,0,2640,1500,0,\"FALSE\",\"CREEPS\",,,,,\"323\",,,\"res://src/towers/tower_behaviors/small_ray_blaster.gd\",\"res://resources/icons/tower_icons/small_ray_blaster.tres\",\"res://src/towers/tower_sprites/small_ray_blaster_5.tscn\",\"F2OT\",\"0ZIN\"\r\n\"Dimensional Flux Collector\",1,306,306,\"cedi\",\"unique\",\"storm\",\"FALSE\",\"physical\",2000,1,0,0,0,0,3500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"324\",\"45\",\"84\",\"res://src/towers/tower_behaviors/dimensional_flux_collector.gd\",\"res://resources/icons/tower_icons/dimensional_flux_collector.tres\",\"res://src/towers/tower_sprites/dimensional_flux_collector_1.tscn\",\"PSPT\",\"E2EP\"\r\n\"Tombstone\",1,307,307,\"geX\",\"common\",\"darkness\",\"TRUE\",\"decay\",1050,2,37,47,0,0,30,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"325\",,,\"res://src/towers/tower_behaviors/tombstone.gd\",\"res://resources/icons/tower_icons/tombstone.tres\",\"res://src/towers/tower_sprites/tombstone_1.tscn\",\"KUJX\",\"XKCW\"\r\n\"Creepy Tombstone\",2,318,307,\"geX\",\"common\",\"darkness\",\"TRUE\",\"decay\",1050,1.95,164,204,0,0,140,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"326\",,,\"res://src/towers/tower_behaviors/tombstone.gd\",\"res://resources/icons/tower_icons/tombstone.tres\",\"res://src/towers/tower_sprites/tombstone_2.tscn\",\"KZEF\",\"XKCW\"\r\n\"Cursed Tombstone\",3,354,307,\"geX\",\"common\",\"darkness\",\"TRUE\",\"decay\",1050,1.9,447,547,0,0,400,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"327\",,,\"res://src/towers/tower_behaviors/tombstone.gd\",\"res://resources/icons/tower_icons/tombstone.tres\",\"res://src/towers/tower_sprites/tombstone_3.tscn\",\"QPX1\",\"XKCW\"\r\n\"Horrible Tombstone\",4,324,307,\"geX\",\"common\",\"darkness\",\"TRUE\",\"decay\",1050,1.85,953,1153,0,0,900,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"328\",,,\"res://src/towers/tower_behaviors/tombstone.gd\",\"res://resources/icons/tower_icons/tombstone.tres\",\"res://src/towers/tower_sprites/tombstone_4.tscn\",\"P22E\",\"XKCW\"\r\n\"Daemonic Tombstone\",5,333,307,\"geX\",\"common\",\"darkness\",\"TRUE\",\"decay\",1050,1.8,1585,1935,0,0,1600,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"329\",,,\"res://src/towers/tower_behaviors/tombstone.gd\",\"res://resources/icons/tower_icons/tombstone.tres\",\"res://src/towers/tower_sprites/tombstone_5.tscn\",\"YSYC\",\"XKCW\"\r\n\"Monument of Death\",6,344,307,\"geX\",\"common\",\"darkness\",\"TRUE\",\"decay\",1050,1.75,2296,2896,0,0,2500,1800,0.15,\"FALSE\",\"CREEPS\",,,,,\"330\",,,\"res://src/towers/tower_behaviors/tombstone.gd\",\"res://resources/icons/tower_icons/tombstone.tres\",\"res://src/towers/tower_sprites/tombstone_6.tscn\",\"YGBD\",\"XKCW\"\r\n\"Broken Circle of Wind\",1,312,312,\"SternBogen / Natac & girlfriend\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1100,1.4,54,56,0,0,50,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.7,0.02\",\"331\",,,\"res://src/towers/tower_behaviors/broken_circle_of_wind.gd\",\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"res://src/towers/tower_sprites/broken_circle_of_wind_1.tscn\",\"96MP\",\"0WMC\"\r\n\"Circle of Wind\",2,313,312,\"SternBogen / Natac & girlfriend\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1100,1.4,184,184,0,0,170,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.7,0.02\",\"332\",,,\"res://src/towers/tower_behaviors/broken_circle_of_wind.gd\",\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"res://src/towers/tower_sprites/broken_circle_of_wind_2.tscn\",\"5UH0\",\"0WMC\"\r\n\"Circle of Storm\",3,314,312,\"SternBogen / Natac & girlfriend\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1100,1.4,526,534,0,0,490,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.7,0.02\",\"333\",,,\"res://src/towers/tower_behaviors/broken_circle_of_wind.gd\",\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"res://src/towers/tower_sprites/broken_circle_of_wind_3.tscn\",\"CZ6I\",\"0WMC\"\r\n\"Orcan Circle\",4,315,312,\"SternBogen / Natac & girlfriend\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1100,1.4,1600,1611,0,0,1500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.7,0.02\",\"334\",,,\"res://src/towers/tower_behaviors/broken_circle_of_wind.gd\",\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"res://src/towers/tower_sprites/broken_circle_of_wind_4.tscn\",\"XCEF\",\"0WMC\"\r\n\"Hurricane Circle\",5,316,312,\"SternBogen / Natac & girlfriend\",\"uncommon\",\"storm\",\"TRUE\",\"physical\",1100,1.4,2953,2967,0,0,2800,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.7,0.02\",\"335\",,,\"res://src/towers/tower_behaviors/broken_circle_of_wind.gd\",\"res://resources/icons/tower_icons/broken_circle_of_wind.tres\",\"res://src/towers/tower_sprites/broken_circle_of_wind_5.tscn\",\"9SMW\",\"0WMC\"\r\n\"Death Knight\",1,317,317,\"DaveMatthews\",\"unique\",\"darkness\",\"TRUE\",\"decay\",875,1.1,2659,2659,50,0,3500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,2\",\"336,337\",,\"85\",\"res://src/towers/tower_behaviors/death_knight.gd\",\"res://resources/icons/tower_icons/death_knight.tres\",\"res://src/towers/tower_sprites/death_knight_1.tscn\",\"WIDA\",\"DR2Q\"\r\n\"Morphling\",1,319,319,\"DaveMatthews\",\"unique\",\"nature\",\"TRUE\",\"essence\",900,1.5,3910,3910,0,0,3100,1500,0,\"FALSE\",\"CREEPS\",,,,,\"338,339\",,\"86,87,88\",\"res://src/towers/tower_behaviors/morphling.gd\",\"res://resources/icons/tower_icons/morphling.tres\",\"res://src/towers/tower_sprites/morphling_1.tscn\",\"UM0W\",\"KAWF\"\r\n\"Ice Battery\",1,320,320,\"tolleder\",\"rare\",\"ice\",\"TRUE\",\"elemental\",800,3,822,822,250,2,500,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"340\",,\"89\",\"res://src/towers/tower_behaviors/ice_battery.gd\",\"res://resources/icons/tower_icons/ice_battery.tres\",\"res://src/towers/tower_sprites/ice_battery_1.tscn\",\"RVU8\",\"BXZW\"\r\n\"Ice Storage\",2,321,320,\"tolleder\",\"rare\",\"ice\",\"TRUE\",\"elemental\",800,3,1973,1973,300,2,1200,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"341\",,\"90\",\"res://src/towers/tower_behaviors/ice_battery.gd\",\"res://resources/icons/tower_icons/ice_battery.tres\",\"res://src/towers/tower_sprites/ice_battery_2.tscn\",\"XALH\",\"BXZW\"\r\n\"Ice Accumulator\",3,322,320,\"tolleder\",\"rare\",\"ice\",\"TRUE\",\"elemental\",800,3,4933,4933,350,2,3000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"342\",,\"91\",\"res://src/towers/tower_behaviors/ice_battery.gd\",\"res://resources/icons/tower_icons/ice_battery.tres\",\"res://src/towers/tower_sprites/ice_battery_3.tscn\",\"MRFS\",\"BXZW\"\r\n\"Wooden Trap\",1,325,325,\"Boekie\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",950,1.3,38,38,0,0,50,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"343\",,,\"res://src/towers/tower_behaviors/wooden_trap.gd\",\"res://resources/icons/tower_icons/wooden_trap.tres\",\"res://src/towers/tower_sprites/wooden_trap_1.tscn\",\"DISK\",\"Z5DC\"\r\n\"Advanced Wooden Trap\",2,623,325,\"Boekie\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",950,1.3,141,141,0,0,200,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"344\",,,\"res://src/towers/tower_behaviors/wooden_trap.gd\",\"res://resources/icons/tower_icons/wooden_trap.tres\",\"res://src/towers/tower_sprites/wooden_trap_2.tscn\",\"R2GY\",\"Z5DC\"\r\n\"Iron Trap\",3,624,325,\"Boekie\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",950,1.3,441,441,0,0,650,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"345\",,,\"res://src/towers/tower_behaviors/wooden_trap.gd\",\"res://resources/icons/tower_icons/wooden_trap.tres\",\"res://src/towers/tower_sprites/wooden_trap_3.tscn\",\"79UT\",\"Z5DC\"\r\n\"Advanced Iron Trap\",4,625,325,\"Boekie\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",950,1.3,942,942,0,0,1500,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"346\",,,\"res://src/towers/tower_behaviors/wooden_trap.gd\",\"res://resources/icons/tower_icons/wooden_trap.tres\",\"res://src/towers/tower_sprites/wooden_trap_4.tscn\",\"BPBB\",\"Z5DC\"\r\n\"Steel Trap\",5,626,325,\"Boekie\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",950,1.3,1409,1409,0,0,2500,1500,0.2,\"FALSE\",\"CREEPS\",,,,,\"347\",,,\"res://src/towers/tower_behaviors/wooden_trap.gd\",\"res://resources/icons/tower_icons/wooden_trap.tres\",\"res://src/towers/tower_sprites/wooden_trap_5.tscn\",\"1OWC\",\"Z5DC\"\r\n\"Gnoll Thunder Mage\",1,328,328,\"cedi\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,0.75,111,111,20,1,950,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"92\",\"res://src/towers/tower_behaviors/gnoll_thunder_mage.gd\",\"res://resources/icons/tower_icons/gnoll_thunder_mage.tres\",\"res://src/towers/tower_sprites/gnoll_thunder_mage_1.tscn\",\"0HVM\",\"LPMU\"\r\n\"Gnoll Lightning Caller\",2,326,328,\"cedi\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,0.75,222,222,20,1,1900,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"93\",\"res://src/towers/tower_behaviors/gnoll_thunder_mage.gd\",\"res://resources/icons/tower_icons/gnoll_thunder_mage.tres\",\"res://src/towers/tower_sprites/gnoll_thunder_mage_2.tscn\",\"1SHB\",\"LPMU\"\r\n\"Gnoll Storm Caster\",3,327,328,\"cedi\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,0.75,334,334,20,1,2850,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"94\",\"res://src/towers/tower_behaviors/gnoll_thunder_mage.gd\",\"res://resources/icons/tower_icons/gnoll_thunder_mage.tres\",\"res://src/towers/tower_sprites/gnoll_thunder_mage_3.tscn\",\"XEVX\",\"LPMU\"\r\n\"Green Lightning\",1,329,329,\"drol\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,2,486,635,65,0,500,9001,0.15,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.2,0\",\"348,349\",,\"95\",\"res://src/towers/tower_behaviors/green_lightning.gd\",\"res://resources/icons/tower_icons/green_lightning.tres\",\"res://src/towers/tower_sprites/green_lightning_1.tscn\",\"RO5W\",\"EUCU\"\r\n\"Green Thunder\",2,263,329,\"drol\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,2,763,1062,65,0,1000,9001,0.15,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.2,0\",\"350,351\",,\"96\",\"res://src/towers/tower_behaviors/green_lightning.gd\",\"res://resources/icons/tower_icons/green_lightning.tres\",\"res://src/towers/tower_sprites/green_lightning_2.tscn\",\"Q688\",\"EUCU\"\r\n\"Green Lightning Storm\",3,264,329,\"drol\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,2,1183,1782,65,0,2000,9001,0.15,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.2,0\",\"352,353\",,\"97\",\"res://src/towers/tower_behaviors/green_lightning.gd\",\"res://resources/icons/tower_icons/green_lightning.tres\",\"res://src/towers/tower_sprites/green_lightning_3.tscn\",\"W36G\",\"EUCU\"\r\n\"Green Thunder Storm\",4,265,329,\"drol\",\"rare\",\"storm\",\"TRUE\",\"energy\",1200,2,1375,2274,65,0,3000,9001,0.15,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.2,0\",\"354,355\",,\"98\",\"res://src/towers/tower_behaviors/green_lightning.gd\",\"res://resources/icons/tower_icons/green_lightning.tres\",\"res://src/towers/tower_sprites/green_lightning_4.tscn\",\"TKN5\",\"EUCU\"\r\n\"Magic Battery\",1,331,331,\"tolleder\",\"rare\",\"astral\",\"TRUE\",\"arcane\",800,3,822,822,250,2,500,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"356\",,\"99\",\"res://src/towers/tower_behaviors/magic_battery.gd\",\"res://resources/icons/tower_icons/magic_battery.tres\",\"res://src/towers/tower_sprites/magic_battery_1.tscn\",\"IHT5\",\"P7KZ\"\r\n\"Magic Storage\",2,332,331,\"tolleder\",\"rare\",\"astral\",\"TRUE\",\"arcane\",800,3,1973,1973,300,2,1200,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"357\",,\"100\",\"res://src/towers/tower_behaviors/magic_battery.gd\",\"res://resources/icons/tower_icons/magic_battery.tres\",\"res://src/towers/tower_sprites/magic_battery_2.tscn\",\"3NJP\",\"P7KZ\"\r\n\"Magic Accumulator\",3,334,331,\"tolleder\",\"rare\",\"astral\",\"TRUE\",\"arcane\",800,3,4933,4933,350,2,3000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"358\",,\"101\",\"res://src/towers/tower_behaviors/magic_battery.gd\",\"res://resources/icons/tower_icons/magic_battery.tres\",\"res://src/towers/tower_sprites/magic_battery_3.tscn\",\"IRPC\",\"P7KZ\"\r\n\"Sacrificial Lamb\",1,335,335,\"DaveMatthews\",\"rare\",\"darkness\",\"TRUE\",\"decay\",850,1,1234,1234,100,2.5,1300,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.1\",\"359\",,\"102\",\"res://src/towers/tower_behaviors/sacrificial_lamb.gd\",\"res://resources/icons/tower_icons/sacrificial_lamb.tres\",\"res://src/towers/tower_sprites/sacrificial_lamb_1.tscn\",\"YOHG\",\"DJYT\"\r\n\"Human Sacrifice\",2,336,335,\"DaveMatthews\",\"rare\",\"darkness\",\"TRUE\",\"decay\",850,1,2099,2099,100,2.5,2400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.2\",\"360\",,\"103\",\"res://src/towers/tower_behaviors/sacrificial_lamb.gd\",\"res://resources/icons/tower_icons/sacrificial_lamb.tres\",\"res://src/towers/tower_sprites/sacrificial_lamb_2.tscn\",\"0QCC\",\"DJYT\"\r\n\"Inexperienced Huntress\",1,338,338,\"cedi\",\"rare\",\"nature\",\"TRUE\",\"physical\",800,1.8,937,937,0,0,1000,900,0,\"FALSE\",\"CREEPS\",,,\"4,0.25\",\"MOD_ATTACKSPEED,0,0.024\",\"361,362\",,,\"res://src/towers/tower_behaviors/inexperienced_huntress.gd\",\"res://resources/icons/tower_icons/inexperienced_huntress.tres\",\"res://src/towers/tower_sprites/inexperienced_huntress_1.tscn\",\"E9I8\",\"W7OO\"\r\n\"Huntress\",2,339,338,\"cedi\",\"rare\",\"nature\",\"TRUE\",\"physical\",800,1.8,1730,1730,0,0,2000,900,0,\"FALSE\",\"CREEPS\",,,\"4,0.25\",\"MOD_ATTACKSPEED,0,0.024\",\"363,364\",,,\"res://src/towers/tower_behaviors/inexperienced_huntress.gd\",\"res://resources/icons/tower_icons/inexperienced_huntress.tres\",\"res://src/towers/tower_sprites/inexperienced_huntress_2.tscn\",\"LUKX\",\"W7OO\"\r\n\"Master Huntress\",3,340,338,\"cedi\",\"rare\",\"nature\",\"TRUE\",\"physical\",800,1.8,2409,2409,0,0,3000,900,0,\"FALSE\",\"CREEPS\",,,\"4,0.25\",\"MOD_ATTACKSPEED,0,0.024\",\"365,366\",,,\"res://src/towers/tower_behaviors/inexperienced_huntress.gd\",\"res://resources/icons/tower_icons/inexperienced_huntress.tres\",\"res://src/towers/tower_sprites/inexperienced_huntress_3.tscn\",\"LJQW\",\"W7OO\"\r\n\"Dark Battery\",1,345,345,\"tolleder\",\"rare\",\"darkness\",\"TRUE\",\"decay\",800,3,822,822,250,2,500,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"367\",,\"104\",\"res://src/towers/tower_behaviors/dark_battery.gd\",\"res://resources/icons/tower_icons/dark_battery.tres\",\"res://src/towers/tower_sprites/dark_battery_1.tscn\",\"9M93\",\"PYM9\"\r\n\"Dark Storage\",2,346,345,\"tolleder\",\"rare\",\"darkness\",\"TRUE\",\"decay\",800,3,1973,1973,300,2,1200,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"368\",,\"105\",\"res://src/towers/tower_behaviors/dark_battery.gd\",\"res://resources/icons/tower_icons/dark_battery.tres\",\"res://src/towers/tower_sprites/dark_battery_2.tscn\",\"UFAB\",\"PYM9\"\r\n\"Dark Accumulator\",3,347,345,\"tolleder\",\"rare\",\"darkness\",\"TRUE\",\"decay\",800,3,4933,4933,350,2,3000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"369\",,\"106\",\"res://src/towers/tower_behaviors/dark_battery.gd\",\"res://resources/icons/tower_icons/dark_battery.tres\",\"res://src/towers/tower_sprites/dark_battery_3.tscn\",\"1REI\",\"PYM9\"\r\n\"Poison Battery\",1,348,348,\"tolleder\",\"rare\",\"nature\",\"TRUE\",\"decay\",800,3,822,822,250,2,500,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"370\",,\"107\",\"res://src/towers/tower_behaviors/poison_battery.gd\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"res://src/towers/tower_sprites/poison_battery_1.tscn\",\"AB4O\",\"XQI0\"\r\n\"Poison Storage\",2,349,348,\"tolleder\",\"rare\",\"nature\",\"TRUE\",\"decay\",800,3,1973,1973,300,2,1200,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"371\",,\"108\",\"res://src/towers/tower_behaviors/poison_battery.gd\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"res://src/towers/tower_sprites/poison_battery_2.tscn\",\"W8JI\",\"XQI0\"\r\n\"Poison Accumulator\",3,350,348,\"tolleder\",\"rare\",\"nature\",\"TRUE\",\"decay\",800,3,4933,4933,350,2,3000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"372\",,\"109\",\"res://src/towers/tower_behaviors/poison_battery.gd\",\"res://resources/icons/tower_icons/poison_battery.tres\",\"res://src/towers/tower_sprites/poison_battery_3.tscn\",\"SY8E\",\"XQI0\"\r\n\"Fire Battery\",1,351,351,\"tolleder\",\"rare\",\"fire\",\"TRUE\",\"elemental\",800,3,822,822,250,2,500,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"373\",,\"110\",\"res://src/towers/tower_behaviors/fire_battery.gd\",\"res://resources/icons/tower_icons/fire_battery.tres\",\"res://src/towers/tower_sprites/fire_battery_1.tscn\",\"WVN4\",\"WY10\"\r\n\"Fire Storage\",2,352,351,\"tolleder\",\"rare\",\"fire\",\"TRUE\",\"elemental\",800,3,1973,1973,300,2,1200,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"374\",,\"111\",\"res://src/towers/tower_behaviors/fire_battery.gd\",\"res://resources/icons/tower_icons/fire_battery.tres\",\"res://src/towers/tower_sprites/fire_battery_2.tscn\",\"KD28\",\"WY10\"\r\n\"Fire Accumulator\",3,353,351,\"tolleder\",\"rare\",\"fire\",\"TRUE\",\"elemental\",800,3,4933,4933,350,2,3000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"375\",,\"112\",\"res://src/towers/tower_behaviors/fire_battery.gd\",\"res://resources/icons/tower_icons/fire_battery.tres\",\"res://src/towers/tower_sprites/fire_battery_3.tscn\",\"R6DF\",\"WY10\"\r\n\"Storm Battery\",1,357,357,\"tolleder\",\"rare\",\"storm\",\"TRUE\",\"energy\",800,3,822,822,250,2,500,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"376\",,\"113\",\"res://src/towers/tower_behaviors/storm_battery.gd\",\"res://resources/icons/tower_icons/storm_battery.tres\",\"res://src/towers/tower_sprites/storm_battery_1.tscn\",\"8LKY\",\"5L11\"\r\n\"Storm Storage\",2,358,357,\"tolleder\",\"rare\",\"storm\",\"TRUE\",\"energy\",800,3,1973,1973,300,2,1200,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"377\",,\"114\",\"res://src/towers/tower_behaviors/storm_battery.gd\",\"res://resources/icons/tower_icons/storm_battery.tres\",\"res://src/towers/tower_sprites/storm_battery_2.tscn\",\"IOLO\",\"5L11\"\r\n\"Storm Accumulator\",3,359,357,\"tolleder\",\"rare\",\"storm\",\"TRUE\",\"energy\",800,3,4933,4933,350,2,3000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10\",\"378\",,\"115\",\"res://src/towers/tower_behaviors/storm_battery.gd\",\"res://resources/icons/tower_icons/storm_battery.tres\",\"res://src/towers/tower_sprites/storm_battery_3.tscn\",\"XEKG\",\"5L11\"\r\n\"Ruined Sun Pedestal\",1,363,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,43,47,0,0,35,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.5\",\"MOD_DMG_TO_UNDEAD,0.2,0.02\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_1.tscn\",\"3WME\",\"QZWR\"\r\n\"Ruined Sun Pillar\",2,404,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,154,171,0,0,130,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.48\",\"MOD_DMG_TO_UNDEAD,0.21,0.021\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_2.tscn\",\"7RY8\",\"QZWR\"\r\n\"Flawed Sun Pillar\",3,448,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,370,414,0,0,320,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.46\",\"MOD_DMG_TO_UNDEAD,0.22,0.022\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_3.tscn\",\"CTAM\",\"QZWR\"\r\n\"Sun Pillar\",4,440,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,738,825,0,0,650,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.44\",\"MOD_DMG_TO_UNDEAD,0.23,0.023\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_4.tscn\",\"R3P3\",\"QZWR\"\r\n\"Sun Shrine\",5,445,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,1218,1374,0,0,1100,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.42\",\"MOD_DMG_TO_UNDEAD,0.24,0.024\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_5.tscn\",\"I70Z\",\"QZWR\"\r\n\"Sun Array\",6,446,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,1844,2085,0,0,1700,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.4\",\"MOD_DMG_TO_UNDEAD,0.25,0.025\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_6.tscn\",\"ESGD\",\"QZWR\"\r\n\"Sun Monument\",7,447,363,\"geX\",\"common\",\"astral\",\"TRUE\",\"energy\",1200,2,2654,3013,0,0,2500,1900,0,\"FALSE\",\"CREEPS\",,,\"3,0.38\",\"MOD_DMG_TO_UNDEAD,0.26,0.026\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_sun_pedestal.tres\",\"res://src/towers/tower_sprites/ruined_sun_pedestal_7.tscn\",\"11XW\",\"QZWR\"\r\n\"Small Frost Fire\",1,364,364,\"IamanEvilMan\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,0.9,46,46,25,2,70,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.25,0.002\",,,\"116\",\"res://src/towers/tower_behaviors/small_frost_fire.gd\",\"res://resources/icons/tower_icons/small_frost_fire.tres\",\"res://src/towers/tower_sprites/small_frost_fire_1.tscn\",\"YDGF\",\"1OMS\"\r\n\"Frost Fire\",2,365,364,\"IamanEvilMan\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,0.9,163,163,25,2,250,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.25,0.002\",,,\"117\",\"res://src/towers/tower_behaviors/small_frost_fire.gd\",\"res://resources/icons/tower_icons/small_frost_fire.tres\",\"res://src/towers/tower_sprites/small_frost_fire_2.tscn\",\"AUE6\",\"1OMS\"\r\n\"Hungry Frost Fire\",3,366,364,\"IamanEvilMan\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,0.9,456,456,25,2,700,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.25,0.002\",,,\"118\",\"res://src/towers/tower_behaviors/small_frost_fire.gd\",\"res://resources/icons/tower_icons/small_frost_fire.tres\",\"res://src/towers/tower_sprites/small_frost_fire_3.tscn\",\"7JGB\",\"1OMS\"\r\n\"Hungry Frozen Flame\",4,367,364,\"IamanEvilMan\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,0.9,911,911,25,2,1400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.25,0.002\",,,\"119\",\"res://src/towers/tower_behaviors/small_frost_fire.gd\",\"res://resources/icons/tower_icons/small_frost_fire.tres\",\"res://src/towers/tower_sprites/small_frost_fire_4.tscn\",\"GOT1\",\"1OMS\"\r\n\"Frozen Inferno\",5,368,364,\"IamanEvilMan\",\"common\",\"darkness\",\"TRUE\",\"essence\",900,0.9,1627,1627,25,2,2500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.25,0.002\",,,\"120\",\"res://src/towers/tower_behaviors/small_frost_fire.gd\",\"res://resources/icons/tower_icons/small_frost_fire.tres\",\"res://src/towers/tower_sprites/small_frost_fire_5.tscn\",\"G0OI\",\"1OMS\"\r\n\"Ymir\",1,372,372,\"IamanEvilMan\",\"unique\",\"ice\",\"TRUE\",\"elemental\",900,1.5,2300,2300,0,0,3800,1500,0,\"FALSE\",\"CREEPS\",,\"400,0.25\",,\"MOD_DAMAGE_BASE_PERC,0,0.1\",\"379,380\",\"46\",,\"res://src/towers/tower_behaviors/ymir.gd\",\"res://resources/icons/tower_icons/ymir.tres\",\"res://src/towers/tower_sprites/ymir_1.tscn\",\"KS7K\",\"CCH8\"\r\n\"Goblin Stronghold\",1,373,373,\"cedi\",\"unique\",\"iron\",\"TRUE\",\"physical\",800,2.5,897,906,0,0,2500,1200,0.2,\"FALSE\",\"CREEPS\",,,,,\"381,382,383,384\",,,\"res://src/towers/tower_behaviors/goblin_stronghold.gd\",\"res://resources/icons/tower_icons/goblin_stronghold.tres\",\"res://src/towers/tower_sprites/goblin_stronghold_1.tscn\",\"63KW\",\"977T\"\r\n\"Fire Star\",1,374,374,\"cedi\",\"unique\",\"fire\",\"TRUE\",\"elemental\",1000,2,900,900,0,0,3000,1000,0,\"FALSE\",\"CREEPS\",\"14\",,,,\"385,386\",,,\"res://src/towers/tower_behaviors/fire_star.gd\",\"res://resources/icons/tower_icons/fire_star.tres\",\"res://src/towers/tower_sprites/fire_star_1.tscn\",\"XH2D\",\"KHME\"\r\n\"Buried Soul\",1,376,376,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"arcane\",1200,1,10,71,0,0,80,30000,0,\"TRUE\",\"CREEPS\",,,,,\"387,388\",,,\"res://src/towers/tower_behaviors/buried_soul.gd\",\"res://resources/icons/tower_icons/buried_soul.tres\",\"res://src/towers/tower_sprites/buried_soul_1.tscn\",\"5CHD\",\"43FJ\"\r\n\"Lost Soul\",2,379,376,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"arcane\",1200,1,117,178,0,0,310,30000,0,\"TRUE\",\"CREEPS\",,,,,\"389,390\",,,\"res://src/towers/tower_behaviors/buried_soul.gd\",\"res://resources/icons/tower_icons/buried_soul.tres\",\"res://src/towers/tower_sprites/buried_soul_2.tscn\",\"VUEM\",\"43FJ\"\r\n\"Forgotten Soul\",3,384,376,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"arcane\",1200,1,528,589,0,0,1240,30000,0,\"TRUE\",\"CREEPS\",,,,,\"391,392\",,,\"res://src/towers/tower_behaviors/buried_soul.gd\",\"res://resources/icons/tower_icons/buried_soul.tres\",\"res://src/towers/tower_sprites/buried_soul_3.tscn\",\"5PUW\",\"43FJ\"\r\n\"Long Forgotten Soul\",4,395,376,\"SirCoqalot.\",\"uncommon\",\"darkness\",\"TRUE\",\"arcane\",1200,1,1014,1075,0,0,2450,30000,0,\"TRUE\",\"CREEPS\",,,,,\"393,394\",,,\"res://src/towers/tower_behaviors/buried_soul.gd\",\"res://resources/icons/tower_icons/buried_soul.tres\",\"res://src/towers/tower_sprites/buried_soul_4.tscn\",\"F6J3\",\"43FJ\"\r\n\"Magic Mushroom\",1,377,377,\"drol\",\"unique\",\"nature\",\"TRUE\",\"arcane\",900,0.9,1513,1612,60,4,3200,1000,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN,0,0.16\",\"395,396\",,\"121\",\"res://src/towers/tower_behaviors/magic_mushroom.gd\",\"res://resources/icons/tower_icons/magic_mushroom.tres\",\"res://src/towers/tower_sprites/magic_mushroom_1.tscn\",\"Q02O\",\"4S0E\"\r\n\"Lightning Generator\",1,378,378,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",980,1.35,1,1,0,0,92,10000,0,\"TRUE\",\"CREEPS\",,,,,\"397,398\",,,\"res://src/towers/tower_behaviors/lightning_generator.gd\",\"res://resources/icons/tower_icons/lightning_generator.tres\",\"res://src/towers/tower_sprites/lightning_generator_1.tscn\",\"UXVT\",\"SZVM\"\r\n\"Fortified Lightning Generator\",2,381,378,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",980,1.35,1,1,0,0,345,10000,0,\"TRUE\",\"CREEPS\",,,,,\"399,400\",,,\"res://src/towers/tower_behaviors/lightning_generator.gd\",\"res://resources/icons/tower_icons/lightning_generator.tres\",\"res://src/towers/tower_sprites/lightning_generator_2.tscn\",\"VX2A\",\"SZVM\"\r\n\"Stormcloud Generator\",3,382,378,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",980,1.35,1,1,0,0,1025,10000,0,\"TRUE\",\"CREEPS\",,,,,\"401,402\",,,\"res://src/towers/tower_behaviors/lightning_generator.gd\",\"res://resources/icons/tower_icons/lightning_generator.tres\",\"res://src/towers/tower_sprites/lightning_generator_3.tscn\",\"67HN\",\"SZVM\"\r\n\"Thunderstorm Generator\",4,383,378,\"SirCoqalot.\",\"uncommon\",\"storm\",\"TRUE\",\"arcane\",980,1.35,1,1,0,0,2450,10000,0,\"TRUE\",\"CREEPS\",,,,,\"403,404\",,,\"res://src/towers/tower_behaviors/lightning_generator.gd\",\"res://resources/icons/tower_icons/lightning_generator.tres\",\"res://src/towers/tower_sprites/lightning_generator_4.tscn\",\"JOH5\",\"SZVM\"\r\n\"Tiny Storm Lantern\",1,380,380,\"Boekie\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",1000,1.3,207,207,0,0,250,1500,0,\"FALSE\",\"CREEPS\",,,,,\"405\",,,\"res://src/towers/tower_behaviors/tiny_storm_lantern.gd\",\"res://resources/icons/tower_icons/tiny_storm_lantern.tres\",\"res://src/towers/tower_sprites/tiny_storm_lantern_1.tscn\",\"Y9H7\",\"RX76\"\r\n\"Storm Lantern\",2,551,380,\"Boekie\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",1000,1.3,529,529,0,0,750,1500,0,\"FALSE\",\"CREEPS\",,,,,\"406\",,,\"res://src/towers/tower_behaviors/tiny_storm_lantern.gd\",\"res://resources/icons/tower_icons/tiny_storm_lantern.tres\",\"res://src/towers/tower_sprites/tiny_storm_lantern_2.tscn\",\"56XT\",\"RX76\"\r\n\"Sparkling Storm Lantern\",3,552,380,\"Boekie\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",1000,1.3,990,990,0,0,1600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"407\",,,\"res://src/towers/tower_behaviors/tiny_storm_lantern.gd\",\"res://resources/icons/tower_icons/tiny_storm_lantern.tres\",\"res://src/towers/tower_sprites/tiny_storm_lantern_3.tscn\",\"A1E9\",\"RX76\"\r\n\"Electrified Storm Lantern\",4,553,380,\"Boekie\",\"uncommon\",\"storm\",\"TRUE\",\"energy\",1000,1.3,1525,1525,0,0,2800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"408\",,,\"res://src/towers/tower_behaviors/tiny_storm_lantern.gd\",\"res://resources/icons/tower_icons/tiny_storm_lantern.tres\",\"res://src/towers/tower_sprites/tiny_storm_lantern_4.tscn\",\"ASUO\",\"RX76\"\r\n\"Glowing Solar Orb\",1,385,385,\"MasterCassim\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.3,40,40,0,0,40,1050,0.3,\"FALSE\",\"CREEPS\",,\"125,0.45,225,0.15\",,\"MOD_DMG_TO_UNDEAD,0.15,0\",\"409\",,,\"res://src/towers/tower_behaviors/glowing_solar_orb.gd\",\"res://resources/icons/tower_icons/glowing_solar_orb.tres\",\"res://src/towers/tower_sprites/glowing_solar_orb_1.tscn\",\"JARK\",\"F6FP\"\r\n\"Glaring Solar Orb\",2,389,385,\"MasterCassim\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.3,242,242,0,0,250,1050,0.3,\"FALSE\",\"CREEPS\",,\"125,0.45,225,0.2\",,\"MOD_DMG_TO_UNDEAD,0.15,0\",\"410\",,,\"res://src/towers/tower_behaviors/glowing_solar_orb.gd\",\"res://resources/icons/tower_icons/glowing_solar_orb.tres\",\"res://src/towers/tower_sprites/glowing_solar_orb_2.tscn\",\"86WO\",\"F6FP\"\r\n\"Glowing Sun Orb\",3,390,385,\"MasterCassim\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.3,562,562,0,0,600,1050,0.3,\"FALSE\",\"CREEPS\",,\"125,0.5,225,0.25\",,\"MOD_DMG_TO_UNDEAD,0.15,0\",\"411\",,,\"res://src/towers/tower_behaviors/glowing_solar_orb.gd\",\"res://resources/icons/tower_icons/glowing_solar_orb.tres\",\"res://src/towers/tower_sprites/glowing_solar_orb_3.tscn\",\"RVMN\",\"F6FP\"\r\n\"Shiny Sun Orb\",4,387,385,\"MasterCassim\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.3,1420,1420,0,0,1550,1050,0.3,\"FALSE\",\"CREEPS\",,\"125,0.5,225,0.3\",,\"MOD_DMG_TO_UNDEAD,0.15,0\",\"412\",,,\"res://src/towers/tower_behaviors/glowing_solar_orb.gd\",\"res://resources/icons/tower_icons/glowing_solar_orb.tres\",\"res://src/towers/tower_sprites/glowing_solar_orb_4.tscn\",\"XBGJ\",\"F6FP\"\r\n\"Blazing Sun Orb\",5,388,385,\"MasterCassim\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.3,2300,2300,0,0,2600,1050,0.3,\"FALSE\",\"CREEPS\",,\"125,0.55,225,0.35\",,\"MOD_DMG_TO_UNDEAD,0.15,0\",\"413\",,,\"res://src/towers/tower_behaviors/glowing_solar_orb.gd\",\"res://resources/icons/tower_icons/glowing_solar_orb.tres\",\"res://src/towers/tower_sprites/glowing_solar_orb_5.tscn\",\"4ZY8\",\"F6FP\"\r\n\"Forest Protectress\",1,386,386,\"cedi\",\"unique\",\"nature\",\"TRUE\",\"physical\",900,2.2,2896,2896,0,0,2900,1250,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DAMAGE_BASE_PERC,0,0.06\",\"414,415\",\"47\",,\"res://src/towers/tower_behaviors/forest_protectress.gd\",\"res://resources/icons/tower_icons/forest_protectress.tres\",\"res://src/towers/tower_sprites/forest_protectress_1.tscn\",\"5DP8\",\"HYUV\"\r\n\"The Steam Engine\",1,391,391,\"Glowackos/cedi\",\"unique\",\"iron\",\"FALSE\",\"physical\",800,1,1,1,1000,10,4000,1200,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,10|MOD_MANA_REGEN_PERC,0,0.05\",\"416\",\"48\",\"122,123\",\"res://src/towers/tower_behaviors/the_steam_engine.gd\",\"res://resources/icons/tower_icons/the_steam_engine.tres\",\"res://src/towers/tower_sprites/the_steam_engine_1.tscn\",\"OF8N\",\"ELT2\"\r\n\"Shaman\",1,392,392,\"His_Shadow\",\"rare\",\"fire\",\"TRUE\",\"essence\",900,1.5,462,462,20,1,700,1150,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0\",,\"49\",\"124\",\"res://src/towers/tower_behaviors/shaman.gd\",\"res://resources/icons/tower_icons/shaman.tres\",\"res://src/towers/tower_sprites/shaman_1.tscn\",\"Z9ID\",\"IM1T\"\r\n\"Shaman Cheftain\",2,393,392,\"His_Shadow\",\"rare\",\"fire\",\"TRUE\",\"essence\",900,1.5,809,809,20,1,1400,1150,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0\",,\"50\",\"125\",\"res://src/towers/tower_behaviors/shaman.gd\",\"res://resources/icons/tower_icons/shaman.tres\",\"res://src/towers/tower_sprites/shaman_2.tscn\",\"ZUGK\",\"IM1T\"\r\n\"Shaman Master\",3,394,392,\"His_Shadow\",\"rare\",\"fire\",\"TRUE\",\"essence\",900,1.5,1387,1387,20,1,2800,1150,0.15,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0\",,\"51\",\"126\",\"res://src/towers/tower_behaviors/shaman.gd\",\"res://resources/icons/tower_icons/shaman.tres\",\"res://src/towers/tower_sprites/shaman_3.tscn\",\"FBXE\",\"IM1T\"\r\n\"Nature Sprites\",1,396,396,\"DaveMatthews\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",900,2.5,338,338,50,2.5,400,1100,0,\"FALSE\",\"CREEPS\",,,,,,,\"127\",\"res://src/towers/tower_behaviors/nature_sprites.gd\",\"res://resources/icons/tower_icons/nature_sprites.tres\",\"res://src/towers/tower_sprites/nature_sprites_1.tscn\",\"DV24\",\"NZKE\"\r\n\"Nature Spirits\",2,397,396,\"DaveMatthews\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",900,2.5,1267,1267,50,2.5,1500,1100,0,\"FALSE\",\"CREEPS\",,,,,,,\"128\",\"res://src/towers/tower_behaviors/nature_sprites.gd\",\"res://resources/icons/tower_icons/nature_sprites.tres\",\"res://src/towers/tower_sprites/nature_sprites_2.tscn\",\"0SVZ\",\"NZKE\"\r\n\"Nature Souls\",3,398,396,\"DaveMatthews\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",900,2.5,2364,2364,50,2.5,2800,1100,0,\"FALSE\",\"CREEPS\",,,,,,,\"129\",\"res://src/towers/tower_behaviors/nature_sprites.gd\",\"res://resources/icons/tower_icons/nature_sprites.tres\",\"res://src/towers/tower_sprites/nature_sprites_3.tscn\",\"AZE4\",\"NZKE\"\r\n\"The Conduit\",1,399,399,\"Ashbringer\",\"unique\",\"storm\",\"TRUE\",\"arcane\",1200,2,1,1,1000,0,4000,1000,0,\"FALSE\",\"CREEPS\",\"10\",,,\"MOD_SPELL_CRIT_CHANCE,0.0375,0.005|MOD_SPELL_CRIT_DAMAGE,0.25,0.05\",\"417\",\"52\",\"130\",\"res://src/towers/tower_behaviors/the_conduit.gd\",\"res://resources/icons/tower_icons/the_conduit.tres\",\"res://src/towers/tower_sprites/the_conduit_1.tscn\",\"VR9K\",\"N2HI\"\r\n\"Particle Accelerator\",1,400,400,\"the_red_terror\",\"rare\",\"iron\",\"TRUE\",\"energy\",900,1,426,426,0,0,600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"418,419\",,,\"res://src/towers/tower_behaviors/particle_accelerator.gd\",\"res://resources/icons/tower_icons/particle_accelerator.tres\",\"res://src/towers/tower_sprites/particle_accelerator_1.tscn\",\"BFOI\",\"W31T\"\r\n\"Atom Smasher\",2,402,400,\"the_red_terror\",\"rare\",\"iron\",\"TRUE\",\"energy\",900,1,780,780,0,0,1200,1500,0,\"FALSE\",\"CREEPS\",,,,,\"420,421\",,,\"res://src/towers/tower_behaviors/particle_accelerator.gd\",\"res://resources/icons/tower_icons/particle_accelerator.tres\",\"res://src/towers/tower_sprites/particle_accelerator_2.tscn\",\"P9T9\",\"W31T\"\r\n\"Supercollider\",3,403,400,\"the_red_terror\",\"rare\",\"iron\",\"TRUE\",\"energy\",900,1,1413,1413,0,0,2400,1500,0,\"FALSE\",\"CREEPS\",,,,,\"422,423\",,,\"res://src/towers/tower_behaviors/particle_accelerator.gd\",\"res://resources/icons/tower_icons/particle_accelerator.tres\",\"res://src/towers/tower_sprites/particle_accelerator_3.tscn\",\"I46D\",\"W31T\"\r\n\"Helicopter Zone\",1,401,401,\"Deemzul\",\"unique\",\"iron\",\"TRUE\",\"physical\",1000,0.25,775,775,0,0,4500,1000,0.5,\"FALSE\",\"CREEPS\",,,,,\"424,425\",,\"131\",\"res://src/towers/tower_behaviors/helicopter_zone.gd\",\"res://resources/icons/tower_icons/helicopter_zone.tres\",\"res://src/towers/tower_sprites/helicopter_zone_1.tscn\",\"136D\",\"D8CW\"\r\n\"Felweed\",1,405,405,\"SirCoqalot.\",\"common\",\"fire\",\"TRUE\",\"decay\",750,1,49,49,0,0,55,1500,0,\"FALSE\",\"CREEPS\",,,,,\"426\",,,\"res://src/towers/tower_behaviors/felweed.gd\",\"res://resources/icons/tower_icons/felweed.tres\",\"res://src/towers/tower_sprites/felweed_1.tscn\",\"QLQJ\",\"N5HH\"\r\n\"Grown Felweed\",2,406,405,\"SirCoqalot.\",\"common\",\"fire\",\"TRUE\",\"decay\",750,1,192,192,0,0,215,1500,0,\"FALSE\",\"CREEPS\",,,,,\"427\",,,\"res://src/towers/tower_behaviors/felweed.gd\",\"res://resources/icons/tower_icons/felweed.tres\",\"res://src/towers/tower_sprites/felweed_2.tscn\",\"2ZVC\",\"N5HH\"\r\n\"Rancid Felweed\",3,407,405,\"SirCoqalot.\",\"common\",\"fire\",\"TRUE\",\"decay\",750,1,423,423,0,0,510,1500,0,\"FALSE\",\"CREEPS\",,,,,\"428\",,,\"res://src/towers/tower_behaviors/felweed.gd\",\"res://resources/icons/tower_icons/felweed.tres\",\"res://src/towers/tower_sprites/felweed_3.tscn\",\"CH0V\",\"N5HH\"\r\n\"Old Felweed\",4,408,405,\"SirCoqalot.\",\"common\",\"fire\",\"TRUE\",\"decay\",750,1,912,912,0,0,1100,1500,0,\"FALSE\",\"CREEPS\",,,,,\"429\",,,\"res://src/towers/tower_behaviors/felweed.gd\",\"res://resources/icons/tower_icons/felweed.tres\",\"res://src/towers/tower_sprites/felweed_4.tscn\",\"M1MT\",\"N5HH\"\r\n\"Elder Felweed\",5,409,405,\"SirCoqalot.\",\"common\",\"fire\",\"TRUE\",\"decay\",750,1,1360,1360,0,0,1800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"430\",,,\"res://src/towers/tower_behaviors/felweed.gd\",\"res://resources/icons/tower_icons/felweed.tres\",\"res://src/towers/tower_sprites/felweed_5.tscn\",\"WX8F\",\"N5HH\"\r\n\"Ancient Felweed\",6,410,405,\"SirCoqalot.\",\"common\",\"fire\",\"TRUE\",\"decay\",750,1,1889,1889,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"431\",,,\"res://src/towers/tower_behaviors/felweed.gd\",\"res://resources/icons/tower_icons/felweed.tres\",\"res://src/towers/tower_sprites/felweed_6.tscn\",\"HL5U\",\"N5HH\"\r\n\"Mister Fireflies\",1,411,411,\"Deemzul\",\"rare\",\"darkness\",\"TRUE\",\"arcane\",600,2,1,1,0,0,1000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.3,0|MOD_DMG_TO_MAGIC,0.2,0|MOD_SPELL_DAMAGE_DEALT,0,0.08\",\"432,433\",,,\"res://src/towers/tower_behaviors/mister_fireflies.gd\",\"res://resources/icons/tower_icons/mister_fireflies.tres\",\"res://src/towers/tower_sprites/mister_fireflies_1.tscn\",\"PG2P\",\"YO05\"\r\n\"Sir Fireflies\",2,412,411,\"Deemzul\",\"rare\",\"darkness\",\"TRUE\",\"arcane\",600,2,1,1,0,0,1750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.3,0|MOD_DMG_TO_MAGIC,0.2,0|MOD_SPELL_DAMAGE_DEALT,0,0.08\",\"434,435\",,,\"res://src/towers/tower_behaviors/mister_fireflies.gd\",\"res://resources/icons/tower_icons/mister_fireflies.tres\",\"res://src/towers/tower_sprites/mister_fireflies_2.tscn\",\"2GU1\",\"YO05\"\r\n\"Lord of the Fireflies\",3,413,411,\"Deemzul\",\"rare\",\"darkness\",\"TRUE\",\"arcane\",600,2,1,1,0,0,1750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.3,0|MOD_DMG_TO_MAGIC,0.2,0|MOD_SPELL_DAMAGE_DEALT,0,0.08\",\"436,437\",,,\"res://src/towers/tower_behaviors/mister_fireflies.gd\",\"res://resources/icons/tower_icons/mister_fireflies.tres\",\"res://src/towers/tower_sprites/mister_fireflies_3.tscn\",\"O53J\",\"YO05\"\r\n\"Dutchman's Grave\",1,414,414,\"cedi\",\"unique\",\"darkness\",\"TRUE\",\"physical\",2000,2.5,7138,7138,0,0,5000,10000,0,\"TRUE\",\"CREEPS\",,,,,\"438,439,440\",,\"132\",\"res://src/towers/tower_behaviors/dutchmans_grave.gd\",\"res://resources/icons/tower_icons/dutchmans_grave.tres\",\"res://src/towers/tower_sprites/dutchmans_grave_1.tscn\",\"7WW6\",\"OAEM\"\r\n\"Prince of Lightning\",1,415,415,\"Boekie\",\"rare\",\"storm\",\"TRUE\",\"energy\",1300,1.5,213,217,0,0,1200,2000,0,\"FALSE\",\"CREEPS\",,,\"5,0.3\",\"MOD_SPELL_CRIT_CHANCE,0.0375,0.0025\",\"441\",\"53\",,\"res://src/towers/tower_behaviors/prince_of_lightning.gd\",\"res://resources/icons/tower_icons/prince_of_lightning.tres\",\"res://src/towers/tower_sprites/prince_of_lightning_1.tscn\",\"3HMF\",\"UUV7\"\r\n\"King of Lightning\",2,416,415,\"Boekie\",\"rare\",\"storm\",\"TRUE\",\"energy\",1300,1.5,321,325,0,0,2500,2000,0,\"FALSE\",\"CREEPS\",,,\"5,0.3\",\"MOD_SPELL_CRIT_CHANCE,0.0375,0.005\",\"442\",\"54\",,\"res://src/towers/tower_behaviors/prince_of_lightning.gd\",\"res://resources/icons/tower_icons/prince_of_lightning.tres\",\"res://src/towers/tower_sprites/prince_of_lightning_2.tscn\",\"JF3G\",\"UUV7\"\r\n\"Militia Watchtower\",1,417,417,\"ShyGnome\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",850,0.7,71,71,0,0,250,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,-0.2,0.006|MOD_DMG_TO_UNDEAD,-0.2,0.004|MOD_DMG_TO_NATURE,0.2,0.004\",\"443\",,,\"res://src/towers/tower_behaviors/militia_watchtower.gd\",\"res://resources/icons/tower_icons/militia_watchtower.tres\",\"res://src/towers/tower_sprites/militia_watchtower_1.tscn\",\"Z4H4\",\"3CZN\"\r\n\"Militia Outpost\",2,418,417,\"ShyGnome\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",850,0.7,213,213,0,0,750,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,-0.2,0.007|MOD_DMG_TO_UNDEAD,-0.2,0.005|MOD_DMG_TO_NATURE,0.2,0.005\",\"444\",,,\"res://src/towers/tower_behaviors/militia_watchtower.gd\",\"res://resources/icons/tower_icons/militia_watchtower.tres\",\"res://src/towers/tower_sprites/militia_watchtower_2.tscn\",\"PDHU\",\"3CZN\"\r\n\"Militia Forepost\",3,419,417,\"ShyGnome\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",850,0.7,426,426,0,0,1500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,-0.2,0.008|MOD_DMG_TO_UNDEAD,-0.2,0.006|MOD_DMG_TO_NATURE,0.2,0.006\",\"445\",,,\"res://src/towers/tower_behaviors/militia_watchtower.gd\",\"res://resources/icons/tower_icons/militia_watchtower.tres\",\"res://src/towers/tower_sprites/militia_watchtower_3.tscn\",\"0K40\",\"3CZN\"\r\n\"Militia Blockpost\",4,420,417,\"ShyGnome\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",850,0.7,853,853,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,-0.2,0.009|MOD_DMG_TO_UNDEAD,-0.2,0.007|MOD_DMG_TO_NATURE,0.2,0.007\",\"446\",,,\"res://src/towers/tower_behaviors/militia_watchtower.gd\",\"res://resources/icons/tower_icons/militia_watchtower.tres\",\"res://src/towers/tower_sprites/militia_watchtower_4.tscn\",\"B1GV\",\"3CZN\"\r\n\"Firestorm Cell\",1,421,421,\"Ashbringer\",\"uncommon\",\"fire\",\"TRUE\",\"arcane\",900,1.3,106,106,0,0,200,1300,0,\"FALSE\",\"CREEPS\",,,,,\"447\",,,\"res://src/towers/tower_behaviors/firestorm_cell.gd\",\"res://resources/icons/tower_icons/firestorm_cell.tres\",\"res://src/towers/tower_sprites/firestorm_cell_1.tscn\",\"TI2H\",\"G1LI\"\r\n\"Firestorm Core\",2,424,421,\"Ashbringer\",\"uncommon\",\"fire\",\"TRUE\",\"arcane\",900,1.3,319,319,0,0,600,1300,0,\"FALSE\",\"CREEPS\",,,,,\"448\",,,\"res://src/towers/tower_behaviors/firestorm_cell.gd\",\"res://resources/icons/tower_icons/firestorm_cell.tres\",\"res://src/towers/tower_sprites/firestorm_cell_2.tscn\",\"RLSZ\",\"G1LI\"\r\n\"Firestorm Generator\",3,422,421,\"Ashbringer\",\"uncommon\",\"fire\",\"TRUE\",\"arcane\",900,1.3,850,850,0,0,1600,1300,0,\"FALSE\",\"CREEPS\",,,,,\"449\",,,\"res://src/towers/tower_behaviors/firestorm_cell.gd\",\"res://resources/icons/tower_icons/firestorm_cell.tres\",\"res://src/towers/tower_sprites/firestorm_cell_3.tscn\",\"4JB9\",\"G1LI\"\r\n\"Firestorm Reactor\",4,423,421,\"Ashbringer\",\"uncommon\",\"fire\",\"TRUE\",\"arcane\",900,1.3,1487,1487,0,0,2800,1300,0,\"FALSE\",\"CREEPS\",,,,,\"450\",,,\"res://src/towers/tower_behaviors/firestorm_cell.gd\",\"res://resources/icons/tower_icons/firestorm_cell.tres\",\"res://src/towers/tower_sprites/firestorm_cell_4.tscn\",\"2TO4\",\"G1LI\"\r\n\"Drake Whisperer\",1,426,426,\"Ely\",\"unique\",\"astral\",\"TRUE\",\"elemental\",1000,1.9,3109,3138,0,0,3500,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_AIR,0.15,0.004\",\"451,452,453\",,,\"res://src/towers/tower_behaviors/drake_whisperer.gd\",\"res://resources/icons/tower_icons/drake_whisperer.tres\",\"res://src/towers/tower_sprites/drake_whisperer_1.tscn\",\"JRL4\",\"UK28\"\r\n\"Teacher\",1,427,427,\"Deikorim/limfa\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",900,1.5,86,90,0,0,70,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.2,0\",\"454\",,,\"res://src/towers/tower_behaviors/teacher.gd\",\"res://resources/icons/tower_icons/teacher.tres\",\"res://src/towers/tower_sprites/teacher_1.tscn\",\"W55X\",\"9OXZ\"\r\n\"Clever Teacher\",2,428,427,\"Deikorim/limfa\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",900,1.5,225,229,0,0,180,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.35,0\",\"455\",,,\"res://src/towers/tower_behaviors/teacher.gd\",\"res://resources/icons/tower_icons/teacher.tres\",\"res://src/towers/tower_sprites/teacher_2.tscn\",\"S8X4\",\"9OXZ\"\r\n\"Learned Teacher\",3,429,427,\"Deikorim/limfa\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",900,1.5,439,443,0,0,350,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.45,0\",\"456\",,,\"res://src/towers/tower_behaviors/teacher.gd\",\"res://resources/icons/tower_icons/teacher.tres\",\"res://src/towers/tower_sprites/teacher_3.tscn\",\"HSVE\",\"9OXZ\"\r\n\"Studied Teacher\",4,430,427,\"Deikorim/limfa\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",900,1.5,1070,1074,0,0,850,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.6,0\",\"457\",,,\"res://src/towers/tower_behaviors/teacher.gd\",\"res://resources/icons/tower_icons/teacher.tres\",\"res://src/towers/tower_sprites/teacher_4.tscn\",\"INXM\",\"9OXZ\"\r\n\"Doctorated Teacher\",5,431,427,\"Deikorim/limfa\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",900,1.5,2016,2020,0,0,1600,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.7,0\",\"458\",,,\"res://src/towers/tower_behaviors/teacher.gd\",\"res://resources/icons/tower_icons/teacher.tres\",\"res://src/towers/tower_sprites/teacher_5.tscn\",\"VLIE\",\"9OXZ\"\r\n\"All-Knowing Teacher\",6,432,427,\"Deikorim/limfa\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",900,1.5,3151,3155,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.8,0\",\"459\",,,\"res://src/towers/tower_behaviors/teacher.gd\",\"res://resources/icons/tower_icons/teacher.tres\",\"res://src/towers/tower_sprites/teacher_6.tscn\",\"7T6N\",\"9OXZ\"\r\n\"Soulflame Device\",1,433,433,\"Ashbringer\",\"unique\",\"darkness\",\"TRUE\",\"decay\",1000,1.5,1344,1344,100,0,4000,1400,0,\"FALSE\",\"CREEPS\",\"8\",,,\"MOD_DMG_TO_UNDEAD,-0.4,0.01\",\"460,461\",\"55\",\"133\",\"res://src/towers/tower_behaviors/soulflame_device.gd\",\"res://resources/icons/tower_icons/soulflame_device.tres\",\"res://src/towers/tower_sprites/soulflame_device_1.tscn\",\"M80H\",\"35XB\"\r\n\"The Furnace\",1,434,434,\"Ashbringer\",\"unique\",\"fire\",\"TRUE\",\"elemental\",1000,1.8,988,988,3000,0,4000,1500,0.1,\"FALSE\",\"CREEPS\",,\"300,1\",,,\"462,463,464\",\"56\",\"134\",\"res://src/towers/tower_behaviors/the_furnace.gd\",\"res://resources/icons/tower_icons/the_furnace.tres\",\"res://src/towers/tower_sprites/the_furnace_1.tscn\",\"48JR\",\"VMNS\"\r\n\"Glaive Master\",1,435,435,\"Ashbringer\",\"unique\",\"iron\",\"TRUE\",\"physical\",1000,1.4,1855,1855,0,0,3600,1300,0,\"FALSE\",\"CREEPS\",,,\"2,0\",,\"465,466,467\",,\"135\",\"res://src/towers/tower_behaviors/glaive_master.gd\",\"res://resources/icons/tower_icons/glaive_master.tres\",\"res://src/towers/tower_sprites/glaive_master_1.tscn\",\"WM45\",\"MZPT\"\r\n\"Arcane Storm\",1,436,436,\"Ashbringer\",\"unique\",\"storm\",\"TRUE\",\"energy\",1200,1.5,998,998,150,0,3400,9001,0,\"TRUE\",\"CREEPS\",,,,,\"468,469,470\",,,\"res://src/towers/tower_behaviors/arcane_storm.gd\",\"res://resources/icons/tower_icons/arcane_storm.tres\",\"res://src/towers/tower_sprites/arcane_storm_1.tscn\",\"Q501\",\"WO1L\"\r\n\"Ebonfrost Crystal\",1,437,437,\"Ashbringer\",\"unique\",\"ice\",\"TRUE\",\"elemental\",1000,1.6,1960,1960,400,0,3600,1050,0,\"FALSE\",\"CREEPS\",,,,,\"471,472,473\",,\"136\",\"res://src/towers/tower_behaviors/ebonfrost_crystal.gd\",\"res://resources/icons/tower_icons/ebonfrost_crystal.tres\",\"res://src/towers/tower_sprites/ebonfrost_crystal_1.tscn\",\"JOSQ\",\"UOS8\"\r\n\"Kraken\",1,438,438,\"cedi, Deemzul, His_Shadow\",\"unique\",\"darkness\",\"TRUE\",\"decay\",1200,5,5289,5289,0,0,3500,1050,0.35,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.01|MOD_ATTACKSPEED,0,0.02\",\"474,475,476\",,,\"res://src/towers/tower_behaviors/kraken.gd\",\"res://resources/icons/tower_icons/kraken.tres\",\"res://src/towers/tower_sprites/kraken_1.tscn\",\"L6Z3\",\"RLB8\"\r\n\"Icy Skulls\",1,442,442,\"MasterCassim\",\"common\",\"ice\",\"TRUE\",\"elemental\",700,1.5,53,58,0,0,35,1100,0,\"FALSE\",\"CREEPS\",,,,,\"477\",,,\"res://src/towers/tower_behaviors/icy_skulls.gd\",\"res://resources/icons/tower_icons/icy_skulls.tres\",\"res://src/towers/tower_sprites/icy_skulls_1.tscn\",\"2FDJ\",\"040Y\"\r\n\"Icy Bones\",2,425,442,\"MasterCassim\",\"common\",\"ice\",\"TRUE\",\"elemental\",700,1.5,589,594,0,0,375,1100,0,\"FALSE\",\"CREEPS\",,,,,\"478\",,,\"res://src/towers/tower_behaviors/icy_skulls.gd\",\"res://resources/icons/tower_icons/icy_skulls.tres\",\"res://src/towers/tower_sprites/icy_skulls_2.tscn\",\"9BAQ\",\"040Y\"\r\n\"Icy Skeleton\",3,441,442,\"MasterCassim\",\"common\",\"ice\",\"TRUE\",\"elemental\",700,1.5,1967,1972,0,0,1250,1100,0,\"FALSE\",\"CREEPS\",,,,,\"479\",,,\"res://src/towers/tower_behaviors/icy_skulls.gd\",\"res://resources/icons/tower_icons/icy_skulls.tres\",\"res://src/towers/tower_sprites/icy_skulls_3.tscn\",\"PCFE\",\"040Y\"\r\n\"Icy Boneyard\",4,443,442,\"MasterCassim\",\"common\",\"ice\",\"TRUE\",\"elemental\",700,1.5,3503,3508,0,0,2225,1100,0,\"FALSE\",\"CREEPS\",,,,,\"480\",,,\"res://src/towers/tower_behaviors/icy_skulls.gd\",\"res://resources/icons/tower_icons/icy_skulls.tres\",\"res://src/towers/tower_sprites/icy_skulls_4.tscn\",\"GWPN\",\"040Y\"\r\n\"The Frozen Wyrm\",1,444,444,\"MasterCassim\",\"unique\",\"ice\",\"TRUE\",\"elemental\",850,2.75,4921,4930,0,0,2600,1100,0,\"FALSE\",\"CREEPS\",,\"550,0.2\",,,\"481\",,,\"res://src/towers/tower_behaviors/the_frozen_wyrm.gd\",\"res://resources/icons/tower_icons/the_frozen_wyrm.tres\",\"res://src/towers/tower_sprites/the_frozen_wyrm_1.tscn\",\"EEB2\",\"RM1T\"\r\n\"Snowy Pebble\",1,449,449,\"geX\",\"common\",\"ice\",\"TRUE\",\"elemental\",700,0.9,22,24,0,0,30,1500,0,\"FALSE\",\"CREEPS\",,\"600,0.1\",,\"MOD_DMG_TO_MASS,0.3,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/snowy_pebble.tres\",\"res://src/towers/tower_sprites/snowy_pebble_1.tscn\",\"5FCK\",\"M9MJ\"\r\n\"Snowy Stone\",2,454,449,\"geX\",\"common\",\"ice\",\"TRUE\",\"elemental\",720,0.9,96,121,0,0,140,1500,0,\"FALSE\",\"CREEPS\",,\"600,0.1\",,\"MOD_DMG_TO_MASS,0.33,0.011\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/snowy_pebble.tres\",\"res://src/towers/tower_sprites/snowy_pebble_2.tscn\",\"FQ5E\",\"M9MJ\"\r\n\"Snowy Rock\",3,455,449,\"geX\",\"common\",\"ice\",\"TRUE\",\"elemental\",740,0.9,242,302,0,0,360,1500,0,\"FALSE\",\"CREEPS\",,\"600,0.1\",,\"MOD_DMG_TO_MASS,0.36,0.012\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/snowy_pebble.tres\",\"res://src/towers/tower_sprites/snowy_pebble_3.tscn\",\"GZ5Q\",\"M9MJ\"\r\n\"Snowy Rock Formation\",4,456,449,\"geX\",\"common\",\"ice\",\"TRUE\",\"elemental\",760,0.9,481,601,0,0,730,1500,0,\"FALSE\",\"CREEPS\",,\"600,0.1\",,\"MOD_DMG_TO_MASS,0.39,0.013\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/snowy_pebble.tres\",\"res://src/towers/tower_sprites/snowy_pebble_4.tscn\",\"6T51\",\"M9MJ\"\r\n\"Snowy Cliff\",5,452,449,\"geX\",\"common\",\"ice\",\"TRUE\",\"elemental\",780,0.9,850,1040,0,0,1300,1500,0,\"FALSE\",\"CREEPS\",,\"600,0.1\",,\"MOD_DMG_TO_MASS,0.42,0.014\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/snowy_pebble.tres\",\"res://src/towers/tower_sprites/snowy_pebble_5.tscn\",\"ADA6\",\"M9MJ\"\r\n\"Snowy Peak\",6,457,449,\"geX\",\"common\",\"ice\",\"TRUE\",\"elemental\",800,0.9,1471,1671,0,0,2200,1500,0,\"FALSE\",\"CREEPS\",,\"600,0.1\",,\"MOD_DMG_TO_MASS,0.45,0.015\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/snowy_pebble.tres\",\"res://src/towers/tower_sprites/snowy_pebble_6.tscn\",\"BBVA\",\"M9MJ\"\r\n\"Soul Vault\",1,453,453,\"SirCoqalot.\",\"unique\",\"darkness\",\"TRUE\",\"decay\",775,3,6155,9155,0,0,2800,30000,0,\"TRUE\",\"CREEPS\",,,,,\"482,483\",\"57\",,\"res://src/towers/tower_behaviors/soul_vault.gd\",\"res://resources/icons/tower_icons/soul_vault.tres\",\"res://src/towers/tower_sprites/soul_vault_1.tscn\",\"M53H\",\"JKRL\"\r\n\"Trash Heap\",1,458,458,\"geX\",\"common\",\"iron\",\"TRUE\",\"physical\",1000,2.5,86,96,0,0,35,1200,0.25,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.006|MOD_ITEM_CHANCE_ON_KILL,0.2,0.005|MOD_ITEM_QUALITY_ON_KILL,-0.2,-0.005\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/trash_heap.tres\",\"res://src/towers/tower_sprites/trash_heap_1.tscn\",\"AU90\",\"C93K\"\r\n\"Spare Part Heap\",2,460,458,\"geX\",\"common\",\"iron\",\"TRUE\",\"physical\",1000,2.5,398,450,0,0,165,1200,0.25,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.006|MOD_ITEM_CHANCE_ON_KILL,0.2,0.006|MOD_ITEM_QUALITY_ON_KILL,-0.2,-0.006\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/trash_heap.tres\",\"res://src/towers/tower_sprites/trash_heap_2.tscn\",\"R4SR\",\"C93K\"\r\n\"Supply Heap\",3,462,458,\"geX\",\"common\",\"iron\",\"TRUE\",\"physical\",1000,2.5,838,968,0,0,350,1200,0.25,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.006|MOD_ITEM_CHANCE_ON_KILL,0.2,0.007|MOD_ITEM_QUALITY_ON_KILL,-0.2,-0.007\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/trash_heap.tres\",\"res://src/towers/tower_sprites/trash_heap_3.tscn\",\"L4HA\",\"C93K\"\r\n\"Weapon Heap\",4,463,458,\"geX\",\"common\",\"iron\",\"TRUE\",\"physical\",1000,2.5,1908,2208,0,0,800,1200,0.25,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.006|MOD_ITEM_CHANCE_ON_KILL,0.2,0.008|MOD_ITEM_QUALITY_ON_KILL,-0.2,-0.008\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/trash_heap.tres\",\"res://src/towers/tower_sprites/trash_heap_4.tscn\",\"C8VG\",\"C93K\"\r\n\"Treasure Heap\",5,464,458,\"geX\",\"common\",\"iron\",\"TRUE\",\"physical\",1000,2.5,3314,3864,0,0,1400,1200,0.25,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.006|MOD_ITEM_CHANCE_ON_KILL,0.2,0.009|MOD_ITEM_QUALITY_ON_KILL,-0.2,-0.009\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/trash_heap.tres\",\"res://src/towers/tower_sprites/trash_heap_5.tscn\",\"5HSB\",\"C93K\"\r\n\"Precious Treasure Heap\",6,465,458,\"geX\",\"common\",\"iron\",\"TRUE\",\"physical\",1000,2.5,5216,6016,0,0,2200,1200,0.25,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_BOSS,0.1,0.006|MOD_ITEM_CHANCE_ON_KILL,0.2,0.01|MOD_ITEM_QUALITY_ON_KILL,-0.2,-0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/trash_heap.tres\",\"res://src/towers/tower_sprites/trash_heap_6.tscn\",\"5A3H\",\"C93K\"\r\n\"Cruel Fire\",1,461,461,\"Boekie\",\"rare\",\"fire\",\"TRUE\",\"decay\",900,1.5,642,642,0,0,550,1500,0,\"FALSE\",\"CREEPS\",,,,,,\"58\",,\"res://src/towers/tower_behaviors/cruel_fire.gd\",\"res://resources/icons/tower_icons/cruel_fire.tres\",\"res://src/towers/tower_sprites/cruel_fire_1.tscn\",\"C2QT\",\"JVID\"\r\n\"Cruel Flames\",2,466,461,\"Boekie\",\"rare\",\"fire\",\"TRUE\",\"decay\",900,1.5,1634,1634,0,0,1400,1500,0,\"FALSE\",\"CREEPS\",,,,,,\"59\",,\"res://src/towers/tower_behaviors/cruel_fire.gd\",\"res://resources/icons/tower_icons/cruel_fire.tres\",\"res://src/towers/tower_sprites/cruel_fire_2.tscn\",\"300D\",\"JVID\"\r\n\"Cruel Inferno\",3,467,461,\"Boekie\",\"rare\",\"fire\",\"TRUE\",\"decay\",900,1.5,3501,3501,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,,,\"60\",,\"res://src/towers/tower_behaviors/cruel_fire.gd\",\"res://resources/icons/tower_icons/cruel_fire.tres\",\"res://src/towers/tower_sprites/cruel_fire_3.tscn\",\"URX0\",\"JVID\"\r\n\"Living Volcano\",1,468,468,\"Kricz\",\"unique\",\"fire\",\"TRUE\",\"decay\",1100,1.8,1771,1771,0,0,3600,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,0.45,0.02|MOD_DAMAGE_BASE_PERC,0,0.075|MOD_SPELL_DAMAGE_DEALT,0,0.015\",\"484,485\",\"61\",,\"res://src/towers/tower_behaviors/living_volcano.gd\",\"res://resources/icons/tower_icons/living_volcano.tres\",\"res://src/towers/tower_sprites/living_volcano_1.tscn\",\"UOM3\",\"JWWE\"\r\n\"Dwarven Forgery\",1,469,469,\"geX\",\"unique\",\"iron\",\"TRUE\",\"physical\",675,2.5,4225,4825,0,0,1500,900,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_ITEM_QUALITY_ON_KILL,0.5,0.01\",,\"62\",,\"res://src/towers/tower_behaviors/dwarven_forgery.gd\",\"res://resources/icons/tower_icons/dwarven_forgery.tres\",\"res://src/towers/tower_sprites/dwarven_forgery_1.tscn\",\"Y8L7\",\"PZLC\"\r\n\"Ruined Storm Cap\",1,470,470,\"geX\",\"common\",\"storm\",\"TRUE\",\"energy\",1600,1.3,24,64,0,0,40,2000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_storm_cap.tres\",\"res://src/towers/tower_sprites/ruined_storm_cap_1.tscn\",\"MUZE\",\"5V4H\"\r\n\"Broken Storm Column\",2,475,470,\"geX\",\"common\",\"storm\",\"TRUE\",\"energy\",1600,1.25,68,228,0,0,160,2000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_storm_cap.tres\",\"res://src/towers/tower_sprites/ruined_storm_cap_2.tscn\",\"DI09\",\"5V4H\"\r\n\"Storm Column\",3,481,470,\"geX\",\"common\",\"storm\",\"TRUE\",\"energy\",1600,1.2,160,580,0,0,420,2000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_storm_cap.tres\",\"res://src/towers/tower_sprites/ruined_storm_cap_3.tscn\",\"71CT\",\"5V4H\"\r\n\"Storm Chamber\",4,489,470,\"geX\",\"common\",\"storm\",\"TRUE\",\"energy\",1600,1.15,286,1136,0,0,850,2000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_storm_cap.tres\",\"res://src/towers/tower_sprites/ruined_storm_cap_4.tscn\",\"T68P\",\"5V4H\"\r\n\"Storm Turret\",5,450,470,\"geX\",\"common\",\"storm\",\"TRUE\",\"energy\",1600,1.15,521,2071,0,0,1550,2000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_storm_cap.tres\",\"res://src/towers/tower_sprites/ruined_storm_cap_5.tscn\",\"TGJI\",\"5V4H\"\r\n\"Storm Destillator\",6,500,470,\"geX\",\"common\",\"storm\",\"TRUE\",\"energy\",1600,1.1,717,3167,0,0,2450,2000,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_storm_cap.tres\",\"res://src/towers/tower_sprites/ruined_storm_cap_6.tscn\",\"52YK\",\"5V4H\"\r\n\"Lesser Wolves Den\",1,471,471,\"ColdRocker\",\"rare\",\"nature\",\"TRUE\",\"physical\",700,1.6,535,535,0,0,500,1500,0,\"FALSE\",\"CREEPS\",,,,,,\"63\",,\"res://src/towers/tower_behaviors/lesser_wolves_den.gd\",\"res://resources/icons/tower_icons/lesser_wolves_den.tres\",\"res://src/towers/tower_sprites/lesser_wolves_den_1.tscn\",\"DXMW\",\"C2W1\"\r\n\"Greater Wolves Den\",2,472,471,\"ColdRocker\",\"rare\",\"nature\",\"TRUE\",\"physical\",700,1.6,1485,1485,0,0,1350,1500,0,\"FALSE\",\"CREEPS\",,,,,,\"64\",,\"res://src/towers/tower_behaviors/lesser_wolves_den.gd\",\"res://resources/icons/tower_icons/lesser_wolves_den.tres\",\"res://src/towers/tower_sprites/lesser_wolves_den_2.tscn\",\"SLUQ\",\"C2W1\"\r\n\"Grand Wolves Lair\",3,473,471,\"ColdRocker\",\"rare\",\"nature\",\"TRUE\",\"physical\",700,1.6,2474,2474,0,0,2250,1500,0,\"FALSE\",\"CREEPS\",,,,,,\"65\",,\"res://src/towers/tower_behaviors/lesser_wolves_den.gd\",\"res://resources/icons/tower_icons/lesser_wolves_den.tres\",\"res://src/towers/tower_sprites/lesser_wolves_den_3.tscn\",\"D3V9\",\"C2W1\"\r\n\"Tree Stump\",1,474,474,\"Monolith\",\"common\",\"nature\",\"TRUE\",\"physical\",950,0.9,24,27,0,0,40,1300,0.1,\"FALSE\",\"CREEPS\",\"2\",,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tree_stump.tres\",\"res://src/towers/tower_sprites/tree_stump_1.tscn\",\"ET8F\",\"YLKI\"\r\n\"Tree Trunk\",2,634,474,\"Monolith\",\"common\",\"nature\",\"TRUE\",\"physical\",950,0.9,119,124,0,0,280,1300,0.1,\"FALSE\",\"CREEPS\",\"3\",,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tree_stump.tres\",\"res://src/towers/tower_sprites/tree_stump_2.tscn\",\"DOEC\",\"9WPN\"\r\n\"Tree\",3,635,474,\"Monolith\",\"common\",\"nature\",\"TRUE\",\"physical\",950,0.9,227,232,0,0,640,1300,0.1,\"FALSE\",\"CREEPS\",\"4\",,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tree_stump.tres\",\"res://src/towers/tower_sprites/tree_stump_3.tscn\",\"KV8Y\",\"9WPN\"\r\n\"Tree Group\",4,636,474,\"Monolith\",\"common\",\"nature\",\"TRUE\",\"physical\",950,0.8,264,269,0,0,1100,1300,0.1,\"FALSE\",\"CREEPS\",\"5\",,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tree_stump.tres\",\"res://src/towers/tower_sprites/tree_stump_4.tscn\",\"GRFI\",\"E1NL\"\r\n\"Forest\",5,637,474,\"Monolith\",\"common\",\"nature\",\"TRUE\",\"physical\",950,0.8,541,546,0,0,2250,1300,0.1,\"FALSE\",\"CREEPS\",\"5\",,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/tree_stump.tres\",\"res://src/towers/tower_sprites/tree_stump_5.tscn\",\"OY4G\",\"XWFK\"\r\n\"Cold Troll\",1,476,476,\"cedi\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.5,71,71,100,2.5,90,900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_ORC,0.25,0|MOD_DMG_TO_HUMANOID,0.25,0\",,,\"137\",\"res://src/towers/tower_behaviors/cold_troll.gd\",\"res://resources/icons/tower_icons/cold_troll.tres\",\"res://src/towers/tower_sprites/cold_troll_1.tscn\",\"CMI2\",\"FC99\"\r\n\"Really Cold Troll\",2,477,476,\"cedi\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.5,397,397,100,2.5,600,900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_ORC,0.25,0|MOD_DMG_TO_HUMANOID,0.25,0\",,,\"138\",\"res://src/towers/tower_behaviors/cold_troll.gd\",\"res://resources/icons/tower_icons/cold_troll.tres\",\"res://src/towers/tower_sprites/cold_troll_2.tscn\",\"2GV2\",\"JTKP\"\r\n\"Frozen Troll\",3,478,476,\"cedi\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.5,738,738,100,2.5,1200,900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_ORC,0.25,0|MOD_DMG_TO_HUMANOID,0.25,0\",,,\"139\",\"res://src/towers/tower_behaviors/cold_troll.gd\",\"res://resources/icons/tower_icons/cold_troll.tres\",\"res://src/towers/tower_sprites/cold_troll_3.tscn\",\"SJCT\",\"PF1K\"\r\n\"Totally Frozen Troll\",4,479,476,\"cedi\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.5,1362,1362,100,2.5,2400,900,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_ORC,0.25,0|MOD_DMG_TO_HUMANOID,0.25,0\",,,\"140\",\"res://src/towers/tower_behaviors/cold_troll.gd\",\"res://resources/icons/tower_icons/cold_troll.tres\",\"res://src/towers/tower_sprites/cold_troll_4.tscn\",\"YYE9\",\"BKNV\"\r\n\"Library of Alexandria\",1,480,480,\"Boekie\",\"unique\",\"astral\",\"FALSE\",\"physical\",800,1,1,1,40,2,1500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA_REGEN_PERC,0,0.04\",\"486\",\"66\",\"141\",\"res://src/towers/tower_behaviors/library_of_alexandria.gd\",\"res://resources/icons/tower_icons/library_of_alexandria.tres\",\"res://src/towers/tower_sprites/library_of_alexandria_1.tscn\",\"W0I3\",\"DOPC\"\r\n\"Lesser Flamy Defender\",1,482,482,\"Natac\",\"common\",\"fire\",\"TRUE\",\"elemental\",700,1.5,111,124,0,0,65,900,0.35,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_flamy_defender.tres\",\"res://src/towers/tower_sprites/lesser_flamy_defender_1.tscn\",\"BAQL\",\"IUDX\"\r\n\"Small Flamy Defender\",2,483,482,\"Natac\",\"common\",\"fire\",\"TRUE\",\"elemental\",700,1.5,374,418,0,0,220,900,0.35,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_flamy_defender.tres\",\"res://src/towers/tower_sprites/lesser_flamy_defender_2.tscn\",\"HF5P\",\"IUDX\"\r\n\"Medium Flamy Defender\",3,484,482,\"Natac\",\"common\",\"fire\",\"TRUE\",\"elemental\",700,1.5,1105,1235,0,0,650,900,0.35,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_flamy_defender.tres\",\"res://src/towers/tower_sprites/lesser_flamy_defender_3.tscn\",\"0DVL\",\"IUDX\"\r\n\"Grand Flamy Defender\",4,486,482,\"Natac\",\"common\",\"fire\",\"TRUE\",\"elemental\",700,1.5,2296,2566,0,0,1350,900,0.35,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_flamy_defender.tres\",\"res://src/towers/tower_sprites/lesser_flamy_defender_4.tscn\",\"EJNL\",\"IUDX\"\r\n\"Superior Flamy Defender\",5,485,482,\"Natac\",\"common\",\"fire\",\"TRUE\",\"elemental\",700,1.5,4251,4751,0,0,2500,900,0.35,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_flamy_defender.tres\",\"res://src/towers/tower_sprites/lesser_flamy_defender_5.tscn\",\"QBF5\",\"IUDX\"\r\n\"Lesser Dark Defender\",1,487,487,\"Natac\",\"common\",\"darkness\",\"TRUE\",\"decay\",825,1.1,68,76,0,0,65,900,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_dark_defender.tres\",\"res://src/towers/tower_sprites/lesser_dark_defender_1.tscn\",\"7SEV\",\"IUDX\"\r\n\"Small Dark Defender\",2,488,487,\"Natac\",\"common\",\"darkness\",\"TRUE\",\"decay\",825,1.1,228,257,0,0,220,901,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_dark_defender.tres\",\"res://src/towers/tower_sprites/lesser_dark_defender_2.tscn\",\"UVP7\",\"IUDX\"\r\n\"Medium Dark Defender\",3,490,487,\"Natac\",\"common\",\"darkness\",\"TRUE\",\"decay\",825,1.1,672,759,0,0,650,902,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_dark_defender.tres\",\"res://src/towers/tower_sprites/lesser_dark_defender_3.tscn\",\"HDEU\",\"IUDX\"\r\n\"Grand Dark Defender\",4,492,487,\"Natac\",\"common\",\"darkness\",\"TRUE\",\"decay\",825,1.1,1395,1577,0,0,1350,903,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_dark_defender.tres\",\"res://src/towers/tower_sprites/lesser_dark_defender_4.tscn\",\"LNZ4\",\"IUDX\"\r\n\"Superior Dark Defender\",5,491,487,\"Natac\",\"common\",\"darkness\",\"TRUE\",\"decay\",825,1.1,2584,2921,0,0,2500,904,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_dark_defender.tres\",\"res://src/towers/tower_sprites/lesser_dark_defender_5.tscn\",\"XUL1\",\"IUDX\"\r\n\"Lesser Storm Defender\",1,496,496,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",950,0.8,31,60,0,0,65,1200,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_storm_defender.tres\",\"res://src/towers/tower_sprites/lesser_storm_defender_1.tscn\",\"JNVT\",\"IUDX\"\r\n\"Small Storm Defender\",2,497,496,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",950,0.8,103,202,0,0,220,1200,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_storm_defender.tres\",\"res://src/towers/tower_sprites/lesser_storm_defender_2.tscn\",\"2YDE\",\"IUDX\"\r\n\"Medium Storm Defender\",3,493,496,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",950,0.8,303,595,0,0,650,1200,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_storm_defender.tres\",\"res://src/towers/tower_sprites/lesser_storm_defender_3.tscn\",\"Q863\",\"IUDX\"\r\n\"Grand Storm Defender\",4,494,496,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",950,0.8,629,1236,0,0,1350,1200,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_storm_defender.tres\",\"res://src/towers/tower_sprites/lesser_storm_defender_4.tscn\",\"0L8X\",\"IUDX\"\r\n\"Superior Storm Defender\",5,495,496,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",950,0.8,1163,2288,0,0,2500,1200,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_storm_defender.tres\",\"res://src/towers/tower_sprites/lesser_storm_defender_5.tscn\",\"HJNY\",\"IUDX\"\r\n\"Lesser Natural Defender\",1,498,498,\"Natac\",\"common\",\"nature\",\"TRUE\",\"essence\",875,1.3,75,94,0,0,65,1800,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_natural_defender.tres\",\"res://src/towers/tower_sprites/lesser_natural_defender_1.tscn\",\"QMDT\",\"IUDX\"\r\n\"Small Natural Defender\",2,499,498,\"Natac\",\"common\",\"nature\",\"TRUE\",\"essence\",875,1.3,251,317,0,0,220,1800,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_natural_defender.tres\",\"res://src/towers/tower_sprites/lesser_natural_defender_2.tscn\",\"JSTH\",\"IUDX\"\r\n\"Medium Natural Defender\",3,501,498,\"Natac\",\"common\",\"nature\",\"TRUE\",\"essence\",875,1.3,741,936,0,0,650,1800,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_natural_defender.tres\",\"res://src/towers/tower_sprites/lesser_natural_defender_3.tscn\",\"A5O3\",\"IUDX\"\r\n\"Grand Natural Defender\",4,502,498,\"Natac\",\"common\",\"nature\",\"TRUE\",\"essence\",875,1.3,1539,1944,0,0,1350,1800,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_natural_defender.tres\",\"res://src/towers/tower_sprites/lesser_natural_defender_4.tscn\",\"737E\",\"IUDX\"\r\n\"Superior Natural Defender\",5,503,498,\"Natac\",\"common\",\"nature\",\"TRUE\",\"essence\",875,1.3,2848,3598,0,0,2500,1800,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_natural_defender.tres\",\"res://src/towers/tower_sprites/lesser_natural_defender_5.tscn\",\"ZYST\",\"IUDX\"\r\n\"Lesser Ice Defender\",1,507,507,\"Natac\",\"common\",\"ice\",\"TRUE\",\"elemental\",900,1.4,88,94,0,0,65,1200,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_ice_defender.tres\",\"res://src/towers/tower_sprites/lesser_ice_defender_1.tscn\",\"CUGM\",\"IUDX\"\r\n\"Small Ice Defender\",2,508,507,\"Natac\",\"common\",\"ice\",\"TRUE\",\"elemental\",900,1.4,296,318,0,0,220,1200,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_ice_defender.tres\",\"res://src/towers/tower_sprites/lesser_ice_defender_2.tscn\",\"87FL\",\"IUDX\"\r\n\"Medium Ice Defender\",3,504,507,\"Natac\",\"common\",\"ice\",\"TRUE\",\"elemental\",900,1.4,875,940,0,0,650,1200,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_ice_defender.tres\",\"res://src/towers/tower_sprites/lesser_ice_defender_3.tscn\",\"FYT1\",\"IUDX\"\r\n\"Grand Ice Defender\",4,505,507,\"Natac\",\"common\",\"ice\",\"TRUE\",\"elemental\",900,1.4,1817,1952,0,0,1350,1200,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_ice_defender.tres\",\"res://src/towers/tower_sprites/lesser_ice_defender_4.tscn\",\"V1J6\",\"IUDX\"\r\n\"Superior Ice Defender\",5,506,507,\"Natac\",\"common\",\"ice\",\"TRUE\",\"elemental\",900,1.4,3363,3613,0,0,2500,1200,0,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_ice_defender.tres\",\"res://src/towers/tower_sprites/lesser_ice_defender_5.tscn\",\"A4FZ\",\"IUDX\"\r\n\"Lesser Astral Defender\",1,510,510,\"Natac\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.2,73,84,0,0,65,900,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_astral_defender.tres\",\"res://src/towers/tower_sprites/lesser_astral_defender_1.tscn\",\"QM83\",\"IUDX\"\r\n\"Small Astral Defender\",2,512,510,\"Natac\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.2,246,283,0,0,220,900,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_astral_defender.tres\",\"res://src/towers/tower_sprites/lesser_astral_defender_2.tscn\",\"MGD7\",\"IUDX\"\r\n\"Medium Astral Defender\",3,513,510,\"Natac\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.2,725,836,0,0,650,900,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_astral_defender.tres\",\"res://src/towers/tower_sprites/lesser_astral_defender_3.tscn\",\"L52R\",\"IUDX\"\r\n\"Grand Astral Defender\",4,514,510,\"Natac\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.2,1506,1735,0,0,1350,900,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_astral_defender.tres\",\"res://src/towers/tower_sprites/lesser_astral_defender_4.tscn\",\"XVVL\",\"IUDX\"\r\n\"Superior Astral Defender\",5,509,510,\"Natac\",\"common\",\"astral\",\"TRUE\",\"energy\",850,1.2,2788,3213,0,0,2500,900,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_astral_defender.tres\",\"res://src/towers/tower_sprites/lesser_astral_defender_5.tscn\",\"6GEA\",\"IUDX\"\r\n\"Lesser Iron Defender\",1,515,515,\"Matac\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1,65,65,0,0,65,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_iron_defender.tres\",\"res://src/towers/tower_sprites/lesser_iron_defender_1.tscn\",\"IK7C\",\"IUDX\"\r\n\"Small Iron Defender\",2,518,515,\"Matac\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1,220,220,0,0,220,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_iron_defender.tres\",\"res://src/towers/tower_sprites/lesser_iron_defender_2.tscn\",\"TZ3N\",\"IUDX\"\r\n\"Medium Iron Defender\",3,519,515,\"Matac\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1,650,650,0,0,650,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_iron_defender.tres\",\"res://src/towers/tower_sprites/lesser_iron_defender_3.tscn\",\"Q7VX\",\"IUDX\"\r\n\"Grand Iron Defender\",4,516,515,\"Matac\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1,1350,1350,0,0,1350,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_iron_defender.tres\",\"res://src/towers/tower_sprites/lesser_iron_defender_4.tscn\",\"6IKD\",\"IUDX\"\r\n\"Superior Iron Defender\",5,517,515,\"Matac\",\"common\",\"iron\",\"TRUE\",\"physical\",800,1,2500,2500,0,0,2500,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/lesser_iron_defender.tres\",\"res://src/towers/tower_sprites/lesser_iron_defender_5.tscn\",\"JWDH\",\"IUDX\"\r\n\"Annoyed Tree\",1,520,520,\"Boekie\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",950,1.4,142,161,0,0,200,1500,0,\"FALSE\",\"CREEPS\",,,,,\"487\",,,\"res://src/towers/tower_behaviors/annoyed_tree.gd\",\"res://resources/icons/tower_icons/annoyed_tree.tres\",\"res://src/towers/tower_sprites/annoyed_tree_1.tscn\",\"9L9N\",\"696B\"\r\n\"Angry Tree\",2,521,520,\"Boekie\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",950,1.4,574,593,0,0,800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"488\",,,\"res://src/towers/tower_behaviors/annoyed_tree.gd\",\"res://resources/icons/tower_icons/annoyed_tree.tres\",\"res://src/towers/tower_sprites/annoyed_tree_2.tscn\",\"8ME9\",\"696B\"\r\n\"Enraged Tree\",3,522,520,\"Boekie\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",950,1.4,1096,1115,0,0,1600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"489\",,,\"res://src/towers/tower_behaviors/annoyed_tree.gd\",\"res://resources/icons/tower_icons/annoyed_tree.tres\",\"res://src/towers/tower_sprites/annoyed_tree_3.tscn\",\"8NN4\",\"696B\"\r\n\"Mad Tree\",4,523,520,\"Boekie\",\"uncommon\",\"nature\",\"TRUE\",\"physical\",950,1.4,1702,1721,0,0,2600,1500,0,\"FALSE\",\"CREEPS\",,,,,\"490\",,,\"res://src/towers/tower_behaviors/annoyed_tree.gd\",\"res://resources/icons/tower_icons/annoyed_tree.tres\",\"res://src/towers/tower_sprites/annoyed_tree_4.tscn\",\"E8RJ\",\"696B\"\r\n\"Dragon Sorcerer\",1,524,524,\"Boekie\",\"unique\",\"fire\",\"TRUE\",\"decay\",900,1,1505,1514,30,2,1800,1000,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,5|MOD_MANA_REGEN,0,0.1\",,,\"142\",\"res://src/towers/tower_behaviors/dragon_sorcerer.gd\",\"res://resources/icons/tower_icons/dragon_sorcerer.tres\",\"res://src/towers/tower_sprites/dragon_sorcerer_1.tscn\",\"TDPW\",\"OQJY\"\r\n\"Coconut Sapling\",1,525,525,\"cedi\",\"rare\",\"nature\",\"TRUE\",\"physical\",825,3,1,1,0,0,1500,10000,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.3,0.01|MOD_DMG_TO_HUMANOID,0.2,0.01\",\"491\",,,\"res://src/towers/tower_behaviors/coconut_sapling.gd\",\"res://resources/icons/tower_icons/coconut_sapling.tres\",\"res://src/towers/tower_sprites/coconut_sapling_1.tscn\",\"JLW5\",\"OJNT\"\r\n\"Monkey Boogie Palm\",2,531,525,\"cedi\",\"rare\",\"nature\",\"TRUE\",\"physical\",825,3,1,1,0,0,3000,10000,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.5,0.01|MOD_DMG_TO_HUMANOID,0.4,0.01\",\"492\",,,\"res://src/towers/tower_behaviors/coconut_sapling.gd\",\"res://resources/icons/tower_icons/coconut_sapling.tres\",\"res://src/towers/tower_sprites/coconut_sapling_2.tscn\",\"SCXM\",\"OJNT\"\r\n\"Safiron's Cold Grave\",1,526,526,\"cedi\",\"unique\",\"ice\",\"TRUE\",\"elemental\",1500,4,1,1,0,0,4000,10000,0,\"TRUE\",\"CREEPS\",,,,,\"493,494\",,,\"res://src/towers/tower_behaviors/safirons_cold_grave.gd\",\"res://resources/icons/tower_icons/safirons_cold_grave.tres\",\"res://src/towers/tower_sprites/safirons_cold_grave_1.tscn\",\"BXFH\",\"GVJH\"\r\n\"Lesser Skeletal Mage\",1,527,527,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",900,2,270,270,40,2,150,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"143\",\"res://src/towers/tower_behaviors/lesser_skeletal_mage.gd\",\"res://resources/icons/tower_icons/lesser_skeletal_mage.tres\",\"res://src/towers/tower_sprites/lesser_skeletal_mage_1.tscn\",\"45XA\",\"LCJL\"\r\n\"Skeletal Mage\",2,528,527,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",900,2,1169,1169,50,2,650,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"144\",\"res://src/towers/tower_behaviors/lesser_skeletal_mage.gd\",\"res://resources/icons/tower_icons/lesser_skeletal_mage.tres\",\"res://src/towers/tower_sprites/lesser_skeletal_mage_2.tscn\",\"FE6T\",\"LCJL\"\r\n\"Skeletal Sorceror\",3,529,527,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",900,2,2517,2517,60,2,1400,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"145\",\"res://src/towers/tower_behaviors/lesser_skeletal_mage.gd\",\"res://resources/icons/tower_icons/lesser_skeletal_mage.tres\",\"res://src/towers/tower_sprites/lesser_skeletal_mage_3.tscn\",\"OZFI\",\"LCJL\"\r\n\"Skeletal Wizard\",4,530,527,\"Boekie\",\"uncommon\",\"darkness\",\"TRUE\",\"decay\",900,2,3956,3956,70,2,2200,1500,0,\"FALSE\",\"CREEPS\",,,,,,,\"146\",\"res://src/towers/tower_behaviors/lesser_skeletal_mage.gd\",\"res://resources/icons/tower_icons/lesser_skeletal_mage.tres\",\"res://src/towers/tower_sprites/lesser_skeletal_mage_4.tscn\",\"QTTJ\",\"LCJL\"\r\n\"Embershell Turtle Hatchling\",1,532,532,\"Velex\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,0.25,49,50,10,1,70,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,0.5\",\"495\",,,\"res://src/towers/tower_behaviors/embershell_turtle_hatchling.gd\",\"res://resources/icons/tower_icons/embershell_turtle_hatchling.tres\",\"res://src/towers/tower_sprites/embershell_turtle_hatchling_1.tscn\",\"OJP3\",\"3ISX\"\r\n\"Embershell Turtle Nestling\",2,533,532,\"Velex\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,0.25,181,182,12,1,260,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,0.6\",\"496\",,,\"res://src/towers/tower_behaviors/embershell_turtle_hatchling.gd\",\"res://resources/icons/tower_icons/embershell_turtle_hatchling.tres\",\"res://src/towers/tower_sprites/embershell_turtle_hatchling_2.tscn\",\"NERL\",\"3ISX\"\r\n\"Embershell Turtle Loner\",3,534,532,\"Velex\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,0.25,453,454,14,1,650,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,0.7\",\"497\",,,\"res://src/towers/tower_behaviors/embershell_turtle_hatchling.gd\",\"res://resources/icons/tower_icons/embershell_turtle_hatchling.tres\",\"res://src/towers/tower_sprites/embershell_turtle_hatchling_3.tscn\",\"Q7RX\",\"3ISX\"\r\n\"Embershell Turtle Adult\",4,535,532,\"Velex\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,0.25,1044,1045,16,1,1500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,0.8\",\"498\",,,\"res://src/towers/tower_behaviors/embershell_turtle_hatchling.gd\",\"res://resources/icons/tower_icons/embershell_turtle_hatchling.tres\",\"res://src/towers/tower_sprites/embershell_turtle_hatchling_4.tscn\",\"50E7\",\"3ISX\"\r\n\"Embershell Turtle Matriarch\",5,536,532,\"Velex\",\"uncommon\",\"fire\",\"TRUE\",\"decay\",800,0.25,1880,1881,18,1,2700,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,0.9\",\"499\",,,\"res://src/towers/tower_behaviors/embershell_turtle_hatchling.gd\",\"res://resources/icons/tower_icons/embershell_turtle_hatchling.tres\",\"res://src/towers/tower_sprites/embershell_turtle_hatchling_5.tscn\",\"0FBM\",\"3ISX\"\r\n\"Jungle Stalker\",1,537,537,\"Boekie\",\"rare\",\"nature\",\"TRUE\",\"physical\",850,1.1,613,712,0,0,800,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1375,0.005\",\"500,501\",,,\"res://src/towers/tower_behaviors/jungle_stalker.gd\",\"res://resources/icons/tower_icons/jungle_stalker.tres\",\"res://src/towers/tower_sprites/jungle_stalker_1.tscn\",\"WYIM\",\"3ISX\"\r\n\"Elder Jungle Stalker\",2,549,537,\"Boekie\",\"rare\",\"nature\",\"TRUE\",\"physical\",850,1.1,1300,1399,0,0,1900,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1625,0.005\",\"502,503\",,,\"res://src/towers/tower_behaviors/jungle_stalker.gd\",\"res://resources/icons/tower_icons/jungle_stalker.tres\",\"res://src/towers/tower_sprites/jungle_stalker_2.tscn\",\"TGZL\",\"LWGF\"\r\n\"Ancient Jungle Stalker\",3,550,537,\"Boekie\",\"rare\",\"nature\",\"TRUE\",\"physical\",850,1.1,2021,2120,0,0,3500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.1875,0.005\",\"504,505\",,,\"res://src/towers/tower_behaviors/jungle_stalker.gd\",\"res://resources/icons/tower_icons/jungle_stalker.tres\",\"res://src/towers/tower_sprites/jungle_stalker_3.tscn\",\"6H44\",\"LWGF\"\r\n\"Green Dragon Roost\",1,538,538,\"Boekie\",\"unique\",\"nature\",\"TRUE\",\"essence\",800,2,1048,1097,0,0,1600,1000,0.4,\"FALSE\",\"CREEPS\",,,\"4,0.1\",\"MOD_ATK_CRIT_CHANCE,0.1375,0.005|MOD_ATK_CRIT_DAMAGE,0.25,0.05\",,\"67\",,\"res://src/towers/tower_behaviors/green_dragon_roost.gd\",\"res://resources/icons/tower_icons/green_dragon_roost.tres\",\"res://src/towers/tower_sprites/green_dragon_roost_1.tscn\",\"7A3A\",\"A0MI\"\r\n\"Cold Obelisk\",1,539,539,\"Boekie\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",600,2.1,681,681,0,0,400,900,0,\"FALSE\",\"CREEPS\",,\"140,0.35\",,\"MOD_DMG_TO_MASS,0.45,0.02\",\"506\",,,\"res://src/towers/tower_behaviors/cold_obelisk.gd\",\"res://resources/icons/tower_icons/cold_obelisk.tres\",\"res://src/towers/tower_sprites/cold_obelisk_1.tscn\",\"14JR\",\"3C9J\"\r\n\"Icy Obelisk\",2,540,539,\"Boekie\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",600,2.1,1989,1989,0,0,1200,900,0,\"FALSE\",\"CREEPS\",,\"180,0.35\",,\"MOD_DMG_TO_MASS,0.45,0.02\",\"507\",,,\"res://src/towers/tower_behaviors/cold_obelisk.gd\",\"res://resources/icons/tower_icons/cold_obelisk.tres\",\"res://src/towers/tower_sprites/cold_obelisk_2.tscn\",\"NEA6\",\"3C9J\"\r\n\"Frozen Obelisk\",3,541,539,\"Boekie\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",600,2.1,4445,4445,0,0,2750,900,0,\"FALSE\",\"CREEPS\",,\"220,0.35\",,\"MOD_DMG_TO_MASS,0.45,0.02\",\"508\",,,\"res://src/towers/tower_behaviors/cold_obelisk.gd\",\"res://resources/icons/tower_icons/cold_obelisk.tres\",\"res://src/towers/tower_sprites/cold_obelisk_3.tscn\",\"Z2X6\",\"3C9J\"\r\n\"Small Pocket Rocket\",1,544,544,\"Boekie\",\"common\",\"iron\",\"TRUE\",\"decay\",700,1.65,75,96,0,0,55,1800,0.3,\"FALSE\",\"CREEPS\",,\"125,0.55\",,\"MOD_DMG_TO_MASS,0.2,0.02\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_pocket_rocket.tres\",\"res://src/towers/tower_sprites/small_pocket_rocket_1.tscn\",\"GWEN\",\"OYPN\"\r\n\"Pocket Rocket\",2,545,544,\"Boekie\",\"common\",\"iron\",\"TRUE\",\"decay\",700,1.65,249,270,0,0,170,1800,0.3,\"FALSE\",\"CREEPS\",,\"125,0.55\",,\"MOD_DMG_TO_MASS,0.25,0.02\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_pocket_rocket.tres\",\"res://src/towers/tower_sprites/small_pocket_rocket_2.tscn\",\"TLT6\",\"OYPN\"\r\n\"Upgraded Pocket Rocket\",3,546,544,\"Boekie\",\"common\",\"iron\",\"TRUE\",\"decay\",700,1.65,711,754,0,0,485,1800,0.3,\"FALSE\",\"CREEPS\",,\"125,0.55\",,\"MOD_DMG_TO_MASS,0.3,0.02\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_pocket_rocket.tres\",\"res://src/towers/tower_sprites/small_pocket_rocket_3.tscn\",\"6ZP9\",\"OYPN\"\r\n\"Advanced Pocket Rocket\",4,547,544,\"Boekie\",\"common\",\"iron\",\"TRUE\",\"decay\",700,1.65,1863,1884,0,0,1255,1800,0.3,\"FALSE\",\"CREEPS\",,\"125,0.55\",,\"MOD_DMG_TO_MASS,0.35,0.02\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_pocket_rocket.tres\",\"res://src/towers/tower_sprites/small_pocket_rocket_4.tscn\",\"GL47\",\"OYPN\"\r\n\"Ultimate Pocket Rocket\",5,548,544,\"Boekie\",\"common\",\"iron\",\"TRUE\",\"decay\",700,1.65,3133,3154,0,0,2130,1800,0.3,\"FALSE\",\"CREEPS\",,\"125,0.55\",,\"MOD_DMG_TO_MASS,0.4,0.02\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_pocket_rocket.tres\",\"res://src/towers/tower_sprites/small_pocket_rocket_5.tscn\",\"FWW5\",\"OYPN\"\r\n\"The Fire Lord\",1,554,554,\"Boekie\",\"unique\",\"fire\",\"TRUE\",\"decay\",900,2.5,4107,4126,0,0,2750,1500,0,\"FALSE\",\"CREEPS\",,,,,\"509,510\",,,\"res://src/towers/tower_behaviors/the_fire_lord.gd\",\"res://resources/icons/tower_icons/the_fire_lord.tres\",\"res://src/towers/tower_sprites/the_fire_lord_1.tscn\",\"OZ15\",\"E6AC\"\r\n\"Broken Fire Pit\",1,555,555,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"decay\",800,0.9,57,57,0,0,70,1500,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_MULTICRIT_COUNT,1,0\",\"511\",,,\"res://src/towers/tower_behaviors/broken_fire_pit.gd\",\"res://resources/icons/tower_icons/broken_fire_pit.tres\",\"res://src/towers/tower_sprites/broken_fire_pit_1.tscn\",\"DPA6\",\"0QSP\"\r\n\"Burning Fire Pit\",2,558,555,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"decay\",800,0.9,157,157,0,0,200,1500,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_MULTICRIT_COUNT,1,0\",\"512\",,,\"res://src/towers/tower_behaviors/broken_fire_pit.gd\",\"res://resources/icons/tower_icons/broken_fire_pit.tres\",\"res://src/towers/tower_sprites/broken_fire_pit_2.tscn\",\"RSL9\",\"0QSP\"\r\n\"Expanded Fire Pit\",3,559,555,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"decay\",800,0.9,455,455,0,0,600,1500,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_MULTICRIT_COUNT,1,0\",\"513\",,,\"res://src/towers/tower_behaviors/broken_fire_pit.gd\",\"res://resources/icons/tower_icons/broken_fire_pit.tres\",\"res://src/towers/tower_sprites/broken_fire_pit_3.tscn\",\"GO6J\",\"0QSP\"\r\n\"Wealthy Fire Pit\",4,585,555,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"decay\",800,0.9,951,951,0,0,1300,1500,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_MULTICRIT_COUNT,1,0\",\"514\",,,\"res://src/towers/tower_behaviors/broken_fire_pit.gd\",\"res://resources/icons/tower_icons/broken_fire_pit.tres\",\"res://src/towers/tower_sprites/broken_fire_pit_4.tscn\",\"ZI5I\",\"0QSP\"\r\n\"Luxurious Fire Pit\",5,560,555,\"Boekie\",\"common\",\"fire\",\"TRUE\",\"decay\",800,0.9,1692,1692,0,0,2400,1500,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_MULTICRIT_COUNT,1,0\",\"515\",,,\"res://src/towers/tower_behaviors/broken_fire_pit.gd\",\"res://resources/icons/tower_icons/broken_fire_pit.tres\",\"res://src/towers/tower_sprites/broken_fire_pit_5.tscn\",\"HA5T\",\"0QSP\"\r\n\"Coin Machine\",1,556,556,\"Boekie\",\"rare\",\"iron\",\"TRUE\",\"physical\",1200,2.5,2955,2955,30,2,1700,1500,0.5,\"FALSE\",\"CREEPS\",,,,,\"516\",,\"147\",\"res://src/towers/tower_behaviors/coin_machine.gd\",\"res://resources/icons/tower_icons/coin_machine.tres\",\"res://src/towers/tower_sprites/coin_machine_1.tscn\",\"RXK7\",\"UCFC\"\r\n\"Gold Machine\",2,557,556,\"Boekie\",\"rare\",\"iron\",\"TRUE\",\"physical\",1200,2.5,4867,4867,30,2,2800,1500,0.5,\"FALSE\",\"CREEPS\",,,,,\"517\",,\"148\",\"res://src/towers/tower_behaviors/coin_machine.gd\",\"res://resources/icons/tower_icons/coin_machine.tres\",\"res://src/towers/tower_sprites/coin_machine_2.tscn\",\"GOVA\",\"UCFC\"\r\n\"Princess of Light\",1,561,561,\"Boekie\",\"rare\",\"astral\",\"TRUE\",\"arcane\",1000,1.5,1989,1989,30,1.5,1700,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,2\",\"518\",,\"149\",\"res://src/towers/tower_behaviors/princess_of_light.gd\",\"res://resources/icons/tower_icons/princess_of_light.tres\",\"res://src/towers/tower_sprites/princess_of_light_1.tscn\",\"6M0U\",\"KG7S\"\r\n\"Queen of Light\",2,168,561,\"Boekie\",\"rare\",\"astral\",\"TRUE\",\"arcane\",1000,1.5,3389,3389,30,1.5,3100,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_MANA,0,2\",\"519\",,\"150\",\"res://src/towers/tower_behaviors/princess_of_light.gd\",\"res://resources/icons/tower_icons/princess_of_light.tres\",\"res://src/towers/tower_sprites/princess_of_light_2.tscn\",\"D7NI\",\"KG7S\"\r\n\"Icy Core\",1,562,562,\"geX\",\"rare\",\"ice\",\"TRUE\",\"elemental\",1000,1.5,974,1138,0,0,1000,1900,0,\"FALSE\",\"CREEPS\",,,,,,\"68\",,\"res://src/towers/tower_behaviors/icy_core.gd\",\"res://resources/icons/tower_icons/icy_core.tres\",\"res://src/towers/tower_sprites/icy_core_1.tscn\",\"P40Z\",\"IGES\"\r\n\"Icy Flower\",2,543,562,\"geX\",\"rare\",\"ice\",\"TRUE\",\"elemental\",1000,1.5,3275,3769,0,0,3000,1900,0,\"FALSE\",\"CREEPS\",,,,,,\"69\",,\"res://src/towers/tower_behaviors/icy_core.gd\",\"res://resources/icons/tower_icons/icy_core.tres\",\"res://src/towers/tower_sprites/icy_core_2.tscn\",\"BB87\",\"ZFPH\"\r\n\"Cursed Grounds\",1,564,564,\"drol\",\"rare\",\"darkness\",\"TRUE\",\"decay\",775,1,280,324,0,0,750,1600,0,\"FALSE\",\"CREEPS\",,,\"4,0.3\",,\"520\",\"70\",,\"res://src/towers/tower_behaviors/cursed_grounds.gd\",\"res://resources/icons/tower_icons/cursed_grounds.tres\",\"res://src/towers/tower_sprites/cursed_grounds_1.tscn\",\"HTUB\",\"0XXU\"\r\n\"Afflicted Grounds\",2,563,564,\"drol\",\"rare\",\"darkness\",\"TRUE\",\"decay\",775,1,481,525,0,0,1250,1600,0,\"FALSE\",\"CREEPS\",,,\"4,0.3\",,\"521\",\"71\",,\"res://src/towers/tower_behaviors/cursed_grounds.gd\",\"res://resources/icons/tower_icons/cursed_grounds.tres\",\"res://src/towers/tower_sprites/cursed_grounds_2.tscn\",\"J4FF\",\"0XXU\"\r\n\"Tormented Grounds\",3,569,564,\"drol\",\"rare\",\"darkness\",\"TRUE\",\"decay\",775,1,822,866,0,0,2100,1600,0,\"FALSE\",\"CREEPS\",,,\"4,0.3\",,\"522\",\"72\",,\"res://src/towers/tower_behaviors/cursed_grounds.gd\",\"res://resources/icons/tower_icons/cursed_grounds.tres\",\"res://src/towers/tower_sprites/cursed_grounds_3.tscn\",\"KINW\",\"0XXU\"\r\n\"Abominable Snowman\",1,566,566,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",900,1.5,45,48,0,0,45,1000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0.25\",,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abominable_snowman.tres\",\"res://src/towers/tower_sprites/abominable_snowman_1.tscn\",\"ILTY\",\"5XV0\"\r\n\"Greater Abominable Snowman\",2,567,566,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",900,1.5,220,236,0,0,220,1000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0.2\",,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abominable_snowman.tres\",\"res://src/towers/tower_sprites/abominable_snowman_2.tscn\",\"I1KO\",\"5XV0\"\r\n\"Large Abominable Snowman\",3,568,566,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",900,1.5,650,689,0,0,650,1000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0.15\",,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abominable_snowman.tres\",\"res://src/towers/tower_sprites/abominable_snowman_3.tscn\",\"5WQ4\",\"5XV0\"\r\n\"Major Abominable Snowman\",4,589,566,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",900,1.5,1100,1148,0,0,1100,1000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0.1\",,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abominable_snowman.tres\",\"res://src/towers/tower_sprites/abominable_snowman_4.tscn\",\"MZWO\",\"5XV0\"\r\n\"Collosal Abominable Snowman\",5,588,566,\"drol\",\"common\",\"ice\",\"TRUE\",\"energy\",900,1.5,2200,2259,0,0,2200,1000,0.15,\"FALSE\",\"CREEPS\",,,\"2,0.05\",,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/abominable_snowman.tres\",\"res://src/towers/tower_sprites/abominable_snowman_5.tscn\",\"X2T0\",\"VJOD\"\r\n\"Spider Queen\",1,570,570,\"Boekie\",\"unique\",\"darkness\",\"TRUE\",\"physical\",950,1.25,987,1026,0,0,1800,1500,0,\"FALSE\",\"CREEPS\",,,,,\"523\",,,\"res://src/towers/tower_behaviors/spider_queen.gd\",\"res://resources/icons/tower_icons/spider_queen.tres\",\"res://src/towers/tower_sprites/spider_queen_1.tscn\",\"AYDO\",\"CCHI\"\r\n\"Ash Geyser\",1,571,571,\"drol\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",1100,1.8,106,115,0,0,120,1800,0.2,\"FALSE\",\"CREEPS\",,\"175,0.3\",,\"MOD_DMG_TO_NORMAL,0.2,0.004\",\"524\",,,\"res://src/towers/tower_behaviors/ash_geyser.gd\",\"res://resources/icons/tower_icons/ash_geyser.tres\",\"res://src/towers/tower_sprites/ash_geyser_1.tscn\",\"HQH3\",\"HUGE\"\r\n\"Fire Geyser\",2,572,571,\"drol\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",1100,1.8,315,334,0,0,360,1800,0.2,\"FALSE\",\"CREEPS\",,\"175,0.3\",,\"MOD_DMG_TO_NORMAL,0.2,0.004\",\"525\",,,\"res://src/towers/tower_behaviors/ash_geyser.gd\",\"res://resources/icons/tower_icons/ash_geyser.tres\",\"res://src/towers/tower_sprites/ash_geyser_2.tscn\",\"0R5I\",\"HUGE\"\r\n\"Lava Geyser\",3,573,571,\"drol\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",1100,1.8,646,685,0,0,750,1800,0.2,\"FALSE\",\"CREEPS\",,\"175,0.3\",,\"MOD_DMG_TO_NORMAL,0.2,0.004\",\"526\",,,\"res://src/towers/tower_behaviors/ash_geyser.gd\",\"res://resources/icons/tower_icons/ash_geyser.tres\",\"res://src/towers/tower_sprites/ash_geyser_3.tscn\",\"I1TW\",\"HUGE\"\r\n\"Magma Geyser\",4,574,571,\"drol\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",1100,1.8,1181,1260,0,0,1400,1800,0.2,\"FALSE\",\"CREEPS\",,\"175,0.3\",,\"MOD_DMG_TO_NORMAL,0.2,0.004\",\"527\",,,\"res://src/towers/tower_behaviors/ash_geyser.gd\",\"res://resources/icons/tower_icons/ash_geyser.tres\",\"res://src/towers/tower_sprites/ash_geyser_4.tscn\",\"5NLQ\",\"HUGE\"\r\n\"Volcanic Geyser\",5,122,571,\"drol\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",1100,1.8,2348,2447,0,0,2800,1800,0.2,\"FALSE\",\"CREEPS\",,\"175,0.3\",,\"MOD_DMG_TO_NORMAL,0.2,0.004\",\"528\",,,\"res://src/towers/tower_behaviors/ash_geyser.gd\",\"res://resources/icons/tower_icons/ash_geyser.tres\",\"res://src/towers/tower_sprites/ash_geyser_5.tscn\",\"Z3BI\",\"PEB9\"\r\n\"Meteor Totem\",1,575,575,\"SirCoqalot.\",\"unique\",\"fire\",\"TRUE\",\"elemental\",850,3.8,1966,2966,0,0,2000,1200,0,\"FALSE\",\"CREEPS\",,\"325,0.5\",,,\"529\",,\"151\",\"res://src/towers/tower_behaviors/meteor_totem.gd\",\"res://resources/icons/tower_icons/meteor_totem.tres\",\"res://src/towers/tower_sprites/meteor_totem_1.tscn\",\"O5S9\",\"9XOH\"\r\n\"Storm Coil\",1,576,576,\"SirCoqalot.\",\"unique\",\"storm\",\"TRUE\",\"energy\",1000,4,3270,3270,50,1,3000,1800,0,\"FALSE\",\"CREEPS\",,,,,\"530\",\"73\",\"152\",\"res://src/towers/tower_behaviors/storm_coil.gd\",\"res://resources/icons/tower_icons/storm_coil.tres\",\"res://src/towers/tower_sprites/storm_coil_1.tscn\",\"EP45\",\"XOL4\"\r\n\"Regenerating Well\",1,577,577,\"drol\",\"rare\",\"nature\",\"TRUE\",\"essence\",1000,1.1,738,817,400,5,1200,1100,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0.008\",,\"74\",\"153\",\"res://src/towers/tower_behaviors/regenerating_well.gd\",\"res://resources/icons/tower_icons/regenerating_well.tres\",\"res://src/towers/tower_sprites/regenerating_well_1.tscn\",\"6TWQ\",\"HJPE\"\r\n\"Enchanted Well\",2,578,577,\"drol\",\"rare\",\"nature\",\"TRUE\",\"essence\",1000,1.1,1514,1593,400,5,2400,1100,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0.008\",,\"75\",\"154\",\"res://src/towers/tower_behaviors/regenerating_well.gd\",\"res://resources/icons/tower_icons/regenerating_well.tres\",\"res://src/towers/tower_sprites/regenerating_well_2.tscn\",\"EQNU\",\"HJPE\"\r\n\"Rejuvenating Well\",3,579,577,\"drol\",\"rare\",\"nature\",\"TRUE\",\"essence\",1000,1.1,2291,2370,400,5,3600,1100,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_ORC,0.2,0.008\",,\"76\",\"155\",\"res://src/towers/tower_behaviors/regenerating_well.gd\",\"res://resources/icons/tower_icons/regenerating_well.tres\",\"res://src/towers/tower_sprites/regenerating_well_3.tscn\",\"ZCCJ\",\"HJPE\"\r\n\"Broken Cage\",1,580,580,\"Chronos\",\"common\",\"darkness\",\"TRUE\",\"decay\",800,1.5,88,93,0,0,70,1500,0,\"FALSE\",\"CREEPS\",,,,,\"531\",,,\"res://src/towers/tower_behaviors/broken_cage.gd\",\"res://resources/icons/tower_icons/broken_cage.tres\",\"res://src/towers/tower_sprites/broken_cage_1.tscn\",\"NTNT\",\"U51W\"\r\n\"Restored Cage\",2,581,580,\"Chronos\",\"common\",\"darkness\",\"TRUE\",\"decay\",800,1.5,299,304,0,0,250,1501,0,\"FALSE\",\"CREEPS\",,,,,\"532\",,,\"res://src/towers/tower_behaviors/broken_cage.gd\",\"res://resources/icons/tower_icons/broken_cage.tres\",\"res://src/towers/tower_sprites/broken_cage_2.tscn\",\"M1AR\",\"U51W\"\r\n\"Caged Soul\",3,582,580,\"Chronos\",\"common\",\"darkness\",\"TRUE\",\"decay\",800,1.5,750,755,0,0,660,1502,0,\"FALSE\",\"CREEPS\",,,,,\"533\",,,\"res://src/towers/tower_behaviors/broken_cage.gd\",\"res://resources/icons/tower_icons/broken_cage.tres\",\"res://src/towers/tower_sprites/broken_cage_3.tscn\",\"A1MS\",\"U51W\"\r\n\"Trapped Souls\",4,583,580,\"Chronos\",\"common\",\"darkness\",\"TRUE\",\"decay\",800,1.5,1329,1334,0,0,1240,1503,0,\"FALSE\",\"CREEPS\",,,,,\"534\",,,\"res://src/towers/tower_behaviors/broken_cage.gd\",\"res://resources/icons/tower_icons/broken_cage.tres\",\"res://src/towers/tower_sprites/broken_cage_4.tscn\",\"4440\",\"U51W\"\r\n\"Soul Prison\",5,584,580,\"Chronos\",\"common\",\"darkness\",\"TRUE\",\"decay\",800,1.5,2253,2258,0,0,2200,1504,0,\"FALSE\",\"CREEPS\",,,,,\"535\",,,\"res://src/towers/tower_behaviors/broken_cage.gd\",\"res://resources/icons/tower_icons/broken_cage.tres\",\"res://src/towers/tower_sprites/broken_cage_5.tscn\",\"YR2N\",\"U51W\"\r\n\"Fiery Pebble\",1,586,586,\"geX\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,1.2,31,36,0,0,30,1300,0.12,\"FALSE\",\"CREEPS\",,\"150,0.25\",,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"res://src/towers/tower_sprites/fiery_pebble_1.tscn\",\"7GBA\",\"CBNA\"\r\n\"Fiery Stone\",2,630,586,\"geX\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,1.2,147,171,0,0,150,1300,0.12,\"FALSE\",\"CREEPS\",,\"160,0.25\",,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"res://src/towers/tower_sprites/fiery_pebble_2.tscn\",\"B6SV\",\"CBNA\"\r\n\"Fiery Rock\",3,653,586,\"geX\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,1.2,389,455,0,0,400,1300,0.12,\"FALSE\",\"CREEPS\",,,,,\"536\",,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"res://src/towers/tower_sprites/fiery_pebble_3.tscn\",\"5T1H\",\"CBNA\"\r\n\"Fiery Rock Formation\",4,451,586,\"geX\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,1.2,775,904,0,0,800,1300,0.12,\"FALSE\",\"CREEPS\",,\"180,0.25\",,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"res://src/towers/tower_sprites/fiery_pebble_4.tscn\",\"IEI2\",\"CBNA\"\r\n\"Burning Rock\",5,2,586,\"geX\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,1.2,1343,1582,0,0,1400,1300,0.12,\"FALSE\",\"CREEPS\",,\"190,0.25\",,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"res://src/towers/tower_sprites/fiery_pebble_5.tscn\",\"C29N\",\"CBNA\"\r\n\"Hell Rock\",6,35,586,\"geX\",\"common\",\"fire\",\"TRUE\",\"elemental\",900,1.2,2247,2637,0,0,2350,1300,0.12,\"FALSE\",\"CREEPS\",,\"200,0.25\",,,,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/fiery_pebble.tres\",\"res://src/towers/tower_sprites/fiery_pebble_6.tscn\",\"JYXZ\",\"CBNA\"\r\n\"Healing Obelisk\",1,587,587,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,1.5,674,736,0,0,300,1200,0,\"FALSE\",\"CREEPS\",,,,,\"537\",,,\"res://src/towers/tower_behaviors/healing_obelisk.gd\",\"res://resources/icons/tower_icons/healing_obelisk.tres\",\"res://src/towers/tower_sprites/healing_obelisk_1.tscn\",\"0PH5\",\"06U0\"\r\n\"Healing Monument\",2,627,587,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,1.5,2614,2676,0,0,1000,1200,0,\"FALSE\",\"CREEPS\",,,,,\"538\",,,\"res://src/towers/tower_behaviors/healing_obelisk.gd\",\"res://resources/icons/tower_icons/healing_obelisk.tres\",\"res://src/towers/tower_sprites/healing_obelisk_2.tscn\",\"G5A7\",\"06U0\"\r\n\"Healing Altar\",3,628,587,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,1.5,5554,5616,0,0,1900,1200,0,\"FALSE\",\"CREEPS\",,,,,\"539\",,,\"res://src/towers/tower_behaviors/healing_obelisk.gd\",\"res://resources/icons/tower_icons/healing_obelisk.tres\",\"res://src/towers/tower_sprites/healing_obelisk_3.tscn\",\"D3IM\",\"06U0\"\r\n\"Healing Shrine\",4,629,587,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,1.5,10109,10171,0,0,3000,1200,0,\"FALSE\",\"CREEPS\",,,,,\"540\",,,\"res://src/towers/tower_behaviors/healing_obelisk.gd\",\"res://resources/icons/tower_icons/healing_obelisk.tres\",\"res://src/towers/tower_sprites/healing_obelisk_4.tscn\",\"SMW1\",\"06U0\"\r\n\"Lesser Priest\",1,590,590,\"Boekie\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,2,97,97,0,0,90,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"541\",,,\"res://src/towers/tower_behaviors/lesser_priest.gd\",\"res://resources/icons/tower_icons/lesser_priest.tres\",\"res://src/towers/tower_sprites/lesser_priest_1.tscn\",\"E9OH\",\"UQ0K\"\r\n\"Priest\",2,597,590,\"Boekie\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,2,301,301,0,0,290,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"542\",,,\"res://src/towers/tower_behaviors/lesser_priest.gd\",\"res://resources/icons/tower_icons/lesser_priest.tres\",\"res://src/towers/tower_sprites/lesser_priest_2.tscn\",\"SHZL\",\"UQ0K\"\r\n\"Experienced Priest\",3,598,590,\"Boekie\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,2,668,668,0,0,700,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"543\",,,\"res://src/towers/tower_behaviors/lesser_priest.gd\",\"res://resources/icons/tower_icons/lesser_priest.tres\",\"res://src/towers/tower_sprites/lesser_priest_3.tscn\",\"V73T\",\"UQ0K\"\r\n\"Holy Priest\",4,599,590,\"Boekie\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,2,1279,1279,0,0,1400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"544\",,,\"res://src/towers/tower_behaviors/lesser_priest.gd\",\"res://resources/icons/tower_icons/lesser_priest.tres\",\"res://src/towers/tower_sprites/lesser_priest_4.tscn\",\"N5TW\",\"UQ0K\"\r\n\"Divine Priest\",5,600,590,\"Boekie\",\"uncommon\",\"astral\",\"TRUE\",\"elemental\",1000,2,2179,2179,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATTACKSPEED,0,0.03\",\"545\",,,\"res://src/towers/tower_behaviors/lesser_priest.gd\",\"res://resources/icons/tower_icons/lesser_priest.tres\",\"res://src/towers/tower_sprites/lesser_priest_5.tscn\",\"76YW\",\"UQ0K\"\r\n\"Small Frozen Mushroom\",1,591,591,\"BetrayedKnight\",\"common\",\"ice\",\"TRUE\",\"elemental\",950,1.1,57,62,0,0,70,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_NATURE,0.35,0.012|MOD_DMG_TO_ORC,0.35,0.012|MOD_DMG_TO_HUMANOID,0.35,0.012\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_frozen_mushroom.tres\",\"res://src/towers/tower_sprites/small_frozen_mushroom_1.tscn\",\"F5DN\",\"DK81\"\r\n\"Frozen Mushroom\",2,592,591,\"BetrayedKnight\",\"common\",\"ice\",\"TRUE\",\"elemental\",950,1.1,201,212,0,0,245,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_NATURE,0.35,0.012|MOD_DMG_TO_ORC,0.35,0.012|MOD_DMG_TO_HUMANOID,0.35,0.012\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_frozen_mushroom.tres\",\"res://src/towers/tower_sprites/small_frozen_mushroom_2.tscn\",\"QFWS\",\"DK81\"\r\n\"Deep Frozen Mushroom\",3,593,591,\"BetrayedKnight\",\"common\",\"ice\",\"TRUE\",\"elemental\",950,1.1,563,580,0,0,680,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_NATURE,0.35,0.012|MOD_DMG_TO_ORC,0.35,0.012|MOD_DMG_TO_HUMANOID,0.35,0.012\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_frozen_mushroom.tres\",\"res://src/towers/tower_sprites/small_frozen_mushroom_3.tscn\",\"J6B7\",\"DK81\"\r\n\"Utterly Frozen Mushroom\",4,594,591,\"BetrayedKnight\",\"common\",\"ice\",\"TRUE\",\"elemental\",950,1.1,1177,1200,0,0,1450,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_NATURE,0.4,0.0135|MOD_DMG_TO_ORC,0.4,0.0135|MOD_DMG_TO_HUMANOID,0.4,0.0135\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_frozen_mushroom.tres\",\"res://src/towers/tower_sprites/small_frozen_mushroom_4.tscn\",\"3TWV\",\"DK81\"\r\n\"Devastatingly Frozen Mushroom\",5,595,591,\"BetrayedKnight\",\"common\",\"ice\",\"TRUE\",\"elemental\",950,1.1,1878,1925,0,0,2350,1300,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.5,0|MOD_DMG_TO_NATURE,0.4,0.0135|MOD_DMG_TO_ORC,0.4,0.0135|MOD_DMG_TO_HUMANOID,0.4,0.0135\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/small_frozen_mushroom.tres\",\"res://src/towers/tower_sprites/small_frozen_mushroom_5.tscn\",\"4H8X\",\"D3TK\"\r\n\"Nuclear Missile Launcher\",1,596,596,\"Matac\",\"unique\",\"iron\",\"TRUE\",\"essence\",2400,10,17777,17778,0,0,3400,700,1.56,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,\"400,1,500,0.75,600,0.5\",,,,,,\"res://src/towers/tower_behaviors/nuclear_missile_launcher.gd\",\"res://resources/icons/tower_icons/nuclear_missile_launcher.tres\",\"res://src/towers/tower_sprites/nuclear_missile_launcher_1.tscn\",\"WWC0\",\"X6QD\"\r\n\"Forest Archer\",1,601,601,\"Boekie\",\"rare\",\"nature\",\"TRUE\",\"essence\",850,2.2,715,720,0,0,660,1300,0.1,\"FALSE\",\"CREEPS\",\"3\",,,,\"546,547\",,,\"res://src/towers/tower_behaviors/forest_archer.gd\",\"res://resources/icons/tower_icons/forest_archer.tres\",\"res://src/towers/tower_sprites/forest_archer_1.tscn\",\"SNQY\",\"T61C\"\r\n\"Forest Ranger\",2,602,601,\"Boekie\",\"rare\",\"nature\",\"TRUE\",\"essence\",850,2.2,1194,1199,0,0,1100,1300,0.1,\"FALSE\",\"CREEPS\",\"3\",,,,\"548,549\",,,\"res://src/towers/tower_behaviors/forest_archer.gd\",\"res://resources/icons/tower_icons/forest_archer.tres\",\"res://src/towers/tower_sprites/forest_archer_2.tscn\",\"MGTN\",\"T61C\"\r\n\"Forest Amazon\",3,603,601,\"Boekie\",\"rare\",\"nature\",\"TRUE\",\"essence\",850,2.2,2661,2666,0,0,2450,1300,0.1,\"FALSE\",\"CREEPS\",\"3\",,,,\"550,551\",,,\"res://src/towers/tower_behaviors/forest_archer.gd\",\"res://resources/icons/tower_icons/forest_archer.tres\",\"res://src/towers/tower_sprites/forest_archer_3.tscn\",\"PO6F\",\"T61C\"\r\n\"Lightning Totem\",1,604,604,\"Boekie\",\"rare\",\"storm\",\"TRUE\",\"energy\",800,0.7,351,351,0,0,700,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,\"77\",,\"res://src/towers/tower_behaviors/lightning_totem.gd\",\"res://resources/icons/tower_icons/lightning_totem.tres\",\"res://src/towers/tower_sprites/lightning_totem_1.tscn\",\"Q954\",\"DHLQ\"\r\n\"Old Lightning Totem\",2,605,604,\"Boekie\",\"rare\",\"storm\",\"TRUE\",\"energy\",800,0.7,652,652,0,0,1300,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,\"78\",,\"res://src/towers/tower_behaviors/lightning_totem.gd\",\"res://resources/icons/tower_icons/lightning_totem.tres\",\"res://src/towers/tower_sprites/lightning_totem_2.tscn\",\"EWEF\",\"DHLQ\"\r\n\"Ancient Lightning Totem\",3,606,604,\"Boekie\",\"rare\",\"storm\",\"TRUE\",\"energy\",800,0.7,1205,1205,0,0,2400,1500,0.2,\"FALSE\",\"CREEPS\",,,,,,\"79\",,\"res://src/towers/tower_behaviors/lightning_totem.gd\",\"res://resources/icons/tower_icons/lightning_totem.tres\",\"res://src/towers/tower_sprites/lightning_totem_3.tscn\",\"SYEW\",\"DHLQ\"\r\n\"Sacred Altar\",1,607,607,\"Boekie\",\"unique\",\"nature\",\"TRUE\",\"essence\",875,2.5,3052,3052,0,0,3000,1500,0.25,\"FALSE\",\"CREEPS\",,,,,,\"80\",,\"res://src/towers/tower_behaviors/sacred_altar.gd\",\"res://resources/icons/tower_icons/sacred_altar.tres\",\"res://src/towers/tower_sprites/sacred_altar_1.tscn\",\"KQCK\",\"LFIO\"\r\n\"Rowing Boat\",1,608,608,\"Matac\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",900,1.7,434,434,0,0,300,900,0.15,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,\"25,1,150,0.4,250,0.1\",,,\"552\",\"81\",,\"res://src/towers/tower_behaviors/rowing_boat.gd\",\"res://resources/icons/tower_icons/rowing_boat.tres\",\"res://src/towers/tower_sprites/rowing_boat_1.tscn\",\"X111\",\"Z9ZT\"\r\n\"Frigate\",2,609,608,\"Matac\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",900,1.7,1345,1345,0,0,900,900,0.15,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,\"25,1,150,0.4,250,0.1\",,,\"553\",\"82\",,\"res://src/towers/tower_behaviors/rowing_boat.gd\",\"res://resources/icons/tower_icons/rowing_boat.tres\",\"res://src/towers/tower_sprites/rowing_boat_2.tscn\",\"UXDC\",\"SR1B\"\r\n\"Battleship\",3,610,608,\"Matac\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",900,1.7,2342,2342,0,0,1500,900,0.15,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,\"25,1,150,0.4,250,0.1\",,,\"554\",\"83\",,\"res://src/towers/tower_behaviors/rowing_boat.gd\",\"res://resources/icons/tower_icons/rowing_boat.tres\",\"res://src/towers/tower_sprites/rowing_boat_3.tscn\",\"9FF0\",\"OMPF\"\r\n\"Destroyer\",4,611,608,\"Matac\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",900,1.7,3932,3932,0,0,2400,900,0.15,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,\"25,1,150,0.4,250,0.1\",,,\"555\",\"84\",,\"res://src/towers/tower_behaviors/rowing_boat.gd\",\"res://resources/icons/tower_icons/rowing_boat.tres\",\"res://src/towers/tower_sprites/rowing_boat_4.tscn\",\"5A5T\",\"4BHS\"\r\n\"Basic Knowledge\",1,617,617,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",960,2.6,415,415,0,0,200,3000,0,\"FALSE\",\"CREEPS\",,,,,\"556\",,,\"res://src/towers/tower_behaviors/basic_knowledge.gd\",\"res://resources/icons/tower_icons/basic_knowledge.tres\",\"res://src/towers/tower_sprites/basic_knowledge_1.tscn\",\"WFE7\",\"GIWC\"\r\n\"Accumulated Knowledge\",2,618,617,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",960,2.6,960,960,0,0,450,3000,0,\"FALSE\",\"CREEPS\",,,,,\"557\",,,\"res://src/towers/tower_behaviors/basic_knowledge.gd\",\"res://resources/icons/tower_icons/basic_knowledge.tres\",\"res://src/towers/tower_sprites/basic_knowledge_2.tscn\",\"NW8W\",\"GIWC\"\r\n\"Small Library\",3,619,617,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",960,2.6,2083,2083,0,0,950,3000,0,\"FALSE\",\"CREEPS\",,,,,\"558\",,,\"res://src/towers/tower_behaviors/basic_knowledge.gd\",\"res://resources/icons/tower_icons/basic_knowledge.tres\",\"res://src/towers/tower_sprites/basic_knowledge_3.tscn\",\"SM4T\",\"GIWC\"\r\n\"Library\",4,620,617,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",960,2.6,3602,3602,0,0,1600,3000,0,\"FALSE\",\"CREEPS\",,,,,\"559\",,,\"res://src/towers/tower_behaviors/basic_knowledge.gd\",\"res://resources/icons/tower_icons/basic_knowledge.tres\",\"res://src/towers/tower_sprites/basic_knowledge_4.tscn\",\"WP8S\",\"GIWC\"\r\n\"Elder Library\",5,621,617,\"SirCoqalot.\",\"uncommon\",\"astral\",\"TRUE\",\"energy\",960,2.6,5546,5546,0,0,2400,3000,0,\"FALSE\",\"CREEPS\",,,,,\"560\",,,\"res://src/towers/tower_behaviors/basic_knowledge.gd\",\"res://resources/icons/tower_icons/basic_knowledge.tres\",\"res://src/towers/tower_sprites/basic_knowledge_5.tscn\",\"0BBF\",\"GIWC\"\r\n\"Miner\",1,622,622,\"drol\",\"rare\",\"iron\",\"TRUE\",\"decay\",1000,1.8,614,633,0,0,500,1200,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.008\",\"561,562\",,,\"res://src/towers/tower_behaviors/miner.gd\",\"res://resources/icons/tower_icons/miner.tres\",\"res://src/towers/tower_sprites/miner_1.tscn\",\"GS8R\",\"Z2BY\"\r\n\"Lonely Miner\",2,687,622,\"drol\",\"rare\",\"iron\",\"TRUE\",\"decay\",1000,1.8,1717,1771,0,0,1400,1200,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.008\",\"718,719\",,,\"res://src/towers/tower_behaviors/miner.gd\",\"res://resources/icons/tower_icons/miner.tres\",\"res://src/towers/tower_sprites/miner_2.tscn\",\"ZYJN\",\"Z2BY\"\r\n\"Fortunate Miner\",3,688,622,\"drol\",\"rare\",\"iron\",\"TRUE\",\"decay\",1000,1.8,3304,3423,0,0,2700,1200,0.2,\"FALSE\",\"CREEPS\",,,,\"MOD_BOUNTY_RECEIVED,0.2,0.008\",\"720,721\",,,\"res://src/towers/tower_behaviors/miner.gd\",\"res://resources/icons/tower_icons/miner.tres\",\"res://src/towers/tower_sprites/miner_3.tscn\",\"YNM1\",\"Z2BY\"\r\n\"Hall of Souls\",1,633,633,\"Natac\",\"rare\",\"darkness\",\"TRUE\",\"decay\",800,1.4,634,684,0,0,1000,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,\"85\",,\"res://src/towers/tower_behaviors/hall_of_souls.gd\",\"res://resources/icons/tower_icons/hall_of_souls.tres\",\"res://src/towers/tower_sprites/hall_of_souls_1.tscn\",\"FO3B\",\"HDRM\"\r\n\"Necropolis of Souls\",2,632,633,\"Natac\",\"rare\",\"darkness\",\"TRUE\",\"decay\",800,1.4,1268,1368,0,0,2000,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,\"86\",,\"res://src/towers/tower_behaviors/hall_of_souls.gd\",\"res://resources/icons/tower_icons/hall_of_souls.tres\",\"res://src/towers/tower_sprites/hall_of_souls_2.tscn\",\"XUZS\",\"HDRM\"\r\n\"Citadel of Souls\",3,631,633,\"Natac\",\"rare\",\"darkness\",\"TRUE\",\"decay\",800,1.4,1902,2052,0,0,3000,1500,0.15,\"FALSE\",\"CREEPS\",,,,,,\"87\",,\"res://src/towers/tower_behaviors/hall_of_souls.gd\",\"res://resources/icons/tower_icons/hall_of_souls.tres\",\"res://src/towers/tower_sprites/hall_of_souls_3.tscn\",\"ZNVJ\",\"HDRM\"\r\n\"Ruined Monolith\",1,638,638,\"drol\",\"common\",\"storm\",\"TRUE\",\"physical\",1050,1.5,47,51,0,0,50,1500,0.2,\"FALSE\",\"CREEPS\",,,\"3,0.5\",\"MOD_DMG_TO_AIR,0.1,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"res://src/towers/tower_sprites/ruined_monolith_1.tscn\",\"UTNY\",\"LALP\"\r\n\"Monolith\",2,639,638,\"drol\",\"common\",\"storm\",\"TRUE\",\"physical\",1050,1.5,136,150,0,0,150,1500,0.2,\"FALSE\",\"CREEPS\",,,\"3,0.46\",\"MOD_DMG_TO_AIR,0.1,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"res://src/towers/tower_sprites/ruined_monolith_2.tscn\",\"E6HC\",\"LALP\"\r\n\"Enchanted Monolith\",3,640,638,\"drol\",\"common\",\"storm\",\"TRUE\",\"physical\",1050,1.5,264,293,0,0,300,1500,0.2,\"FALSE\",\"CREEPS\",,,\"3,0.42\",\"MOD_DMG_TO_AIR,0.1,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"res://src/towers/tower_sprites/ruined_monolith_3.tscn\",\"BERN\",\"LALP\"\r\n\"Monolith of Lightning\",4,641,638,\"drol\",\"common\",\"storm\",\"TRUE\",\"physical\",1050,1.5,511,570,0,0,600,1500,0.2,\"FALSE\",\"CREEPS\",,,\"3,0.38\",\"MOD_DMG_TO_AIR,0.1,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"res://src/towers/tower_sprites/ruined_monolith_4.tscn\",\"00KS\",\"LALP\"\r\n\"Monolith of Thunder\",5,642,638,\"drol\",\"common\",\"storm\",\"TRUE\",\"physical\",1050,1.5,992,1111,0,0,1200,1500,0.2,\"FALSE\",\"CREEPS\",,,\"3,0.34\",\"MOD_DMG_TO_AIR,0.1,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"res://src/towers/tower_sprites/ruined_monolith_5.tscn\",\"4CZ9\",\"LALP\"\r\n\"Monolith of the Gathering Storm\",6,643,638,\"drol\",\"common\",\"storm\",\"TRUE\",\"physical\",1050,1.5,1924,2163,0,0,2400,1500,0.2,\"FALSE\",\"CREEPS\",,,\"3,0.3\",\"MOD_DMG_TO_AIR,0.1,0.01\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/ruined_monolith.tres\",\"res://src/towers/tower_sprites/ruined_monolith_6.tscn\",\"IHIC\",\"LALP\"\r\n\"Icy Spirit\",1,644,644,\"Boekie\",\"rare\",\"ice\",\"TRUE\",\"energy\",950,2,169,169,0,0,500,1500,0.25,\"FALSE\",\"CREEPS\",,,,,\"566\",,,\"res://src/towers/tower_behaviors/icy_spirit.gd\",\"res://resources/icons/tower_icons/icy_spirit.tres\",\"res://src/towers/tower_sprites/icy_spirit_1.tscn\",\"2MQ2\",\"BHJ6\"\r\n\"Chilled Spirit\",2,646,644,\"Boekie\",\"rare\",\"ice\",\"TRUE\",\"energy\",950,2,439,439,0,0,1300,1500,0.25,\"FALSE\",\"CREEPS\",,,,,\"567\",,,\"res://src/towers/tower_behaviors/icy_spirit.gd\",\"res://resources/icons/tower_icons/icy_spirit.tres\",\"res://src/towers/tower_sprites/icy_spirit_2.tscn\",\"QUQF\",\"BHJ6\"\r\n\"Frozen Spirit\",3,647,644,\"Boekie\",\"rare\",\"ice\",\"TRUE\",\"energy\",950,2,1013,1013,0,0,3000,1500,0.25,\"FALSE\",\"CREEPS\",,,,,\"568\",,,\"res://src/towers/tower_behaviors/icy_spirit.gd\",\"res://resources/icons/tower_icons/icy_spirit.tres\",\"res://src/towers/tower_sprites/icy_spirit_3.tscn\",\"HMQ1\",\"BHJ6\"\r\n\"Plagued Crypt\",1,645,645,\"cedi\",\"unique\",\"darkness\",\"TRUE\",\"decay\",1150,3,3899,3916,0,0,2500,900,0.3,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,\"25,1,50,0.4,150,0.25\",,,\"569,570\",,,\"res://src/towers/tower_behaviors/plagued_crypt.gd\",\"res://resources/icons/tower_icons/plagued_crypt.tres\",\"res://src/towers/tower_sprites/plagued_crypt_1.tscn\",\"8V29\",\"7IG3\"\r\n\"Dreadlord\",1,648,648,\"poussix\",\"unique\",\"darkness\",\"TRUE\",\"decay\",900,1,1086,1086,1000,10,2800,9000,0,\"TRUE\",\"CREEPS\",,,,\"MOD_MANA_PERC,0,0.05|MOD_MANA_REGEN_PERC,0,0.05\",\"571,572\",,\"156\",\"res://src/towers/tower_behaviors/dreadlord.gd\",\"res://resources/icons/tower_icons/dreadlord.tres\",\"res://src/towers/tower_sprites/dreadlord_1.tscn\",\"61CP\",\"V041\"\r\n\"Lich King\",1,649,649,\"Natac\",\"unique\",\"ice\",\"TRUE\",\"elemental\",800,1.4,2197,2296,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"573\",\"88\",,\"res://src/towers/tower_behaviors/lich_king.gd\",\"res://resources/icons/tower_icons/lich_king.tres\",\"res://src/towers/tower_sprites/lich_king_1.tscn\",\"GS44\",\"PPEC\"\r\n\"Rotted Flashing Grave\",1,650,650,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",2000,1,36,36,0,0,70,9001,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.1,0.01\",\"574\",,,\"res://src/towers/tower_behaviors/rotted_flashing_grave.gd\",\"res://resources/icons/tower_icons/rotted_flashing_grave.tres\",\"res://src/towers/tower_sprites/rotted_flashing_grave_1.tscn\",\"A4T3\",\"Z7AX\"\r\n\"Restored Flashing Grave\",2,668,650,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",2000,1,75,77,0,0,140,9001,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.1,0.01\",\"575\",,,\"res://src/towers/tower_behaviors/rotted_flashing_grave.gd\",\"res://resources/icons/tower_icons/rotted_flashing_grave.tres\",\"res://src/towers/tower_sprites/rotted_flashing_grave_2.tscn\",\"V7TR\",\"Z7AX\"\r\n\"Maintenanced Flashing Grave\",3,669,650,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",2000,1,150,152,0,0,280,9001,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.1,0.01\",\"576\",,,\"res://src/towers/tower_behaviors/rotted_flashing_grave.gd\",\"res://resources/icons/tower_icons/rotted_flashing_grave.tres\",\"res://src/towers/tower_sprites/rotted_flashing_grave_3.tscn\",\"7KEF\",\"Z7AX\"\r\n\"Flashing Cenotaph\",4,672,650,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",2000,1,301,303,0,0,560,9001,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.1,0.01\",\"577\",,,\"res://src/towers/tower_behaviors/rotted_flashing_grave.gd\",\"res://resources/icons/tower_icons/rotted_flashing_grave.tres\",\"res://src/towers/tower_sprites/rotted_flashing_grave_4.tscn\",\"AYS7\",\"Z7AX\"\r\n\"Elegant Flashing Cenotaph\",5,670,650,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",2000,1,604,606,0,0,1120,9001,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.1,0.01\",\"578\",,,\"res://src/towers/tower_behaviors/rotted_flashing_grave.gd\",\"res://resources/icons/tower_icons/rotted_flashing_grave.tres\",\"res://src/towers/tower_sprites/rotted_flashing_grave_5.tscn\",\"KQ55\",\"Z7AX\"\r\n\"Flashing Monument\",6,671,650,\"Natac\",\"common\",\"storm\",\"TRUE\",\"energy\",2000,1,1208,1210,0,0,2240,9001,0,\"TRUE\",\"CREEPS\",,,,\"MOD_DMG_TO_MAGIC,0.1,0.01\",\"579\",,,\"res://src/towers/tower_behaviors/rotted_flashing_grave.gd\",\"res://resources/icons/tower_icons/rotted_flashing_grave.tres\",\"res://src/towers/tower_sprites/rotted_flashing_grave_6.tscn\",\"B00C\",\"Z7AX\"\r\n\"Planar Gate\",1,651,651,\"Majildian\",\"unique\",\"astral\",\"TRUE\",\"energy\",700,2.5,3573,3573,1200,12,3200,1200,0,\"FALSE\",\"CREEPS\",,,,,\"580\",,\"157\",\"res://src/towers/tower_behaviors/planar_gate.gd\",\"res://resources/icons/tower_icons/planar_gate.tres\",\"res://src/towers/tower_sprites/planar_gate_1.tscn\",\"EUS1\",\"7XX5\"\r\n\"Garden of Eden\",1,652,652,\"Majildian\",\"unique\",\"nature\",\"TRUE\",\"essence\",800,1,1885,1888,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_NATURE,0.5,0|MOD_DMG_TO_ORC,0.5,0|MOD_DMG_TO_HUMANOID,0.5,0\",\"581\",,\"158\",\"res://src/towers/tower_behaviors/garden_of_eden.gd\",\"res://resources/icons/tower_icons/garden_of_eden.tres\",\"res://src/towers/tower_sprites/garden_of_eden_1.tscn\",\"IRSB\",\"GFRQ\"\r\n\"Sewer Connection\",1,654,654,\"D1000\",\"uncommon\",\"iron\",\"TRUE\",\"essence\",800,1.2,163,163,0,0,200,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.6,0|MOD_DMG_TO_NATURE,0.6,0.02\",\"582\",,,\"res://src/towers/tower_behaviors/sewer_connection.gd\",\"res://resources/icons/tower_icons/sewer_connection.tres\",\"res://src/towers/tower_sprites/sewer_connection_1.tscn\",\"ZNNN\",\"PAXI\"\r\n\"Broken Pipeline\",2,655,654,\"D1000\",\"uncommon\",\"iron\",\"TRUE\",\"essence\",800,1.2,489,489,0,0,600,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.6,0|MOD_DMG_TO_NATURE,0.6,0.02\",\"583\",,,\"res://src/towers/tower_behaviors/sewer_connection.gd\",\"res://resources/icons/tower_icons/sewer_connection.tres\",\"res://src/towers/tower_sprites/sewer_connection_2.tscn\",\"0NQT\",\"ORA9\"\r\n\"Chemical Center\",3,656,654,\"D1000\",\"uncommon\",\"iron\",\"TRUE\",\"essence\",800,1.2,979,979,0,0,1200,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.6,0|MOD_DMG_TO_NATURE,0.6,0.02\",\"584\",,,\"res://src/towers/tower_behaviors/sewer_connection.gd\",\"res://resources/icons/tower_icons/sewer_connection.tres\",\"res://src/towers/tower_sprites/sewer_connection_3.tscn\",\"X1N5\",\"PSFY\"\r\n\"Contaminated Hitch\",4,657,654,\"D1000\",\"uncommon\",\"iron\",\"TRUE\",\"essence\",800,1.2,1794,1794,0,0,2200,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_UNDEAD,-0.6,0|MOD_DMG_TO_NATURE,0.6,0.02\",\"585\",,,\"res://src/towers/tower_behaviors/sewer_connection.gd\",\"res://resources/icons/tower_icons/sewer_connection.tres\",\"res://src/towers/tower_sprites/sewer_connection_4.tscn\",\"88E6\",\"5V04\"\r\n\"Burning Watchtower\",1,658,659,\"Natac\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",800,1.4,51,52,0,0,65,1500,0,\"FALSE\",\"CREEPS\",,,,,\"586\",,,\"res://src/towers/tower_behaviors/burning_watchtower.gd\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"res://src/towers/tower_sprites/burning_watchtower_1.tscn\",\"UJZ1\",\"NK1A\"\r\n\"Burning Sentry\",2,659,659,\"Natac\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",800,1.38,286,287,0,0,370,1500,0,\"FALSE\",\"CREEPS\",,,,,\"587\",,,\"res://src/towers/tower_behaviors/burning_watchtower.gd\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"res://src/towers/tower_sprites/burning_watchtower_2.tscn\",\"6K6R\",\"NK1A\"\r\n\"Burning Outpost\",3,660,659,\"Natac\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",800,1.36,759,760,0,0,1000,1500,0,\"FALSE\",\"CREEPS\",,,,,\"588\",,,\"res://src/towers/tower_behaviors/burning_watchtower.gd\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"res://src/towers/tower_sprites/burning_watchtower_3.tscn\",\"VTO7\",\"NK1A\"\r\n\"Burning Fortress\",4,661,659,\"Natac\",\"uncommon\",\"fire\",\"TRUE\",\"elemental\",800,1.34,1865,1866,0,0,2500,1500,0,\"FALSE\",\"CREEPS\",,,,,\"589\",,,\"res://src/towers/tower_behaviors/burning_watchtower.gd\",\"res://resources/icons/tower_icons/burning_watchtower.tres\",\"res://src/towers/tower_sprites/burning_watchtower_4.tscn\",\"GMNQ\",\"NK1A\"\r\n\"Sniper\",1,662,662,\"cedi\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",1400,2.5,425,425,0,0,300,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.7,0|MOD_DMG_TO_NORMAL,-0.3,0|MOD_DMG_TO_CHAMPION,0.2,0.016|MOD_DMG_TO_BOSS,0.5,0.04|MOD_DMG_TO_AIR,0.2,0.016\",\"590\",,,\"res://src/towers/tower_behaviors/sniper.gd\",\"res://resources/icons/tower_icons/sniper.tres\",\"res://src/towers/tower_sprites/sniper_1.tscn\",\"4H1A\",\"08TU\"\r\n\"Skilled Sniper\",2,663,662,\"cedi\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",1400,2.5,1276,1276,0,0,900,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.7,0|MOD_DMG_TO_NORMAL,-0.3,0|MOD_DMG_TO_CHAMPION,0.2,0.016|MOD_DMG_TO_BOSS,0.5,0.04|MOD_DMG_TO_AIR,0.2,0.016\",\"591\",,,\"res://src/towers/tower_behaviors/sniper.gd\",\"res://resources/icons/tower_icons/sniper.tres\",\"res://src/towers/tower_sprites/sniper_2.tscn\",\"H4P3\",\"08TU\"\r\n\"Sniper Nest\",3,664,662,\"cedi\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",1400,2.5,2551,2551,0,0,1800,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.7,0|MOD_DMG_TO_NORMAL,-0.3,0|MOD_DMG_TO_CHAMPION,0.2,0.016|MOD_DMG_TO_BOSS,0.5,0.04|MOD_DMG_TO_AIR,0.2,0.016\",\"592\",,,\"res://src/towers/tower_behaviors/sniper.gd\",\"res://resources/icons/tower_icons/sniper.tres\",\"res://src/towers/tower_sprites/sniper_3.tscn\",\"XP5H\",\"08TU\"\r\n\"Fortified Sniper Nest\",4,665,662,\"cedi\",\"uncommon\",\"iron\",\"TRUE\",\"physical\",1400,2.5,4252,4252,0,0,3000,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_DMG_TO_MASS,-0.7,0|MOD_DMG_TO_NORMAL,-0.3,0|MOD_DMG_TO_CHAMPION,0.2,0.016|MOD_DMG_TO_BOSS,0.5,0.04|MOD_DMG_TO_AIR,0.2,0.016\",\"593\",,,\"res://src/towers/tower_behaviors/sniper.gd\",\"res://resources/icons/tower_icons/sniper.tres\",\"res://src/towers/tower_sprites/sniper_4.tscn\",\"FQLW\",\"08TU\"\r\n\"Sun Crusader\",1,666,666,\"cedi\",\"rare\",\"astral\",\"TRUE\",\"physical\",750,0.75,176,176,100,0,750,1500,0,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,,\"5,0.1\",\"MOD_DMG_TO_UNDEAD,0.5,0|MOD_MANA,0,1\",\"594\",,\"159\",\"res://src/towers/tower_behaviors/sun_crusader.gd\",\"res://resources/icons/tower_icons/sun_crusader.tres\",\"res://src/towers/tower_sprites/sun_crusader_1.tscn\",\"7R5R\",\"4R6I\"\r\n\"Sun Paladin\",2,667,666,\"cedi\",\"rare\",\"astral\",\"TRUE\",\"physical\",750,0.75,470,470,150,0,2000,1500,0,\"FALSE\",\"CREEPS,SIZE_MASS,SIZE_NORMAL,SIZE_CHAMPION,SIZE_BOSS\",,,\"5,0.1\",\"MOD_DMG_TO_UNDEAD,1,0|MOD_MANA,0,1\",\"595\",,\"160\",\"res://src/towers/tower_behaviors/sun_crusader.gd\",\"res://resources/icons/tower_icons/sun_crusader.tres\",\"res://src/towers/tower_sprites/sun_crusader_2.tscn\",\"OPNZ\",\"Q3QP\"\r\n\"Baby Plant\",1,673,673,\"Boekie\",\"common\",\"nature\",\"TRUE\",\"decay\",825,1.75,108,108,0,0,65,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.4,-0.025|MOD_DAMAGE_BASE_PERC,0,0.05\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/baby_plant.tres\",\"res://src/towers/tower_sprites/baby_plant_1.tscn\",\"GVSD\",\"UN9D\"\r\n\"Small Plant\",2,674,673,\"Boekie\",\"common\",\"nature\",\"TRUE\",\"decay\",825,1.75,215,215,0,0,135,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.42,-0.025|MOD_DAMAGE_BASE_PERC,0,0.055\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/baby_plant.tres\",\"res://src/towers/tower_sprites/baby_plant_2.tscn\",\"69LF\",\"UN9D\"\r\n\"Plant\",3,675,673,\"Boekie\",\"common\",\"nature\",\"TRUE\",\"decay\",825,1.75,454,454,0,0,300,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.44,-0.025|MOD_DAMAGE_BASE_PERC,0,0.06\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/baby_plant.tres\",\"res://src/towers/tower_sprites/baby_plant_3.tscn\",\"A647\",\"UN9D\"\r\n\"Growing Plant\",4,676,673,\"Boekie\",\"common\",\"nature\",\"TRUE\",\"decay\",825,1.75,920,920,0,0,640,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.46,-0.025|MOD_DAMAGE_BASE_PERC,0,0.065\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/baby_plant.tres\",\"res://src/towers/tower_sprites/baby_plant_4.tscn\",\"7R5U\",\"UN9D\"\r\n\"Fast Growing Plant\",5,677,673,\"Boekie\",\"common\",\"nature\",\"TRUE\",\"decay\",825,1.75,1933,1933,0,0,1400,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.48,-0.025|MOD_DAMAGE_BASE_PERC,0,0.07\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/baby_plant.tres\",\"res://src/towers/tower_sprites/baby_plant_5.tscn\",\"WERM\",\"UN9D\"\r\n\"Mutating Plant\",6,678,673,\"Boekie\",\"common\",\"nature\",\"TRUE\",\"decay\",825,1.75,3440,3440,0,0,2600,1500,0,\"FALSE\",\"CREEPS\",,,,\"MOD_EXP_RECEIVED,0.5,-0.025|MOD_DAMAGE_BASE_PERC,0,0.075\",,,,\"res://src/towers/tower_behaviors/empty_tower_behavior.gd\",\"res://resources/icons/tower_icons/baby_plant.tres\",\"res://src/towers/tower_sprites/baby_plant_6.tscn\",\"S933\",\"UN9D\"\r\n\"Rooted Chasm\",1,680,680,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",950,1.4,47,47,0,0,45,1500,0,\"FALSE\",\"CREEPS\",,,,,\"596\",,,\"res://src/towers/tower_behaviors/rooted_chasm.gd\",\"res://resources/icons/tower_icons/rooted_chasm.tres\",\"res://src/towers/tower_sprites/rooted_chasm_1.tscn\",\"YBCV\",\"KVVS\"\r\n\"Blooming Chasm\",2,681,680,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",950,1.4,289,289,0,0,275,1500,0,\"FALSE\",\"CREEPS\",,,,,\"597\",,,\"res://src/towers/tower_behaviors/rooted_chasm.gd\",\"res://resources/icons/tower_icons/rooted_chasm.tres\",\"res://src/towers/tower_sprites/rooted_chasm_2.tscn\",\"PV0V\",\"KVVS\"\r\n\"Cultivated Chasm\",3,682,680,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",950,1.4,961,961,0,0,915,1500,0,\"FALSE\",\"CREEPS\",,,,,\"598\",,,\"res://src/towers/tower_behaviors/rooted_chasm.gd\",\"res://resources/icons/tower_icons/rooted_chasm.tres\",\"res://src/towers/tower_sprites/rooted_chasm_3.tscn\",\"Y9G9\",\"KVVS\"\r\n\"Flourishing Chasm\",4,679,680,\"SirCoqalot.\",\"uncommon\",\"nature\",\"TRUE\",\"essence\",950,1.4,2258,2258,0,0,2150,1500,0,\"FALSE\",\"CREEPS\",,,,,\"599\",,,\"res://src/towers/tower_behaviors/rooted_chasm.gd\",\"res://resources/icons/tower_icons/rooted_chasm.tres\",\"res://src/towers/tower_sprites/rooted_chasm_4.tscn\",\"T66C\",\"KVVS\"\r\n\"Polar Bear Cub\",1,683,683,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.3,503,603,0,0,600,1500,0,\"FALSE\",\"CREEPS\",,\"300,0.35\",,,\"600\",,,\"res://src/towers/tower_behaviors/polar_bear_cub.gd\",\"res://resources/icons/tower_icons/polar_bear_cub.tres\",\"res://src/towers/tower_sprites/polar_bear_cub_1.tscn\",\"FLRT\",\"8OCO\"\r\n\"Polar Bear\",2,9,683,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.35,1108,1208,0,0,1400,1500,0,\"FALSE\",\"CREEPS\",,\"300,0.35\",,,\"601\",,,\"res://src/towers/tower_behaviors/polar_bear_cub.gd\",\"res://resources/icons/tower_icons/polar_bear_cub.tres\",\"res://src/towers/tower_sprites/polar_bear_cub_2.tscn\",\"UDOO\",\"8OCO\"\r\n\"Elder Polar Bear\",3,10,683,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"elemental\",900,1.3,2127,2227,0,0,2950,1500,0,\"FALSE\",\"CREEPS\",,\"300,0.35\",,,\"602\",,,\"res://src/towers/tower_behaviors/polar_bear_cub.gd\",\"res://resources/icons/tower_icons/polar_bear_cub.tres\",\"res://src/towers/tower_sprites/polar_bear_cub_3.tscn\",\"BGRE\",\"8OCO\"\r\n\"Frosty Rock\",1,684,684,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"energy\",760,2.3,237,237,0,0,100,1200,0,\"FALSE\",\"CREEPS\",,,,,\"603\",,,\"res://src/towers/tower_behaviors/frosty_rock.gd\",\"res://resources/icons/tower_icons/frosty_rock.tres\",\"res://src/towers/tower_sprites/frosty_rock_1.tscn\",\"FNW6\",\"QDCC\"\r\n\"Frozen Rock\",2,685,684,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"energy\",760,2.3,1156,1156,0,0,520,1200,0,\"FALSE\",\"CREEPS\",,,,,\"604\",,,\"res://src/towers/tower_behaviors/frosty_rock.gd\",\"res://resources/icons/tower_icons/frosty_rock.tres\",\"res://src/towers/tower_sprites/frosty_rock_2.tscn\",\"SK6I\",\"QDCC\"\r\n\"Glacier Tongue\",3,686,684,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"energy\",760,2.3,2698,2698,0,0,1300,1200,0,\"FALSE\",\"CREEPS\",,,,,\"605\",,,\"res://src/towers/tower_behaviors/frosty_rock.gd\",\"res://resources/icons/tower_icons/frosty_rock.tres\",\"res://src/towers/tower_sprites/frosty_rock_3.tscn\",\"EKZM\",\"QDCC\"\r\n\"Glacier\",4,330,684,\"SirCoqalot.\",\"uncommon\",\"ice\",\"TRUE\",\"energy\",760,2.3,4144,4144,0,0,2150,1200,0,\"FALSE\",\"CREEPS\",,,,,\"606\",,,\"res://src/towers/tower_behaviors/frosty_rock.gd\",\"res://resources/icons/tower_icons/frosty_rock.tres\",\"res://src/towers/tower_sprites/frosty_rock_4.tscn\",\"JP4G\",\"QDCC\"\r\n\"Greyfang\",1,990,990,\"Deemzul\",\"unique\",\"nature\",\"TRUE\",\"physical\",900,1.7,4271,4271,0,0,3400,1800,0,\"FALSE\",\"CREEPS\",,,,\"MOD_ATK_CRIT_CHANCE,0.2,0.004|MOD_ATK_CRIT_DAMAGE,2,0.04|MOD_MULTICRIT_COUNT,2,0|MOD_ATTACKSPEED,0,0.022\",\"607,608\",,,\"res://src/towers/tower_behaviors/greyfang.gd\",\"res://resources/icons/tower_icons/greyfang.tres\",\"res://src/towers/tower_sprites/greyfang_1.tscn\",\"LUMB\",\"LUGG\"\r\n\"Fenced Flames\",1,991,991,\"Deemzul\",\"uncommon\",\"fire\",\"TRUE\",\"physical\",900,1.2,90,90,0,0,120,1800,0,\"FALSE\",\"CREEPS\",,,,,\"609\",,,\"res://src/towers/tower_behaviors/fenced_flames.gd\",\"res://resources/icons/tower_icons/fenced_flames.tres\",\"res://src/towers/tower_sprites/fenced_flames_1.tscn\",\"73OT\",\"G517\"\r\n\"Enclosed Flames\",2,992,991,\"Deemzul\",\"uncommon\",\"fire\",\"TRUE\",\"physical\",900,1.2,90,90,0,0,550,1800,0,\"FALSE\",\"CREEPS\",,,,,\"610\",,,\"res://src/towers/tower_behaviors/fenced_flames.gd\",\"res://resources/icons/tower_icons/fenced_flames.tres\",\"res://src/towers/tower_sprites/fenced_flames_2.tscn\",\"ST03\",\"G517\"\r\n\"Burning Inside\",3,993,991,\"Deemzul\",\"uncommon\",\"fire\",\"TRUE\",\"physical\",900,1.2,90,90,0,0,1250,1800,0,\"FALSE\",\"CREEPS\",,,,,\"611\",,,\"res://src/towers/tower_behaviors/fenced_flames.gd\",\"res://resources/icons/tower_icons/fenced_flames.tres\",\"res://src/towers/tower_sprites/fenced_flames_3.tscn\",\"OVMN\",\"G517\"\r\n\"Crucibled Flames\",4,994,991,\"Deemzul\",\"uncommon\",\"fire\",\"TRUE\",\"physical\",900,1.2,90,90,0,0,2250,1800,0,\"FALSE\",\"CREEPS\",,,,,\"612\",,,\"res://src/towers/tower_behaviors/fenced_flames.gd\",\"res://resources/icons/tower_icons/fenced_flames.tres\",\"res://src/towers/tower_sprites/fenced_flames_4.tscn\",\"RV4Q\",\"G517\"\r\n"
  },
  {
    "path": "data/tower_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/wave_special_properties.csv",
    "content": "\"id\",\"name english\",\"hp modifier\",\"required wave level\",\"frequency\",\"creep sizes\",\"applies only to champions or bosses\",\"group list\",\"uses mana\",\"color\",\"name\",\"short name\",\"description\",\"enabled\",\"script path\",\"icon path\"\r\n0,\"Speed\",-0.2,0,100,\"all\",\"FALSE\",\"speed,mshield-speed\",\"FALSE\",\"#ffbbbb\",\"LMZH\",\"BL3Y\",\"JI1D\",\"TRUE\",\"res://src/creeps/special_buffs/creep_speed.gd\",\"res://resources/icons/fire/burning_cloth.tres\"\r\n1,\"Greater Speed\",-0.33,16,80,\"all\",\"FALSE\",\"speed,mshield-speed\",\"FALSE\",\"#ffbbbb\",\"FH49\",\"N47W\",\"3K4Y\",\"TRUE\",\"res://src/creeps/special_buffs/creep_greater_speed.gd\",\"res://resources/icons/fire/burning_cloth.tres\"\r\n2,\"Xtreme Speed\",-0.3,24,60,\"all\",\"FALSE\",\"speed,mshield-speed\",\"FALSE\",\"#ffbbbb\",\"Q79G\",\"HST6\",\"59V2\",\"TRUE\",\"res://src/creeps/special_buffs/creep_xtreme_speed.gd\",\"res://resources/icons/fire/burning_cloth.tres\"\r\n3,\"Slow\",0.35,32,80,\"all\",\"FALSE\",\"speed,mshield-speed\",\"FALSE\",\"#bbffbb\",\"94WS\",\"C6FD\",\"YCAY\",\"TRUE\",\"res://src/creeps/special_buffs/creep_slow.gd\",\"res://resources/icons/clubs/club_04_without_handle.tres\"\r\n4,\"Invisible\",-0.075,0,130,\"normal,mass,air\",\"FALSE\",\"invis\",\"FALSE\",\"#ffffff\",\"HQCC\",\"OYEE\",\"YT2V\",\"FALSE\",\"res://src/creeps/special_buffs/creep_invisible.gd\",\"res://resources/icons/rings/ring_03.tres\"\r\n5,\"Strong\",0.2,16,100,\"normal,mass,air\",\"FALSE\",\"exp,bounty\",\"FALSE\",\"#ffd7bb\",\"IUF1\",\"9NAP\",\"TB32\",\"TRUE\",\"res://src/creeps/special_buffs/creep_strong.gd\",\"res://resources/icons/misc/red_knight.tres\"\r\n6,\"Rich\",0,0,100,\"all\",\"FALSE\",\"exp,bounty\",\"FALSE\",\"#ffd7bb\",\"05NK\",\"1CJ5\",\"IHM3\",\"TRUE\",\"res://src/creeps/special_buffs/creep_rich.gd\",\"res://resources/icons/misc/gold_cart.tres\"\r\n7,\"Relic Raider\",0,0,100,\"all\",\"FALSE\",\"bounty,relic\",\"FALSE\",\"#ffd7bb\",\"98J5\",\"KFPA\",\"LBKD\",\"TRUE\",\"res://src/creeps/special_buffs/creep_relic_raider.gd\",\"res://resources/icons/swords/greatsword_01.tres\"\r\n8,\"Ultra Wisdom\",0,0,100,\"all\",\"FALSE\",\"exp,bounty,relic\",\"FALSE\",\"#ffd7bb\",\"T5S1\",\"8KPI\",\"OSX6\",\"TRUE\",\"res://src/creeps/special_buffs/creep_ultra_wisdom.gd\",\"res://resources/icons/books/book_07.tres\"\r\n9,\"Armored\",-0.25,0,100,\"all\",\"FALSE\",\"armor-spellres\",\"FALSE\",\"#aaaaaa\",\"Q1R9\",\"7P05\",\"JG5G\",\"TRUE\",\"res://src/creeps/special_buffs/creep_armored.gd\",\"res://resources/icons/armor/chest_plate.tres\"\r\n10,\"Heavy Armored\",-0.35,16,100,\"all\",\"FALSE\",\"armor-spellres\",\"FALSE\",\"#999999\",\"RLHE\",\"95NA\",\"3XZL\",\"TRUE\",\"res://src/creeps/special_buffs/creep_heavy_armored.gd\",\"res://resources/icons/armor/chest_plate.tres\"\r\n11,\"Xtreme Armor\",-0.67,32,80,\"all\",\"FALSE\",\"armor-spellres,speed\",\"FALSE\",\"#999999\",\"UMP9\",\"DKY6\",\"7WH3\",\"TRUE\",\"res://src/creeps/special_buffs/creep_xtreme_armor.gd\",\"res://resources/icons/armor/chest_plate.tres\"\r\n12,\"Evasion\",-0.2,16,140,\"all\",\"FALSE\",\"evasion,immune-evasion\",\"FALSE\",\"#e3f988\",\"DD5N\",\"VTFX\",\"57VY\",\"TRUE\",\"res://src/creeps/special_buffs/creep_evasion.gd\",\"res://resources/icons/daggers/dagger_09.tres\"\r\n13,\"Xtreme Evasion\",-0.65,40,110,\"all\",\"FALSE\",\"evasion,immune-evasion\",\"FALSE\",\"#e3f988\",\"3GUO\",\"OGW2\",\"CTD6\",\"TRUE\",\"res://src/creeps/special_buffs/creep_xtreme_evasion.gd\",\"res://resources/icons/daggers/dagger_09.tres\"\r\n14,\"Ghost\",-0.77,64,140,\"all\",\"FALSE\",\"evasion,ghost-ethereal,armor-spellres\",\"FALSE\",\"#ffffffaa\",\"CN7P\",\"I4YW\",\"D5YC\",\"TRUE\",\"res://src/creeps/special_buffs/creep_ghost.gd\",\"res://resources/icons/faces/sleeping_leaf_spirit.tres\"\r\n15,\"Spell Resistance\",-0.12,8,130,\"all\",\"FALSE\",\"armor-spellres,spellres\",\"FALSE\",\"#d9a6f9\",\"FBGW\",\"0XTO\",\"T8N5\",\"TRUE\",\"res://src/creeps/special_buffs/creep_spell_resistance.gd\",\"res://resources/icons/magic/magic_stone.tres\"\r\n16,\"Greater Spell Resistance\",-0.36,24,130,\"all\",\"FALSE\",\"armor-spellres,spellres\",\"FALSE\",\"#d9a6f9\",\"Z6LA\",\"3HLY\",\"DHWD\",\"TRUE\",\"res://src/creeps/special_buffs/creep_greater_spell_resistance.gd\",\"res://resources/icons/magic/magic_stone.tres\"\r\n17,\"Magic Immunity\",-0.36,24,180,\"all\",\"FALSE\",\"armor-spellres,immune-evasion,spellres\",\"TRUE\",\"#d9a6f9\",\"QYGG\",\"79IP\",\"EV5O\",\"TRUE\",\"res://src/creeps/special_buffs/creep_magic_immunity.gd\",\"res://resources/icons/rings/ring_04.tres\"\r\n18,\"Ethereal\",-0.52,24,200,\"all\",\"FALSE\",\"spellres,regen-ethereal,mech-ethereal,ghost-ethereal,gravid-ethereal\",\"FALSE\",\"#ffffff\",\"6O15\",\"M720\",\"PTPY\",\"TRUE\",\"res://src/creeps/special_buffs/creep_ethereal.gd\",\"res://resources/icons/undead/skull_phazing.tres\"\r\n19,\"Slow Aura\",-0.4,24,150,\"normal,mass,boss\",\"TRUE\",,\"FALSE\",\"#bb8080\",\"9DZV\",\"2ORV\",\"2JS2\",\"TRUE\",\"res://src/creeps/special_buffs/creep_slow_aura.gd\",\"res://resources/icons/misc/flag_03.tres\"\r\n20,\"Mana Drain Aura\",-0.2,32,150,\"normal,mass,boss\",\"TRUE\",\"demana\",\"FALSE\",\"#7c97e2\",\"BZX0\",\"JPO2\",\"SEMC\",\"TRUE\",\"res://src/creeps/special_buffs/creep_mana_drain_aura.gd\",\"res://resources/icons/misc/flag_01.tres\"\r\n21,\"Spellbinder\",-0.2,48,120,\"normal,mass,boss\",\"TRUE\",\"demana\",\"TRUE\",\"#ff77ff\",\"LZU3\",\"DL82\",\"S3GU\",\"TRUE\",\"res://src/creeps/special_buffs/creep_spellbinder.gd\",\"res://resources/icons/undead/skull_02.tres\"\r\n22,\"Stun Revenge\",-0.57,32,100,\"all\",\"FALSE\",,\"FALSE\",\"#ffa5bb\",\"E2EQ\",\"EGRV\",\"0SRZ\",\"TRUE\",\"res://src/creeps/special_buffs/creep_stun_revenge.gd\",\"res://resources/icons/undead/skull_05.tres\"\r\n23,\"Regeneration\",-0.17,16,140,\"all\",\"FALSE\",\"regen,regen-ethereal,regen-evo,regen-protector\",\"FALSE\",\"#ffbbff\",\"86IT\",\"SRQE\",\"F09T\",\"TRUE\",\"res://src/creeps/special_buffs/creep_regeneration.gd\",\"res://resources/icons/misc/poison_01.tres\"\r\n24,\"Xtreme Regeneration\",-0.48,32,110,\"all\",\"FALSE\",\"regen,regen-ethereal,regen-evo,regen-protector\",\"FALSE\",\"#ffbbff\",\"D16L\",\"K1WK\",\"1C6S\",\"TRUE\",\"res://src/creeps/special_buffs/creep_xtreme_regeneration.gd\",\"res://resources/icons/misc/poison_01.tres\"\r\n25,\"Second Chance\",-0.47,32,160,\"all\",\"FALSE\",\"regen,regen-evo,seccha\",\"TRUE\",\"#ffd7bb\",\"ULM0\",\"18FX\",\"BE3D\",\"TRUE\",\"res://src/creeps/special_buffs/creep_second_chance.gd\",\"res://resources/icons/trinkets/trinket_04.tres\"\r\n26,\"Semi-Mechanical\",-0.28,40,150,\"all\",\"FALSE\",\"mech-ethereal\",\"FALSE\",\"#7c97e2\",\"7LDM\",\"SA83\",\"RHJV\",\"TRUE\",\"res://src/creeps/special_buffs/creep_semi-mechanical.gd\",\"res://resources/icons/mechanical/factory_gears.tres\"\r\n27,\"Mechanical\",-0.62,56,150,\"all\",\"FALSE\",\"mech-ethereal\",\"FALSE\",\"#7c97e2\",\"7DFX\",\"JTSZ\",\"XC3D\",\"TRUE\",\"res://src/creeps/special_buffs/creep_mechanical.gd\",\"res://resources/icons/mechanical/factory_gears.tres\"\r\n28,\"Meaty\",0.15,80,100,\"normal,mass,boss\",\"TRUE\",,\"FALSE\",\"#ffbbbb\",\"LIR7\",\"RY5L\",\"53FN\",\"TRUE\",\"res://src/creeps/special_buffs/creep_meaty.gd\",\"res://resources/icons/food/pork.tres\"\r\n29,\"Evolving\",-0.3,56,150,\"mass,normal\",\"FALSE\",\"regen-evo\",\"FALSE\",\"#bbffbb\",\"HVTO\",\"4NF4\",\"57DU\",\"TRUE\",\"res://src/creeps/special_buffs/creep_evolving.gd\",\"res://resources/icons/animals/fish_02.tres\"\r\n30,\"Unlucky\",-0.15,56,150,\"all\",\"FALSE\",,\"FALSE\",\"#e3f988\",\"WDET\",\"3LEV\",\"RDWL\",\"TRUE\",\"res://src/creeps/special_buffs/creep_unlucky.gd\",\"res://resources/icons/statues/statue_01.tres\"\r\n31,\"Flock\",-0.5,40,250,\"air\",\"FALSE\",\"exp,bounty,relic\",\"FALSE\",\"#7c97e2\",\"MQIJ\",\"LACP\",\"JNSA\",\"TRUE\",\"res://src/creeps/special_buffs/creep_flock.gd\",\"res://resources/icons/animals/bat_01.tres\"\r\n32,\"Gravid\",-0.53,40,200,\"normal,mass,boss\",\"TRUE\",\"exp,bounty,seccha,relic,gravid-ethereal\",\"TRUE\",\"#ff77ff\",\"RD90\",\"5K38\",\"7AZB\",\"FALSE\",\"res://src/creeps/special_buffs/creep_gravid.gd\",\"res://resources/icons/misc/spiky_totem_01.tres\"\r\n33,\"Protector\",-0.2,64,240,\"mass,normal\",\"TRUE\",\"regen-protector\",\"FALSE\",\"#ffe4b5\",\"UZXN\",\"KYIV\",\"KEKA\",\"TRUE\",\"res://src/creeps/special_buffs/creep_protector.gd\",\"res://resources/icons/statues/statue_dwarf_02.tres\"\r\n34,\"Manashield\",-0.55,28,150,\"mass,normal\",\"FALSE\",\"mshield,mshield-speed,corpse\",\"TRUE\",\"#bbbbff\",\"OM2K\",\"Z92I\",\"2LNM\",\"TRUE\",\"res://src/creeps/special_buffs/creep_manashield.gd\",\"res://resources/icons/tower_icons/storm_battery.tres\"\r\n35,\"Manashield+\",-0.75,80,150,\"mass,normal\",\"FALSE\",\"mshield,mshield-speed,corpse\",\"TRUE\",\"#bbbbff\",\"AMF5\",\"50R6\",\"35FE\",\"TRUE\",\"res://src/creeps/special_buffs/creep_manashield+.gd\",\"res://resources/icons/tower_icons/storm_battery.tres\"\r\n36,\"Necromancer\",-0.25,50,150,\"mass,normal\",\"TRUE\",\"corpse\",\"TRUE\",\"#d9a6f9\",\"J21D\",\"ZLAU\",\"M7FF\",\"TRUE\",\"res://src/creeps/special_buffs/creep_necromancer.gd\",\"res://resources/icons/undead/skull_wand_04.tres\"\r\n37,\"Purge Revenge\",-0.5,32,100,\"all\",\"FALSE\",,\"FALSE\",\"#ff77ff\",\"FKXP\",\"PZPG\",\"78SR\",\"TRUE\",\"res://src/creeps/special_buffs/creep_purge_revenge.gd\",\"res://resources/icons/misc/teapot_02.tres\"\r\n38,\"Fireball\",-0.03,240,0,\"boss\",\"TRUE\",,\"FALSE\",\"#ffbbbb\",\"F24X\",\"QYR7\",\"CK9M\",\"TRUE\",\"res://src/creeps/special_buffs/creep_fireball.gd\",\"res://resources/icons/tower_icons/meteor_totem.tres\"\r\n39,\"Dart\",0.2,240,170,\"boss\",\"TRUE\",\"speed\",\"FALSE\",\"#ffbbbb\",\"21NC\",\"SE4F\",\"TIGD\",\"TRUE\",\"res://src/creeps/special_buffs/creep_dart.gd\",\"res://resources/icons/tower_icons/charged_obelisk.tres\"\r\n40,\"Broody\",-0.3,240,40,\"boss\",\"TRUE\",,\"TRUE\",\"#ffbbbb\",\"P1WA\",\"ZF1Y\",\"IYUS\",\"FALSE\",\"res://src/creeps/special_buffs/creep_broody.gd\",\"res://resources/icons/tower_icons/spider_queen.tres\"\r\n"
  },
  {
    "path": "data/wave_special_properties.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "data/wisdom_upgrades.csv",
    "content": "\"id\",\"name english\",\"tooltip\",\"icon\"\n0,\"Advanced Fortune\",\"KYHF\",\"res://resources/icons/hud/dice.tres\"\n1,\"Element Mastery\",\"EAF9\",\"res://resources/icons/hud/research_elements.tres\"\n2,\"Swiftness Mastery\",\"OFOF\",\"res://resources/icons/plants/leaf_01.tres\"\n3,\"Combat Mastery\",\"VJZ2\",\"res://resources/icons/swords/greatsword_01.tres\"\n4,\"Mastery of Pain\",\"P81J\",\"res://resources/icons/hud/recipe_reassemble.tres\"\n5,\"Advanced Sorcery\",\"L6Z5\",\"res://resources/icons/books/book_02.tres\"\n6,\"Mastery of Magic\",\"S0T2\",\"res://resources/icons/plants/flower_06.tres\"\n7,\"Mastery of Logistics\",\"2GFC\",\"res://resources/icons/food/pork.tres\"\n8,\"Loot Mastery\",\"Z13P\",\"res://resources/icons/trinkets/trinket_05.tres\"\n9,\"Advanced Wisdom\",\"9JVP\",\"res://resources/icons/scrolls/scroll_06.tres\"\n10,\"Pillage Mastery\",\"WU10\",\"res://resources/icons/gems/earring_01.tres\"\n11,\"Fortified Will\",\"WU11\",\"res://resources/icons/statues/statue_03.tres\"\n12,\"Inner Focus\",\"WU12\",\"res://resources/icons/tower_icons/polar_bear_cub.tres\"\n13,\"Bond of Unity\",\"WU13\",\"res://resources/icons/faces/woman_02.tres\"\n14,\"Foundation of Knowledge\",\"WU14\",\"res://resources/icons/faces/man_02.tres\"\n15,\"Deadly Strikes\",\"WU15\",\"res://resources/icons/swords/sword_swing_01.tres\"\n16,\"Fortune's Favor\",\"WU16\",\"res://resources/icons/rings/ring_02.tres\"\n17,\"Challenge Conqueror\",\"WU17\",\"res://resources/icons/misc/red_knight.tres\"\n18,\"Master of Destruction\",\"WU18\",\"res://resources/icons/helmets/crown_01.tres\"\n19,\"Advanced Optics\",\"WU19\",\"res://resources/icons/cannons/cannon_02.tres\"\n20,\"Elemental Overload\",\"WU20\",\"res://resources/icons/hud/gem_all_rarities.tres\"\n21,\"Pinnacle of Power\",\"WU21\",\"res://resources/icons/holy/altar.tres\"\n22,\"Advanced Synergy\",\"WU22\",\"res://resources/icons/electricity/electricity_yellow.tres\"\n23,\"The Path of Ascension\",\"WU23\",\"res://resources/icons/animals/wing.tres\"\n"
  },
  {
    "path": "data/wisdom_upgrades.csv.import",
    "content": "[remap]\n\nimporter=\"keep\"\n"
  },
  {
    "path": "export_presets.cfg",
    "content": "[preset.0]\n\nname=\"web\"\nplatform=\"Web\"\nrunnable=false\nadvanced_options=false\ndedicated_server=false\ncustom_features=\"\"\nexport_filter=\"exclude\"\nexport_files=PackedStringArray()\ninclude_filter=\"\"\nexclude_filter=\"\"\nexport_path=\"build/web/index.html\"\nencryption_include_filters=\"\"\nencryption_exclude_filters=\"\"\nencrypt_pck=false\nencrypt_directory=false\nscript_export_mode=2\n\n[preset.0.options]\n\ncustom_template/debug=\"\"\ncustom_template/release=\"\"\nvariant/extensions_support=true\nvariant/thread_support=false\nvram_texture_compression/for_desktop=true\nvram_texture_compression/for_mobile=false\nhtml/export_icon=true\nhtml/custom_html_shell=\"res://build/web/full-size.html\"\nhtml/head_include=\"\"\nhtml/canvas_resize_policy=2\nhtml/focus_canvas_on_start=true\nhtml/experimental_virtual_keyboard=false\nprogressive_web_app/enabled=false\nprogressive_web_app/ensure_cross_origin_isolation_headers=true\nprogressive_web_app/offline_page=\"\"\nprogressive_web_app/display=3\nprogressive_web_app/orientation=1\nprogressive_web_app/icon_144x144=\"\"\nprogressive_web_app/icon_180x180=\"\"\nprogressive_web_app/icon_512x512=\"\"\nprogressive_web_app/background_color=Color(0, 0, 0, 1)\n\n[preset.1]\n\nname=\"macos\"\nplatform=\"macOS\"\nrunnable=true\nadvanced_options=false\ndedicated_server=false\ncustom_features=\"\"\nexport_filter=\"exclude\"\nexport_files=PackedStringArray()\ninclude_filter=\"\"\nexclude_filter=\"\"\nexport_path=\"build/macos/YouTD2.zip\"\nencryption_include_filters=\"\"\nencryption_exclude_filters=\"\"\nencrypt_pck=false\nencrypt_directory=false\nscript_export_mode=2\n\n[preset.1.options]\n\nexport/distribution_type=1\nbinary_format/architecture=\"universal\"\ncustom_template/debug=\"\"\ncustom_template/release=\"\"\ndebug/export_console_wrapper=1\napplication/icon=\"res://assets/misc/icob_min.png\"\napplication/icon_interpolation=4\napplication/bundle_identifier=\"com.praytic.YouTD2\"\napplication/signature=\"\"\napplication/app_category=\"Strategy-games\"\napplication/short_version=\"1.0\"\napplication/version=\"1.0\"\napplication/copyright=\"\"\napplication/copyright_localized={}\napplication/min_macos_version=\"10.12\"\napplication/export_angle=0\ndisplay/high_res=true\napplication/additional_plist_content=\"\"\nxcode/platform_build=\"14C18\"\nxcode/sdk_version=\"13.1\"\nxcode/sdk_build=\"22C55\"\nxcode/sdk_name=\"macosx13.1\"\nxcode/xcode_version=\"1420\"\nxcode/xcode_build=\"14C18\"\ncodesign/codesign=1\ncodesign/installer_identity=\"\"\ncodesign/apple_team_id=\"\"\ncodesign/identity=\"\"\ncodesign/entitlements/custom_file=\"\"\ncodesign/entitlements/allow_jit_code_execution=false\ncodesign/entitlements/allow_unsigned_executable_memory=false\ncodesign/entitlements/allow_dyld_environment_variables=false\ncodesign/entitlements/disable_library_validation=true\ncodesign/entitlements/audio_input=false\ncodesign/entitlements/camera=false\ncodesign/entitlements/location=false\ncodesign/entitlements/address_book=false\ncodesign/entitlements/calendars=false\ncodesign/entitlements/photos_library=false\ncodesign/entitlements/apple_events=false\ncodesign/entitlements/debugging=false\ncodesign/entitlements/app_sandbox/enabled=false\ncodesign/entitlements/app_sandbox/network_server=false\ncodesign/entitlements/app_sandbox/network_client=false\ncodesign/entitlements/app_sandbox/device_usb=false\ncodesign/entitlements/app_sandbox/device_bluetooth=false\ncodesign/entitlements/app_sandbox/files_downloads=0\ncodesign/entitlements/app_sandbox/files_pictures=0\ncodesign/entitlements/app_sandbox/files_music=0\ncodesign/entitlements/app_sandbox/files_movies=0\ncodesign/entitlements/app_sandbox/files_user_selected=0\ncodesign/entitlements/app_sandbox/helper_executables=[]\ncodesign/custom_options=PackedStringArray()\nnotarization/notarization=0\nprivacy/microphone_usage_description=\"\"\nprivacy/microphone_usage_description_localized={}\nprivacy/camera_usage_description=\"\"\nprivacy/camera_usage_description_localized={}\nprivacy/location_usage_description=\"\"\nprivacy/location_usage_description_localized={}\nprivacy/address_book_usage_description=\"\"\nprivacy/address_book_usage_description_localized={}\nprivacy/calendar_usage_description=\"\"\nprivacy/calendar_usage_description_localized={}\nprivacy/photos_library_usage_description=\"\"\nprivacy/photos_library_usage_description_localized={}\nprivacy/desktop_folder_usage_description=\"\"\nprivacy/desktop_folder_usage_description_localized={}\nprivacy/documents_folder_usage_description=\"\"\nprivacy/documents_folder_usage_description_localized={}\nprivacy/downloads_folder_usage_description=\"\"\nprivacy/downloads_folder_usage_description_localized={}\nprivacy/network_volumes_usage_description=\"\"\nprivacy/network_volumes_usage_description_localized={}\nprivacy/removable_volumes_usage_description=\"\"\nprivacy/removable_volumes_usage_description_localized={}\nprivacy/tracking_enabled=false\nprivacy/tracking_domains=PackedStringArray()\nprivacy/collected_data/name/collected=false\nprivacy/collected_data/name/linked_to_user=false\nprivacy/collected_data/name/used_for_tracking=false\nprivacy/collected_data/name/collection_purposes=0\nprivacy/collected_data/email_address/collected=false\nprivacy/collected_data/email_address/linked_to_user=false\nprivacy/collected_data/email_address/used_for_tracking=false\nprivacy/collected_data/email_address/collection_purposes=0\nprivacy/collected_data/phone_number/collected=false\nprivacy/collected_data/phone_number/linked_to_user=false\nprivacy/collected_data/phone_number/used_for_tracking=false\nprivacy/collected_data/phone_number/collection_purposes=0\nprivacy/collected_data/physical_address/collected=false\nprivacy/collected_data/physical_address/linked_to_user=false\nprivacy/collected_data/physical_address/used_for_tracking=false\nprivacy/collected_data/physical_address/collection_purposes=0\nprivacy/collected_data/other_contact_info/collected=false\nprivacy/collected_data/other_contact_info/linked_to_user=false\nprivacy/collected_data/other_contact_info/used_for_tracking=false\nprivacy/collected_data/other_contact_info/collection_purposes=0\nprivacy/collected_data/health/collected=false\nprivacy/collected_data/health/linked_to_user=false\nprivacy/collected_data/health/used_for_tracking=false\nprivacy/collected_data/health/collection_purposes=0\nprivacy/collected_data/fitness/collected=false\nprivacy/collected_data/fitness/linked_to_user=false\nprivacy/collected_data/fitness/used_for_tracking=false\nprivacy/collected_data/fitness/collection_purposes=0\nprivacy/collected_data/payment_info/collected=false\nprivacy/collected_data/payment_info/linked_to_user=false\nprivacy/collected_data/payment_info/used_for_tracking=false\nprivacy/collected_data/payment_info/collection_purposes=0\nprivacy/collected_data/credit_info/collected=false\nprivacy/collected_data/credit_info/linked_to_user=false\nprivacy/collected_data/credit_info/used_for_tracking=false\nprivacy/collected_data/credit_info/collection_purposes=0\nprivacy/collected_data/other_financial_info/collected=false\nprivacy/collected_data/other_financial_info/linked_to_user=false\nprivacy/collected_data/other_financial_info/used_for_tracking=false\nprivacy/collected_data/other_financial_info/collection_purposes=0\nprivacy/collected_data/precise_location/collected=false\nprivacy/collected_data/precise_location/linked_to_user=false\nprivacy/collected_data/precise_location/used_for_tracking=false\nprivacy/collected_data/precise_location/collection_purposes=0\nprivacy/collected_data/coarse_location/collected=false\nprivacy/collected_data/coarse_location/linked_to_user=false\nprivacy/collected_data/coarse_location/used_for_tracking=false\nprivacy/collected_data/coarse_location/collection_purposes=0\nprivacy/collected_data/sensitive_info/collected=false\nprivacy/collected_data/sensitive_info/linked_to_user=false\nprivacy/collected_data/sensitive_info/used_for_tracking=false\nprivacy/collected_data/sensitive_info/collection_purposes=0\nprivacy/collected_data/contacts/collected=false\nprivacy/collected_data/contacts/linked_to_user=false\nprivacy/collected_data/contacts/used_for_tracking=false\nprivacy/collected_data/contacts/collection_purposes=0\nprivacy/collected_data/emails_or_text_messages/collected=false\nprivacy/collected_data/emails_or_text_messages/linked_to_user=false\nprivacy/collected_data/emails_or_text_messages/used_for_tracking=false\nprivacy/collected_data/emails_or_text_messages/collection_purposes=0\nprivacy/collected_data/photos_or_videos/collected=false\nprivacy/collected_data/photos_or_videos/linked_to_user=false\nprivacy/collected_data/photos_or_videos/used_for_tracking=false\nprivacy/collected_data/photos_or_videos/collection_purposes=0\nprivacy/collected_data/audio_data/collected=false\nprivacy/collected_data/audio_data/linked_to_user=false\nprivacy/collected_data/audio_data/used_for_tracking=false\nprivacy/collected_data/audio_data/collection_purposes=0\nprivacy/collected_data/gameplay_content/collected=false\nprivacy/collected_data/gameplay_content/linked_to_user=false\nprivacy/collected_data/gameplay_content/used_for_tracking=false\nprivacy/collected_data/gameplay_content/collection_purposes=0\nprivacy/collected_data/customer_support/collected=false\nprivacy/collected_data/customer_support/linked_to_user=false\nprivacy/collected_data/customer_support/used_for_tracking=false\nprivacy/collected_data/customer_support/collection_purposes=0\nprivacy/collected_data/other_user_content/collected=false\nprivacy/collected_data/other_user_content/linked_to_user=false\nprivacy/collected_data/other_user_content/used_for_tracking=false\nprivacy/collected_data/other_user_content/collection_purposes=0\nprivacy/collected_data/browsing_history/collected=false\nprivacy/collected_data/browsing_history/linked_to_user=false\nprivacy/collected_data/browsing_history/used_for_tracking=false\nprivacy/collected_data/browsing_history/collection_purposes=0\nprivacy/collected_data/search_hhistory/collected=false\nprivacy/collected_data/search_hhistory/linked_to_user=false\nprivacy/collected_data/search_hhistory/used_for_tracking=false\nprivacy/collected_data/search_hhistory/collection_purposes=0\nprivacy/collected_data/user_id/collected=false\nprivacy/collected_data/user_id/linked_to_user=false\nprivacy/collected_data/user_id/used_for_tracking=false\nprivacy/collected_data/user_id/collection_purposes=0\nprivacy/collected_data/device_id/collected=false\nprivacy/collected_data/device_id/linked_to_user=false\nprivacy/collected_data/device_id/used_for_tracking=false\nprivacy/collected_data/device_id/collection_purposes=0\nprivacy/collected_data/purchase_history/collected=false\nprivacy/collected_data/purchase_history/linked_to_user=false\nprivacy/collected_data/purchase_history/used_for_tracking=false\nprivacy/collected_data/purchase_history/collection_purposes=0\nprivacy/collected_data/product_interaction/collected=false\nprivacy/collected_data/product_interaction/linked_to_user=false\nprivacy/collected_data/product_interaction/used_for_tracking=false\nprivacy/collected_data/product_interaction/collection_purposes=0\nprivacy/collected_data/advertising_data/collected=false\nprivacy/collected_data/advertising_data/linked_to_user=false\nprivacy/collected_data/advertising_data/used_for_tracking=false\nprivacy/collected_data/advertising_data/collection_purposes=0\nprivacy/collected_data/other_usage_data/collected=false\nprivacy/collected_data/other_usage_data/linked_to_user=false\nprivacy/collected_data/other_usage_data/used_for_tracking=false\nprivacy/collected_data/other_usage_data/collection_purposes=0\nprivacy/collected_data/crash_data/collected=false\nprivacy/collected_data/crash_data/linked_to_user=false\nprivacy/collected_data/crash_data/used_for_tracking=false\nprivacy/collected_data/crash_data/collection_purposes=0\nprivacy/collected_data/performance_data/collected=false\nprivacy/collected_data/performance_data/linked_to_user=false\nprivacy/collected_data/performance_data/used_for_tracking=false\nprivacy/collected_data/performance_data/collection_purposes=0\nprivacy/collected_data/other_diagnostic_data/collected=false\nprivacy/collected_data/other_diagnostic_data/linked_to_user=false\nprivacy/collected_data/other_diagnostic_data/used_for_tracking=false\nprivacy/collected_data/other_diagnostic_data/collection_purposes=0\nprivacy/collected_data/environment_scanning/collected=false\nprivacy/collected_data/environment_scanning/linked_to_user=false\nprivacy/collected_data/environment_scanning/used_for_tracking=false\nprivacy/collected_data/environment_scanning/collection_purposes=0\nprivacy/collected_data/hands/collected=false\nprivacy/collected_data/hands/linked_to_user=false\nprivacy/collected_data/hands/used_for_tracking=false\nprivacy/collected_data/hands/collection_purposes=0\nprivacy/collected_data/head/collected=false\nprivacy/collected_data/head/linked_to_user=false\nprivacy/collected_data/head/used_for_tracking=false\nprivacy/collected_data/head/collection_purposes=0\nprivacy/collected_data/other_data_types/collected=false\nprivacy/collected_data/other_data_types/linked_to_user=false\nprivacy/collected_data/other_data_types/used_for_tracking=false\nprivacy/collected_data/other_data_types/collection_purposes=0\nssh_remote_deploy/enabled=false\nssh_remote_deploy/host=\"user@host_ip\"\nssh_remote_deploy/port=\"22\"\nssh_remote_deploy/extra_args_ssh=\"\"\nssh_remote_deploy/extra_args_scp=\"\"\nssh_remote_deploy/run_script=\"#!/usr/bin/env bash\nunzip -o -q \\\"{temp_dir}/{archive_name}\\\" -d \\\"{temp_dir}\\\"\nopen \\\"{temp_dir}/{exe_name}.app\\\" --args {cmd_args}\"\nssh_remote_deploy/cleanup_script=\"#!/usr/bin/env bash\nkill $(pgrep -x -f \\\"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\\\")\nrm -rf \\\"{temp_dir}\\\"\"\ndebug/export_console_script=1\nnotarization/apple_team_id=\"\"\n\n[preset.2]\n\nname=\"windows\"\nplatform=\"Windows Desktop\"\nrunnable=true\nadvanced_options=false\ndedicated_server=false\ncustom_features=\"\"\nexport_filter=\"exclude\"\nexport_files=PackedStringArray()\ninclude_filter=\"\"\nexclude_filter=\"\"\nexport_path=\"build/windows/YouTD2.zip\"\nencryption_include_filters=\"\"\nencryption_exclude_filters=\"\"\nencrypt_pck=false\nencrypt_directory=false\nscript_export_mode=2\n\n[preset.2.options]\n\ncustom_template/debug=\"\"\ncustom_template/release=\"\"\ndebug/export_console_wrapper=1\nbinary_format/embed_pck=false\ntexture_format/s3tc_bptc=true\ntexture_format/etc2_astc=false\nbinary_format/architecture=\"x86_64\"\ncodesign/enable=false\ncodesign/timestamp=true\ncodesign/timestamp_server_url=\"\"\ncodesign/digest_algorithm=1\ncodesign/description=\"\"\ncodesign/custom_options=PackedStringArray()\napplication/modify_resources=true\napplication/icon=\"res://assets/misc/icob_min.ico\"\napplication/console_wrapper_icon=\"res://assets/misc/icob_min.ico\"\napplication/icon_interpolation=4\napplication/file_version=\"\"\napplication/product_version=\"\"\napplication/company_name=\"Icob Games\"\napplication/product_name=\"You TD 2\"\napplication/file_description=\"\"\napplication/copyright=\"\"\napplication/trademarks=\"\"\napplication/export_angle=0\napplication/export_d3d12=0\napplication/d3d12_agility_sdk_multiarch=true\nssh_remote_deploy/enabled=false\nssh_remote_deploy/host=\"user@host_ip\"\nssh_remote_deploy/port=\"22\"\nssh_remote_deploy/extra_args_ssh=\"\"\nssh_remote_deploy/extra_args_scp=\"\"\nssh_remote_deploy/run_script=\"Expand-Archive -LiteralPath '{temp_dir}\\\\{archive_name}' -DestinationPath '{temp_dir}'\n$action = New-ScheduledTaskAction -Execute '{temp_dir}\\\\{exe_name}' -Argument '{cmd_args}'\n$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n$settings = New-ScheduledTaskSettingsSet\n$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\nRegister-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\nStart-ScheduledTask -TaskName godot_remote_debug\nwhile (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }\nUnregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\"\nssh_remote_deploy/cleanup_script=\"Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue\nUnregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\nRemove-Item -Recurse -Force '{temp_dir}'\"\ntexture_format/bptc=true\ntexture_format/s3tc=true\ntexture_format/etc=false\ntexture_format/etc2=false\ndebug/export_console_script=1\n\n[preset.3]\n\nname=\"linux\"\nplatform=\"Linux\"\nrunnable=true\nadvanced_options=false\ndedicated_server=false\ncustom_features=\"\"\nexport_filter=\"exclude\"\nexport_files=PackedStringArray()\ninclude_filter=\"\"\nexclude_filter=\"\"\nexport_path=\"build/linux/YouTD2.zip\"\nencryption_include_filters=\"\"\nencryption_exclude_filters=\"\"\nencrypt_pck=false\nencrypt_directory=false\nscript_export_mode=2\n\n[preset.3.options]\n\ncustom_template/debug=\"\"\ncustom_template/release=\"\"\ndebug/export_console_wrapper=1\nbinary_format/embed_pck=false\ntexture_format/s3tc_bptc=true\ntexture_format/etc2_astc=false\nbinary_format/architecture=\"x86_64\"\nssh_remote_deploy/enabled=false\nssh_remote_deploy/host=\"user@host_ip\"\nssh_remote_deploy/port=\"22\"\nssh_remote_deploy/extra_args_ssh=\"\"\nssh_remote_deploy/extra_args_scp=\"\"\nssh_remote_deploy/run_script=\"#!/usr/bin/env bash\nexport DISPLAY=:0\nunzip -o -q \\\"{temp_dir}/{archive_name}\\\" -d \\\"{temp_dir}\\\"\n\\\"{temp_dir}/{exe_name}\\\" {cmd_args}\"\nssh_remote_deploy/cleanup_script=\"#!/usr/bin/env bash\nkill $(pgrep -x -f \\\"{temp_dir}/{exe_name} {cmd_args}\\\")\nrm -rf \\\"{temp_dir}\\\"\"\ntexture_format/bptc=true\ntexture_format/s3tc=true\ntexture_format/etc=false\ntexture_format/etc2=false\ndebug/export_console_script=1\n\n[preset.4]\n\nname=\"web for remote debug\"\nplatform=\"Web\"\nrunnable=true\nadvanced_options=false\ndedicated_server=false\ncustom_features=\"\"\nexport_filter=\"exclude\"\nexport_files=PackedStringArray()\ninclude_filter=\"\"\nexclude_filter=\"\"\nexport_path=\"\"\nencryption_include_filters=\"\"\nencryption_exclude_filters=\"\"\nencrypt_pck=false\nencrypt_directory=false\nscript_export_mode=2\n\n[preset.4.options]\n\ncustom_template/debug=\"\"\ncustom_template/release=\"\"\nvariant/extensions_support=false\nvariant/thread_support=false\nvram_texture_compression/for_desktop=true\nvram_texture_compression/for_mobile=false\nhtml/export_icon=true\nhtml/custom_html_shell=\"\"\nhtml/head_include=\"\"\nhtml/canvas_resize_policy=2\nhtml/focus_canvas_on_start=true\nhtml/experimental_virtual_keyboard=false\nprogressive_web_app/enabled=false\nprogressive_web_app/ensure_cross_origin_isolation_headers=true\nprogressive_web_app/offline_page=\"\"\nprogressive_web_app/display=1\nprogressive_web_app/orientation=0\nprogressive_web_app/icon_144x144=\"\"\nprogressive_web_app/icon_180x180=\"\"\nprogressive_web_app/icon_512x512=\"\"\nprogressive_web_app/background_color=Color(0, 0, 0, 1)\n"
  },
  {
    "path": "project.godot",
    "content": "; Engine configuration file.\n; It's best edited using the editor UI and not directly,\n; since the parameters that go here are not all obvious.\n;\n; Format:\n;   [section] ; section goes between []\n;   param=value ; assign values to parameters\n\nconfig_version=5\n\n[application]\n\nconfig/name=\"YouTD 2\"\nconfig/description=\"Discover the standalone sequel to the well-liked WC3 custom tower defense map, YouTD. This follow-up is thoughtfully crafted by the community, continuing the legacy of engaging tower defense gameplay.\"\nconfig/version=\"vDEV\"\nrun/main_scene=\"res://src/ui/title_screen/title_screen.tscn\"\nconfig/features=PackedStringArray(\"4.3\")\nboot_splash/bg_color=Color(0.141176, 0.141176, 0.141176, 1)\nboot_splash/image=\"res://assets/misc/icob_ultra_wide.png\"\nconfig/icon=\"res://assets/misc/icob_min.png\"\nconfig/windows_native_icon=\"res://assets/misc/icob_min.ico\"\nconfig/visible_spell_dummys=false\nconfig/dev_controls=false\nconfig/preload_all_towers_on_startup=false\nconfig/test_item_list=[]\nconfig/cheat_gold=0\nconfig/cheat_tomes=0\nconfig/cheat_food_cap=0\nconfig/always_drop_items=false\nconfig/ignore_tower_requirements=false\nconfig/enable_zoom_by_touchpad=true\nconfig/enable_zoom_by_mousewheel=true\nconfig/show_position_info_label=false\nconfig/override_creep_health=0\nconfig/override_creep_size=\"\"\nconfig/override_creep_armor=\"\"\nconfig/override_creep_race=\"\"\nconfig/override_wave_specials=[]\nconfig/print_wave_info=false\nconfig/allow_transform_in_build_mode=false\nconfig/load_only_orc_scenes=true\nconfig/run_test_towers_tool=false\nconfig/run_auto_playtest_bot=false\nconfig/run_test_items_tool=false\nconfig/run_test_horadric_tool=false\nconfig/run_test_tower_sprite_size=false\nconfig/run_test_item_drop_chances=false\nconfig/unlimited_portal_lives=false\nconfig/show_hidden_buffs=false\nconfig/update_ticks_per_physics_tick=1\nconfig/enable_dev_commands=false\n\n[autoload]\n\nGlobals=\"*res://src/singletons/globals.gd\"\nPreloads=\"*res://src/singletons/preloads.gd\"\nElapsedTimer=\"*res://src/singletons/elapsed_timer.gd\"\nUtils=\"*res://src/singletons/utils.gd\"\nEffect=\"*res://src/singletons/effect.gd\"\nConfig=\"*res://src/singletons/config.gd\"\nTowerProperties=\"*res://src/singletons/properties/tower_properties.gd\"\nItemProperties=\"*res://src/singletons/properties/item_properties.gd\"\nEventBus=\"*res://src/singletons/event_bus.gd\"\nSFX=\"*res://src/singletons/sfx.gd\"\nMessages=\"*res://src/singletons/messages.gd\"\nWaveSpecial=\"*res://src/singletons/wave_special.gd\"\nItemDropCalc=\"*res://src/singletons/item_drop_calc.gd\"\nExperience=\"*res://src/singletons/experience.gd\"\nRichTexts=\"*res://src/singletons/rich_texts.gd\"\nCreepProperties=\"*res://src/singletons/unit_icons.gd\"\nTowerDistribution=\"*res://src/singletons/tower_distribution.gd\"\nSettings=\"*res://src/singletons/settings.gd\"\nCombatLog=\"*res://src/singletons/combat_log.gd\"\nBuilderProperties=\"*res://src/singletons/properties/builder_properties.gd\"\nRecipeProperties=\"*res://src/singletons/properties/recipe_properties.gd\"\nUnitIcons=\"*res://src/singletons/unit_icons.gd\"\nTowerSprites=\"*res://src/singletons/tower_sprites.gd\"\nPlayerManager=\"*res://src/singletons/player_manager.gd\"\nGroupManager=\"*res://src/singletons/group_manager.gd\"\nPlayerExperience=\"*res://src/singletons/player_experience.gd\"\nExperiencePassword=\"*res://src/singletons/experience_password.gd\"\nWisdomUpgradeProperties=\"*res://src/singletons/properties/wisdom_upgrade_properties.gd\"\nVectorUtils=\"*res://src/singletons/vector_utils.gd\"\nTutorialProperties=\"*res://src/singletons/properties/tutorial_properties.gd\"\nButtonSounds=\"*res://src/singletons/button_sounds.gd\"\nSfxPaths=\"*res://src/singletons/sfx_paths.gd\"\nSecrets=\"*res://src/singletons/secrets.gd\"\nNakama=\"*res://addons/com.heroiclabs.nakama/Nakama.gd\"\nNakamaConnection=\"*res://src/singletons/nakama_connection.gd\"\nOnlineMatch=\"*res://addons/nakama-webrtc/OnlineMatch.gd\"\nSanitizeText=\"*res://src/singletons/sanitize_text.gd\"\nMissionProperties=\"*res://src/singletons/properties/mission_properties.gd\"\nMissionStatus=\"*res://src/singletons/mission_status.gd\"\nMissionTracking=\"*res://src/singletons/mission_tracking.gd\"\nAutocastProperties=\"*res://src/singletons/properties/autocast_properties.gd\"\nAuraProperties=\"*res://src/singletons/properties/aura_properties.gd\"\nAbilityProperties=\"*res://src/singletons/properties/ability_properties.gd\"\nWaveSpecialProperties=\"*res://src/singletons/properties/wave_special_properties.gd\"\n\n[debug]\n\nsettings/stdout/print_fps=true\nsettings/stdout/verbose_stdout=true\ngdscript/warnings/unused_signal=0\ngdscript/warnings/return_value_discarded=false\ngdscript/warnings/assert_always_false=0\ngdscript/warnings/integer_division=0\n\n[display]\n\nwindow/size/viewport_width=2560\nwindow/size/viewport_height=1440\nwindow/size/mode=3\nwindow/stretch/mode=\"canvas_items\"\nwindow/stretch/aspect=\"expand\"\n\n[gui]\n\ntheme/custom=\"res://resources/theme/wc3_theme.tres\"\ntheme/custom_font=\"res://assets/fonts/Friz Quadrata Std Medium.otf\"\ncommon/drop_mouse_on_gui_input_disabled=true\n\n[input]\n\nui_left={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":4194319,\"physical_keycode\":0,\"key_label\":0,\"unicode\":4194319,\"location\":0,\"echo\":false,\"script\":null)\n, Object(InputEventJoypadButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"button_index\":13,\"pressure\":0.0,\"pressed\":false,\"script\":null)\n, Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":65,\"key_label\":0,\"unicode\":97,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\nui_right={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":4194321,\"physical_keycode\":0,\"key_label\":0,\"unicode\":4194321,\"location\":0,\"echo\":false,\"script\":null)\n, Object(InputEventJoypadButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"button_index\":14,\"pressure\":0.0,\"pressed\":false,\"script\":null)\n, Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":68,\"key_label\":0,\"unicode\":100,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\nui_up={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":4194320,\"physical_keycode\":0,\"key_label\":0,\"unicode\":4194320,\"location\":0,\"echo\":false,\"script\":null)\n, Object(InputEventJoypadButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"button_index\":11,\"pressure\":0.0,\"pressed\":false,\"script\":null)\n, Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":87,\"key_label\":0,\"unicode\":119,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\nui_down={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":4194322,\"physical_keycode\":0,\"key_label\":0,\"unicode\":4194322,\"location\":0,\"echo\":false,\"script\":null)\n, Object(InputEventJoypadButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":0,\"button_index\":12,\"pressure\":0.0,\"pressed\":false,\"script\":null)\n, Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":83,\"key_label\":0,\"unicode\":115,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\nleft_click={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventMouseButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"button_mask\":0,\"position\":Vector2(0, 0),\"global_position\":Vector2(0, 0),\"factor\":1.0,\"button_index\":1,\"canceled\":false,\"pressed\":false,\"double_click\":false,\"script\":null)\n]\n}\nright_click={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventMouseButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"button_mask\":0,\"position\":Vector2(0, 0),\"global_position\":Vector2(0, 0),\"factor\":1.0,\"button_index\":2,\"canceled\":false,\"pressed\":false,\"double_click\":false,\"script\":null)\n]\n}\nshift={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":4194325,\"key_label\":0,\"unicode\":0,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\npause={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":4194341,\"key_label\":0,\"unicode\":0,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\nmiddle_click={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventMouseButton,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"button_mask\":0,\"position\":Vector2(0, 0),\"global_position\":Vector2(0, 0),\"factor\":1.0,\"button_index\":3,\"canceled\":false,\"pressed\":false,\"double_click\":false,\"script\":null)\n]\n}\nforward_slash={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":47,\"key_label\":0,\"unicode\":47,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\nctrl={\n\"deadzone\": 0.5,\n\"events\": [Object(InputEventKey,\"resource_local_to_scene\":false,\"resource_name\":\"\",\"device\":-1,\"window_id\":0,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"pressed\":false,\"keycode\":0,\"physical_keycode\":4194326,\"key_label\":0,\"unicode\":0,\"location\":0,\"echo\":false,\"script\":null)\n]\n}\n\n[internationalization]\n\nlocale/translations=PackedStringArray(\"res://assets/texts/texts.zh.translation\", \"res://assets/texts/texts.en.translation\", \"res://assets/texts/texts.it.translation\")\n\n[physics]\n\ncommon/physics_ticks_per_second=30\ncommon/enable_pause_aware_picking=true\n\n[rendering]\n\ntextures/vram_compression/import_etc2_astc=true\nvram_compression/import_etc=true\nquality/filters/msaa=1\n"
  },
  {
    "path": "rclone-filter",
    "content": "# Archives\n+ *.7z\n+ *.br\n+ *.gz\n+ *.tar\n+ *.zip\n\n# Documents\n+ *.pdf\n\n# Images\n+ *.gif\n+ *.ico\n+ *.jpg\n+ *.png\n+ *.psd\n+ *.webp\n\n# Fonts\n+ *.woff2\n+ *.otf\n\n# Audio\n+ *.mp3\n+ *.wav\n+ *.ogg\n\n# Other\n+ *.exe\n+ /secrets/secrets.csv\n+ /secrets/badwords.csv\n\n# Exclude everything else\n- *"
  },
  {
    "path": "resources/README.md",
    "content": "This folder contains subclasses of Godot's Resource class, such as textures, UI theme files and shaders.\n"
  },
  {
    "path": "resources/button_groups/element_filter_button_group.tres",
    "content": "[gd_resource type=\"ButtonGroup\" format=3 uid=\"uid://btb8xdpulas1s\"]\n\n[resource]\nresource_local_to_scene = false\n"
  },
  {
    "path": "resources/button_groups/interface_size_setting_button_group.tres",
    "content": "[gd_resource type=\"ButtonGroup\" format=3 uid=\"uid://di3e75guncq3c\"]\n\n[resource]\nresource_local_to_scene = false\n"
  },
  {
    "path": "resources/button_groups/item_type_filter_button_group.tres",
    "content": "[gd_resource type=\"ButtonGroup\" format=3 uid=\"uid://cycas5vk7h2lw\"]\n\n[resource]\nresource_local_to_scene = false\nallow_unpress = true\n"
  },
  {
    "path": "resources/button_groups/menu_cards_button_group.tres",
    "content": "[gd_resource type=\"ButtonGroup\" format=3 uid=\"uid://deklccjgbh0k0\"]\n\n[resource]\nresource_local_to_scene = false\nallow_unpress = true\n"
  },
  {
    "path": "resources/button_groups/right_panel_button_group.tres",
    "content": "[gd_resource type=\"ButtonGroup\" format=3 uid=\"uid://ce5xw83da2d6c\"]\n\n[resource]\nresource_local_to_scene = false\nallow_unpress = true\n"
  },
  {
    "path": "resources/button_groups/speed_button_group.tres",
    "content": "[gd_resource type=\"ButtonGroup\" format=3 uid=\"uid://5mj7ntug0txa\"]\n\n[resource]\nresource_local_to_scene = false\n"
  },
  {
    "path": "resources/icons/amulets/amulet_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cs6dhvb4piglr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4f2vpcxem3iv\" path=\"res://assets/icons/amulets.png\" id=\"1_o36hf\"]\n\n[resource]\natlas = ExtResource(\"1_o36hf\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/amulets/amulet_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://7ablekpfsvep\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4f2vpcxem3iv\" path=\"res://assets/icons/amulets.png\" id=\"1_4otgr\"]\n\n[resource]\natlas = ExtResource(\"1_4otgr\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/amulets/amulet_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://sk8fy4706sxo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4f2vpcxem3iv\" path=\"res://assets/icons/amulets.png\" id=\"1_5iukx\"]\n\n[resource]\natlas = ExtResource(\"1_5iukx\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/amulets/amulet_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://g8y1k2q2n1kc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4f2vpcxem3iv\" path=\"res://assets/icons/amulets.png\" id=\"1_rjhmj\"]\n\n[resource]\natlas = ExtResource(\"1_rjhmj\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/bat_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://baie4iggobgps\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_2thvh\"]\n\n[resource]\natlas = ExtResource(\"1_2thvh\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/bat_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://curxyn2mcvmar\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_oigbf\"]\n\n[resource]\natlas = ExtResource(\"1_oigbf\")\nregion = Rect2(128, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/bat_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://buqqushsjicbo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_gcx8a\"]\n\n[resource]\natlas = ExtResource(\"1_gcx8a\")\nregion = Rect2(256, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/cow.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://hhjtvj347qq3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_w2j3y\"]\n\n[resource]\natlas = ExtResource(\"1_w2j3y\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/dragon_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://csf0epg8rltp8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_neaok\"]\n\n[resource]\natlas = ExtResource(\"1_neaok\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/dragon_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://j1ssq5nci44k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_1to1k\"]\n\n[resource]\natlas = ExtResource(\"1_1to1k\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/dragon_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpp3cwy5ftpv2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_rjx3y\"]\n\n[resource]\natlas = ExtResource(\"1_rjx3y\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/dragon_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c6ugirn2ecw78\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_2jhmn\"]\n\n[resource]\natlas = ExtResource(\"1_2jhmn\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/dragon_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c2injyjnlp6xm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_pmbp8\"]\n\n[resource]\natlas = ExtResource(\"1_pmbp8\")\nregion = Rect2(0, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/fish_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1jvyvnoon2qa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_2y5fk\"]\n\n[resource]\natlas = ExtResource(\"1_2y5fk\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/fish_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bc71ygo7c38gj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_om06f\"]\n\n[resource]\natlas = ExtResource(\"1_om06f\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/fish_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b6hbdg8ontmno\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_vgaie\"]\n\n[resource]\natlas = ExtResource(\"1_vgaie\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/fish_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c5pordi636mm6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_hm8ub\"]\n\n[resource]\natlas = ExtResource(\"1_hm8ub\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/mech_toad.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://doxjkqwny8n7g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_jupsv\"]\n\n[resource]\natlas = ExtResource(\"1_jupsv\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/piglet_warrior.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b3rp6wxwm8bvk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_nmrxu\"]\n\n[resource]\natlas = ExtResource(\"1_nmrxu\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/rabbit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cttcnd43bkbg8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_kiw6v\"]\n\n[resource]\natlas = ExtResource(\"1_kiw6v\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/rooster_warrior.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ytnd4b3x40wp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_sgw1r\"]\n\n[resource]\natlas = ExtResource(\"1_sgw1r\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/spider_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://be55ni7ps4aqk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_4fc2m\"]\n\n[resource]\natlas = ExtResource(\"1_4fc2m\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/spider_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://du3vlwtqc3nr2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_o0egs\"]\n\n[resource]\natlas = ExtResource(\"1_o0egs\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/spider_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2d5k1qmwkb3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_4n3i6\"]\n\n[resource]\natlas = ExtResource(\"1_4n3i6\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/animals/wing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dw8xrlk04bg5n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqw2twgahvt7e\" path=\"res://assets/icons/animals.png\" id=\"1_hc83v\"]\n\n[resource]\natlas = ExtResource(\"1_hc83v\")\nregion = Rect2(384, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/chest_plate.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dn8hfrxvhnd7c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_1brn0\"]\n\n[resource]\natlas = ExtResource(\"1_1brn0\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/chest_plate_with_spike.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://kgwvmtva6si5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_p1b4b\"]\n\n[resource]\natlas = ExtResource(\"1_p1b4b\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/coat.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bweaskho255k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_87gas\"]\n\n[resource]\natlas = ExtResource(\"1_87gas\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/lightning_boot.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://uny6i23in4d4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_rouv7\"]\n\n[resource]\natlas = ExtResource(\"1_rouv7\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/vest_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bdngkhlcbdb0h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_2fo2n\"]\n\n[resource]\natlas = ExtResource(\"1_2fo2n\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/vest_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cquligsun5ke2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_hnkmm\"]\n\n[resource]\natlas = ExtResource(\"1_hnkmm\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/vest_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://qqyelndtmxf2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_cbhys\"]\n\n[resource]\natlas = ExtResource(\"1_cbhys\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/armor/vest_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bbksko70drk7l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jy45uwdi1vwj\" path=\"res://assets/icons/armor.png\" id=\"1_hv82x\"]\n\n[resource]\natlas = ExtResource(\"1_hv82x\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/hammer_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c7dsg070ypy0a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_gqbmi\"]\n\n[resource]\natlas = ExtResource(\"1_gqbmi\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/hammer_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://da41fek2ljoy4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_wxu7u\"]\n\n[resource]\natlas = ExtResource(\"1_wxu7u\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/hammer_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://x75w3uachfh0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_irfr5\"]\n\n[resource]\natlas = ExtResource(\"1_irfr5\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/hammer_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c3ybnrpm64vb5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_1v46j\"]\n\n[resource]\natlas = ExtResource(\"1_1v46j\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/wood_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dedll0pylt2so\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_k6thh\"]\n\n[resource]\natlas = ExtResource(\"1_k6thh\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/wood_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b681qvhlcdfwf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_6wulr\"]\n\n[resource]\natlas = ExtResource(\"1_6wulr\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/wood_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://r7dnpeimpnd8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_jfb7h\"]\n\n[resource]\natlas = ExtResource(\"1_jfb7h\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/blunt_weapons/wood_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dqbgarnns1an6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxmouedtoclok\" path=\"res://assets/icons/blunt_weapons.png\" id=\"1_utudx\"]\n\n[resource]\natlas = ExtResource(\"1_utudx\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c7k7fl31ukx7n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_lmes1\"]\n\n[resource]\natlas = ExtResource(\"1_lmes1\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d22nylor3e0b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_byc4f\"]\n\n[resource]\natlas = ExtResource(\"1_byc4f\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://due8hxsfp2drl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_r6kxp\"]\n\n[resource]\natlas = ExtResource(\"1_r6kxp\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://brq1e77o3pa2l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_6gnmd\"]\n\n[resource]\natlas = ExtResource(\"1_6gnmd\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bn283ata12eqo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_82hym\"]\n\n[resource]\natlas = ExtResource(\"1_82hym\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dskbmgv22ux5y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_hpdra\"]\n\n[resource]\natlas = ExtResource(\"1_hpdra\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cp7u7xj2nldyd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_6uclv\"]\n\n[resource]\natlas = ExtResource(\"1_6uclv\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://2rr782obx4jt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_dfsmq\"]\n\n[resource]\natlas = ExtResource(\"1_dfsmq\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_09.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bghy0erh7vlrf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_ie526\"]\n\n[resource]\natlas = ExtResource(\"1_ie526\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_10.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://djyun8lf5bqgl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_3a7iv\"]\n\n[resource]\natlas = ExtResource(\"1_3a7iv\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/book_11.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c8oxj3ab80js4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_daejt\"]\n\n[resource]\natlas = ExtResource(\"1_daejt\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/note_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dpa82w6smbwhk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_cfxe0\"]\n\n[resource]\natlas = ExtResource(\"1_cfxe0\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/note_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b32jt73y7abky\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_v03uu\"]\n\n[resource]\natlas = ExtResource(\"1_v03uu\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/note_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dm6d50q84td75\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_5hwst\"]\n\n[resource]\natlas = ExtResource(\"1_5hwst\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/books/note_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dvjw1x33ppbqb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://nr8ilug8etwa\" path=\"res://assets/icons/books.png\" id=\"1_6khqr\"]\n\n[resource]\natlas = ExtResource(\"1_6khqr\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/arrow_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dv62he2k4ylmt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_h84x1\"]\n\n[resource]\natlas = ExtResource(\"1_h84x1\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/arrow_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bkla5dfrcmpm7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_cbxto\"]\n\n[resource]\natlas = ExtResource(\"1_cbxto\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/bow_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b8xosijjqmtjl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_wfakt\"]\n\n[resource]\natlas = ExtResource(\"1_wfakt\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/bow_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dj8scl3invlfr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_0mhhn\"]\n\n[resource]\natlas = ExtResource(\"1_0mhhn\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/bow_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpee1sxiyiv8l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_w4ddk\"]\n\n[resource]\natlas = ExtResource(\"1_w4ddk\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/bow_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dqk8snb541guw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_ewr0l\"]\n\n[resource]\natlas = ExtResource(\"1_ewr0l\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/bow_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dv36ds36o7bc8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_mky0v\"]\n\n[resource]\natlas = ExtResource(\"1_mky0v\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/bows/bow_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://5egp56m7o7hx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dxiunk1cedalv\" path=\"res://assets/icons/bows.png\" id=\"1_ek17d\"]\n\n[resource]\natlas = ExtResource(\"1_ek17d\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ul1efovrgbil\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_uuj4c\"]\n\n[resource]\natlas = ExtResource(\"1_uuj4c\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dtxd7kiil8d4e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_cj4ko\"]\n\n[resource]\natlas = ExtResource(\"1_cj4ko\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bbqlv6n7h1n13\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_skfou\"]\n\n[resource]\natlas = ExtResource(\"1_skfou\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dps84ugqypbws\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_8pbo7\"]\n\n[resource]\natlas = ExtResource(\"1_8pbo7\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbdg5g5mbwjmv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_tqoir\"]\n\n[resource]\natlas = ExtResource(\"1_tqoir\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://46goxlidgl2x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_fopas\"]\n\n[resource]\natlas = ExtResource(\"1_fopas\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cqcab3nxjycqu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_wvsaq\"]\n\n[resource]\natlas = ExtResource(\"1_wvsaq\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/cannon_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmrbdtx6uc5s0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_p0leq\"]\n\n[resource]\natlas = ExtResource(\"1_p0leq\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/gun_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://da01pwhuqkm44\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_6m3wk\"]\n\n[resource]\natlas = ExtResource(\"1_6m3wk\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/cannons/gun_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxaxw3ehwlnqs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hogt7wr0i6l6\" path=\"res://assets/icons/cannons.png\" id=\"1_s5k2g\"]\n\n[resource]\natlas = ExtResource(\"1_s5k2g\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/clubs/club_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxx3g338k3y1s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cd0wrsaa54yr8\" path=\"res://assets/icons/clubs.png\" id=\"1_cwd7f\"]\n\n[resource]\natlas = ExtResource(\"1_cwd7f\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/clubs/club_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://das667e1aooki\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cd0wrsaa54yr8\" path=\"res://assets/icons/clubs.png\" id=\"1_l36ww\"]\n\n[resource]\natlas = ExtResource(\"1_l36ww\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/clubs/club_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2ms6tflmr86x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cd0wrsaa54yr8\" path=\"res://assets/icons/clubs.png\" id=\"1_m40ys\"]\n\n[resource]\natlas = ExtResource(\"1_m40ys\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/clubs/club_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c2aqdqhdnw4ip\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cd0wrsaa54yr8\" path=\"res://assets/icons/clubs.png\" id=\"1_qltsb\"]\n\n[resource]\natlas = ExtResource(\"1_qltsb\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/clubs/club_04_without_handle.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://grfunad2tuvr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cd0wrsaa54yr8\" path=\"res://assets/icons/clubs.png\" id=\"1_l6ni3\"]\n\n[resource]\natlas = ExtResource(\"1_l6ni3\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/clubs/club_glowing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dh0uag7gk7gq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cd0wrsaa54yr8\" path=\"res://assets/icons/clubs.png\" id=\"1_ga0qs\"]\n\n[resource]\natlas = ExtResource(\"1_ga0qs\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/challenge_challenge_boss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://wpn3kdfodio1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_4kt41\"]\n\n[resource]\natlas = ExtResource(\"1_4kt41\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/challenge_challenge_mass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dwp0e332xp17y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_cu5ic\"]\n\n[resource]\natlas = ExtResource(\"1_cu5ic\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/humanoid_air.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dqme5rc5e45fq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_o0nwa\"]\n\n[resource]\natlas = ExtResource(\"1_o0nwa\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/humanoid_boss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://db5gkb2u4cunc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_j7lt3\"]\n\n[resource]\natlas = ExtResource(\"1_j7lt3\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/humanoid_champion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dccejvgbokinx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_tp6ef\"]\n\n[resource]\natlas = ExtResource(\"1_tp6ef\")\nregion = Rect2(512, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/humanoid_mass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cvwhxblxaapay\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_hsbkp\"]\n\n[resource]\natlas = ExtResource(\"1_hsbkp\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/humanoid_normal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://by2ki8ltp3nds\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_fsnbs\"]\n\n[resource]\natlas = ExtResource(\"1_fsnbs\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/magic_air.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://crmvirk1csbiv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_irifg\"]\n\n\n[resource]\natlas = ExtResource(\"1_irifg\")\nregion = Rect2(384, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/magic_boss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bd1knlex84tpt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_dps7s\"]\n\n\n[resource]\natlas = ExtResource(\"1_dps7s\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/magic_champion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6fu8pcsxjbtf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_6q7l3\"]\n\n\n[resource]\natlas = ExtResource(\"1_6q7l3\")\nregion = Rect2(512, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/magic_mass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bwj8xc7yf3tix\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_kvs63\"]\n\n\n[resource]\natlas = ExtResource(\"1_kvs63\")\nregion = Rect2(256, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/magic_normal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmlykopj364fb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_oowb2\"]\n\n\n[resource]\natlas = ExtResource(\"1_oowb2\")\nregion = Rect2(128, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/nature_air.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c6gur3jyjjp7y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_k7moo\"]\n\n[resource]\natlas = ExtResource(\"1_k7moo\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/nature_boss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cpwdweupvaqow\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_ns7lv\"]\n\n[resource]\natlas = ExtResource(\"1_ns7lv\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/nature_champion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://doidh6uycm038\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_15fjq\"]\n\n[resource]\natlas = ExtResource(\"1_15fjq\")\nregion = Rect2(512, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/nature_mass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c1d6w7iliavpp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_ilodc\"]\n\n[resource]\natlas = ExtResource(\"1_ilodc\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/nature_normal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b63vxcoxd4hh4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_ffi8t\"]\n\n[resource]\natlas = ExtResource(\"1_ffi8t\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/orc_air.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://2vuc3x7katvu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_rxvio\"]\n\n[resource]\natlas = ExtResource(\"1_rxvio\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/orc_boss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dx2vijxxhk0qx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_5u05l\"]\n\n[resource]\natlas = ExtResource(\"1_5u05l\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/orc_champion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dchx83dipvofd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_a85j3\"]\n\n[resource]\natlas = ExtResource(\"1_a85j3\")\nregion = Rect2(512, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/orc_mass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0b6y1jjksikd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_rmihc\"]\n\n[resource]\natlas = ExtResource(\"1_rmihc\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/orc_normal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://gjoldkg0ife\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_rs8ku\"]\n\n[resource]\natlas = ExtResource(\"1_rs8ku\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/undead_air.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b36cgjilln761\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_ivv8e\"]\n\n[resource]\natlas = ExtResource(\"1_ivv8e\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/undead_boss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dr2r5xy2txmn0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_o7by8\"]\n\n[resource]\natlas = ExtResource(\"1_o7by8\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/undead_champion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://fpi62pd8ngbh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_ty5ku\"]\n\n[resource]\natlas = ExtResource(\"1_ty5ku\")\nregion = Rect2(512, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/undead_mass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0xxhv4ouq26h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_l6w5y\"]\n\n[resource]\natlas = ExtResource(\"1_l6w5y\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/creep_icons/undead_normal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bxyhkcy2au3fx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://du5qunspl0v8d\" path=\"res://assets/icons/creep_icons_atlas.png\" id=\"1_vc6ol\"]\n\n[resource]\natlas = ExtResource(\"1_vc6ol\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cpp12ytya48bi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_y73fc\"]\n\n[resource]\natlas = ExtResource(\"1_y73fc\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://is5qq20187n0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_opufh\"]\n\n[resource]\natlas = ExtResource(\"1_opufh\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://vhhp6ip56bwg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_gvrxb\"]\n\n[resource]\natlas = ExtResource(\"1_gvrxb\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6kmm61imstmo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_y8h65\"]\n\n[resource]\natlas = ExtResource(\"1_y8h65\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://14nrnmis6mo8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_b8028\"]\n\n[resource]\natlas = ExtResource(\"1_b8028\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://uce5y5upxt30\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_hvfsc\"]\n\n[resource]\natlas = ExtResource(\"1_hvfsc\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://nke3a6ve5rvn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_va4pa\"]\n\n[resource]\natlas = ExtResource(\"1_va4pa\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ssflwqxx7pqg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_8mr1l\"]\n\n[resource]\natlas = ExtResource(\"1_8mr1l\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/daggers/dagger_09.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c88dva2o3wrv8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwi67assrjmbr\" path=\"res://assets/icons/daggers.png\" id=\"1_8tf6d\"]\n\n[resource]\natlas = ExtResource(\"1_8tf6d\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/dioramas/book_display.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cgbfx701yxj0a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://eahfoqydhmx8\" path=\"res://assets/icons/dioramas.png\" id=\"1_vshbo\"]\n\n[resource]\natlas = ExtResource(\"1_vshbo\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/dioramas/church.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c8qat10y24gha\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://eahfoqydhmx8\" path=\"res://assets/icons/dioramas.png\" id=\"1_sgfjj\"]\n\n[resource]\natlas = ExtResource(\"1_sgfjj\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/dioramas/fountain.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bhle1jw22cn87\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://eahfoqydhmx8\" path=\"res://assets/icons/dioramas.png\" id=\"1_nfgcy\"]\n\n[resource]\natlas = ExtResource(\"1_nfgcy\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/dioramas/mountain.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0c2cjxjintva\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://eahfoqydhmx8\" path=\"res://assets/icons/dioramas.png\" id=\"1_m5n0w\"]\n\n[resource]\natlas = ExtResource(\"1_m5n0w\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/dioramas/pyramid.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpubq4f0l1k74\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://eahfoqydhmx8\" path=\"res://assets/icons/dioramas.png\" id=\"1_d0yu5\"]\n\n[resource]\natlas = ExtResource(\"1_d0yu5\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/electricity/electricity_blue.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://br6kambyvscch\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bdka8ghpv2c3r\" path=\"res://assets/icons/electricity.png\" id=\"1_e5647\"]\n\n[resource]\natlas = ExtResource(\"1_e5647\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/electricity/electricity_yellow.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhj26dul8djvo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bdka8ghpv2c3r\" path=\"res://assets/icons/electricity.png\" id=\"1_38tjg\"]\n\n[resource]\natlas = ExtResource(\"1_38tjg\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/electricity/lightning_circle_cyan.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dva3clxfeqlyj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bdka8ghpv2c3r\" path=\"res://assets/icons/electricity.png\" id=\"1_oaprd\"]\n\n[resource]\natlas = ExtResource(\"1_oaprd\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/electricity/lightning_circle_white.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://8r5emosr5iew\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bdka8ghpv2c3r\" path=\"res://assets/icons/electricity.png\" id=\"1_c3qnf\"]\n\n[resource]\natlas = ExtResource(\"1_c3qnf\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/electricity/lightning_glowing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b0h56701j5a3f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bdka8ghpv2c3r\" path=\"res://assets/icons/electricity.png\" id=\"1_i1aq1\"]\n\n[resource]\natlas = ExtResource(\"1_i1aq1\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/electricity/thunderstorm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6somhw4q1jum\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bdka8ghpv2c3r\" path=\"res://assets/icons/electricity.png\" id=\"1_55vox\"]\n\n[resource]\natlas = ExtResource(\"1_55vox\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/astral.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b58m66c4f8n2n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_n753t\"]\n\n[resource]\natlas = ExtResource(\"1_n753t\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/darkness.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b7c8ugpn34iib\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_shkj3\"]\n\n[resource]\natlas = ExtResource(\"1_shkj3\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/fire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvhrjk28kmjxg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_lvp7i\"]\n\n[resource]\natlas = ExtResource(\"1_lvp7i\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/ice.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://63uq7vjycais\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_2myab\"]\n\n[resource]\natlas = ExtResource(\"1_2myab\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/iron.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://3aghxlv6b4hb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_x2uoj\"]\n\n[resource]\natlas = ExtResource(\"1_x2uoj\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/nature.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c14cl1op1y5wk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_jaceh\"]\n\n[resource]\natlas = ExtResource(\"1_jaceh\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/elements/storm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ofrvficsj8ih\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0eoqagd75i7k\" path=\"res://assets/icons/elements.png\" id=\"1_2m022\"]\n\n[resource]\natlas = ExtResource(\"1_2m022\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/green_demon.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://do204ej48ox1g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_1m3mt\"]\n\n[resource]\natlas = ExtResource(\"1_1m3mt\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/man_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2a0v2clgfibc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_idkxh\"]\n\n[resource]\natlas = ExtResource(\"1_idkxh\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/man_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bswdgiqt5u2m7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_o01kf\"]\n\n[resource]\natlas = ExtResource(\"1_o01kf\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/man_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://byyqpfxijkqc2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_86osd\"]\n\n[resource]\natlas = ExtResource(\"1_86osd\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/man_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bibyihjdcjrls\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_0a3sa\"]\n\n[resource]\natlas = ExtResource(\"1_0a3sa\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/man_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bcloe1pd3bjlr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_ixnw6\"]\n\n[resource]\natlas = ExtResource(\"1_ixnw6\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/mech_zombie.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bohh0oelc7r3f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_prt3g\"]\n\n[resource]\natlas = ExtResource(\"1_prt3g\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/orc_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://il8r33sq5e3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_pupg7\"]\n\n[resource]\natlas = ExtResource(\"1_pupg7\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/orc_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cirq2nbm85h2e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_l6ecl\"]\n\n[resource]\natlas = ExtResource(\"1_l6ecl\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/sleeping_leaf_spirit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cpeihfa0x517b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_jtoh2\"]\n\n[resource]\natlas = ExtResource(\"1_jtoh2\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/woman_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmqwmftv34a8m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_sbh3c\"]\n\n[resource]\natlas = ExtResource(\"1_sbh3c\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/woman_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://sn1ehc370vgy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_lp7yy\"]\n\n[resource]\natlas = ExtResource(\"1_lp7yy\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/faces/woman_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0xciv1l2w6tu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pgeupu5vkown\" path=\"res://assets/icons/faces.png\" id=\"1_t2hqu\"]\n\n[resource]\natlas = ExtResource(\"1_t2hqu\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/burning_cloth.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://63ywdfc7o4e3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_8x5bu\"]\n\n[resource]\natlas = ExtResource(\"1_8x5bu\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/fire_bowl_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dbh0x1nlsuq53\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_afgv7\"]\n\n[resource]\natlas = ExtResource(\"1_afgv7\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/fire_bowl_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b8dc2cy8asvlh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_omaue\"]\n\n[resource]\natlas = ExtResource(\"1_omaue\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/fire_bowl_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://unmsahh5tu6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_fb4ya\"]\n\n[resource]\natlas = ExtResource(\"1_fb4ya\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/fire_in_cup.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dpts0yyte063n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_4a2r4\"]\n\n[resource]\natlas = ExtResource(\"1_4a2r4\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/flame_blue.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cuf4dwr45qhbw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_dw81p\"]\n\n[resource]\natlas = ExtResource(\"1_dw81p\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/flame_blue_glowing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c2i8dx2hue7w3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_gal0n\"]\n\n[resource]\natlas = ExtResource(\"1_gal0n\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/flame_purple.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ceqvl7x3kc02w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_d743l\"]\n\n[resource]\natlas = ExtResource(\"1_d743l\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/fire/torch.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cu5fbd0fnwpjk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmpa3c1h7ylk\" path=\"res://assets/icons/fire.png\" id=\"1_g2ctg\"]\n\n[resource]\natlas = ExtResource(\"1_g2ctg\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/barrel.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cf2a34pg54hdr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_sbqq5\"]\n\n[resource]\natlas = ExtResource(\"1_sbqq5\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/beer_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://msxmjaf46qif\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_p4jb5\"]\n\n[resource]\natlas = ExtResource(\"1_p4jb5\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/beer_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqawvxijs3fc4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_4rc2b\"]\n\n[resource]\natlas = ExtResource(\"1_4rc2b\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/lard.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2pn7gftjrr41\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_ea748\"]\n\n[resource]\natlas = ExtResource(\"1_ea748\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/pork.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bwcjhm6odarco\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_d2otk\"]\n\n[resource]\natlas = ExtResource(\"1_d2otk\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/pork_without_plate.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvgyvbj1s7jc7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_fsslt\"]\n\n[resource]\natlas = ExtResource(\"1_fsslt\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/food/poultry.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://e21bpw6p1kok\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://versamdrv1pb\" path=\"res://assets/icons/food.png\" id=\"1_vfb6w\"]\n\n[resource]\natlas = ExtResource(\"1_vfb6w\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/artifact_of_skadi.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://byp0e1ejew027\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_5utb0\"]\n\n\n[resource]\natlas = ExtResource(\"1_5utb0\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/artifact_on_pedestal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://nfm4ioymw4n5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_goivb\"]\n\n\n[resource]\natlas = ExtResource(\"1_goivb\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/bed.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnrbvq4mo3ob1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_i0gpi\"]\n\n\n[resource]\natlas = ExtResource(\"1_i0gpi\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/chest.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://2o02qt0v6biq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_mvet7\"]\n\n\n[resource]\natlas = ExtResource(\"1_mvet7\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/exploding_mirror.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c6a610bbi0ord\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_ebgif\"]\n\n\n[resource]\natlas = ExtResource(\"1_ebgif\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/furniture.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bx388l5d5smja\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_ja7by\"]\n\n[resource]\natlas = ExtResource(\"1_ja7by\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/stool.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ckinkpo13wb2f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_bqvym\"]\n\n\n[resource]\natlas = ExtResource(\"1_bqvym\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/throne.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dslt4nqetum5h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_3dd4o\"]\n\n\n[resource]\natlas = ExtResource(\"1_3dd4o\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/furniture/wooden_stand_with_nail.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://i7ft832a1xca\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dw1wnm1xtm8d3\" path=\"res://assets/icons/furniture.png\" id=\"1_sfsfg\"]\n\n[resource]\natlas = ExtResource(\"1_sfsfg\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/crystal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cysj2nwnd6o15\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_pwsif\"]\n\n[resource]\natlas = ExtResource(\"1_pwsif\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/earring_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c6y3vepthrjd3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_2ma52\"]\n\n[resource]\natlas = ExtResource(\"1_2ma52\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/earring_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dq8ebib8ttg8p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_cec10\"]\n\n[resource]\natlas = ExtResource(\"1_cec10\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/earring_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://4agbv1j44f4v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_f7o2d\"]\n\n[resource]\natlas = ExtResource(\"1_f7o2d\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/earring_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ce7sftcucjdu1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_rtvqs\"]\n\n[resource]\natlas = ExtResource(\"1_rtvqs\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/earring_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cw2cxqak4wbea\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_g0wvw\"]\n\n[resource]\natlas = ExtResource(\"1_g0wvw\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://keidafn4wjar\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_65cxn\"]\n\n[resource]\natlas = ExtResource(\"1_65cxn\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://pafu3b3d7wxg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_u663u\"]\n\n[resource]\natlas = ExtResource(\"1_u663u\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cu4hruulnfr17\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_2mqlr\"]\n\n[resource]\natlas = ExtResource(\"1_2mqlr\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://63h87niwwnj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_sxycr\"]\n\n[resource]\natlas = ExtResource(\"1_sxycr\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bmfqpklpe2sp2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_uj2kx\"]\n\n[resource]\natlas = ExtResource(\"1_uj2kx\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://vi7dxxx7qvpo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_2gdhk\"]\n\n[resource]\natlas = ExtResource(\"1_2gdhk\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/gem_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://m0yq4mthuex1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_2l7uy\"]\n\n[resource]\natlas = ExtResource(\"1_2l7uy\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/stone_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cvqmar4gd1ngr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_ot6at\"]\n\n[resource]\natlas = ExtResource(\"1_ot6at\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/stone_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c60fslcqvmqxc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_hratc\"]\n\n[resource]\natlas = ExtResource(\"1_hratc\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/stone_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://mir51fufwae4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_2j0wd\"]\n\n[resource]\natlas = ExtResource(\"1_2j0wd\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gems/stone_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cjilyyyyjlbwt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cnt12q0n2qpou\" path=\"res://assets/icons/gems.png\" id=\"1_1ivw8\"]\n\n[resource]\natlas = ExtResource(\"1_1ivw8\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/README.md",
    "content": "This folder contains icons from game-icons.net website.\n\nThe filenames must match the names on the website.\n\nDo not rename existing icons.\n\nUse matching names when adding new icons.\n"
  },
  {
    "path": "resources/icons/generic_icons/abdominal_armor.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://g6kxhqq1cbfk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_rlxmb\"]\n\n[resource]\natlas = ExtResource(\"1_rlxmb\")\nregion = Rect2(128, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/alien_skull.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bybxbjvfd64tr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_8tfv2\"]\n\n[resource]\natlas = ExtResource(\"1_8tfv2\")\nregion = Rect2(256, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/alligator_clip.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bv7gu3v3jconv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_lacwd\"]\n\n[resource]\natlas = ExtResource(\"1_lacwd\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/amber_mosquito.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6ytfhd8i1ve5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_bk6im\"]\n\n[resource]\natlas = ExtResource(\"1_bk6im\")\nregion = Rect2(128, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/angel_outfit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqmpxcpl04uem\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_johm7\"]\n\n[resource]\natlas = ExtResource(\"1_johm7\")\nregion = Rect2(0, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/angel_wings.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dgrymjtaog3gx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_74cak\"]\n\n[resource]\natlas = ExtResource(\"1_74cak\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/animal_skull.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhbxbxuk7n8kk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_8xe35\"]\n\n[resource]\natlas = ExtResource(\"1_8xe35\")\nregion = Rect2(128, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/ankh.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxttw8oegbi1v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_rg3kj\"]\n\n[resource]\natlas = ExtResource(\"1_rg3kj\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/aquarius.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3chlr7i32uae\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_8jfv6\"]\n\n[resource]\natlas = ExtResource(\"1_8jfv6\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/aries.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://yri0380ravrp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_cs1yd\"]\n\n[resource]\natlas = ExtResource(\"1_cs1yd\")\nregion = Rect2(256, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/armor_vest.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bce4dy61dykla\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_1rk85\"]\n\n[resource]\natlas = ExtResource(\"1_1rk85\")\nregion = Rect2(256, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/atomic_slashes.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cjwek0aj8k6pw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_2srqa\"]\n\n[resource]\natlas = ExtResource(\"1_2srqa\")\nregion = Rect2(256, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/azul_flake.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://2drii204c2r3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_42dkl\"]\n\n[resource]\natlas = ExtResource(\"1_42dkl\")\nregion = Rect2(128, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/barbute.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://digugf0f1udtb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_tc2q7\"]\n\n[resource]\natlas = ExtResource(\"1_tc2q7\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/barefoot.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c52golqtdlvcf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_sbnxt\"]\n\n[resource]\natlas = ExtResource(\"1_sbnxt\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/bat_mask.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1qm7k37swric\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_cvca8\"]\n\n[resource]\natlas = ExtResource(\"1_cvca8\")\nregion = Rect2(0, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/beard.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xjkqhdkmldw0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_wubkc\"]\n\n[resource]\natlas = ExtResource(\"1_wubkc\")\nregion = Rect2(256, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/biceps.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bndmfop66ljoa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_65ndd\"]\n\n[resource]\natlas = ExtResource(\"1_65ndd\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/burning_dot.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://csbk40h1qfx2g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_06e0i\"]\n\n[resource]\natlas = ExtResource(\"1_06e0i\")\nregion = Rect2(256, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/burning_meteor.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://hoh55202e0oe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_l5gdx\"]\n\n[resource]\natlas = ExtResource(\"1_l5gdx\")\nregion = Rect2(384, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/charm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ben1biwc3fyks\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_ptasi\"]\n\n[resource]\natlas = ExtResource(\"1_ptasi\")\nregion = Rect2(384, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/chest_armor.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://s0bsohkidpi6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_a8mma\"]\n\n[resource]\natlas = ExtResource(\"1_a8mma\")\nregion = Rect2(256, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/cog.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3o7wv5cxj5lo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_xeiw6\"]\n\n[resource]\natlas = ExtResource(\"1_xeiw6\")\nregion = Rect2(0, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/egg.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cdqtd51r814ka\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_ptyjt\"]\n\n[resource]\natlas = ExtResource(\"1_ptyjt\")\nregion = Rect2(0, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/electric.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dooe81fs723ya\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_nyko8\"]\n\n[resource]\natlas = ExtResource(\"1_nyko8\")\nregion = Rect2(0, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/energy_breath.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ba6ku7cx0nqo0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_kimbw\"]\n\n[resource]\natlas = ExtResource(\"1_kimbw\")\nregion = Rect2(384, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/fire_dash.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmfyy8y822jj7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_33h32\"]\n\n[resource]\natlas = ExtResource(\"1_33h32\")\nregion = Rect2(128, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/flame.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cd6iaobmlxbs5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_msxba\"]\n\n[resource]\natlas = ExtResource(\"1_msxba\")\nregion = Rect2(384, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/foot_trip.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnrisgtt3wnd2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_8e6gf\"]\n\n[resource]\natlas = ExtResource(\"1_8e6gf\")\nregion = Rect2(384, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/ghost.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://br1e4jv3ceixt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_draw0\"]\n\n[resource]\natlas = ExtResource(\"1_draw0\")\nregion = Rect2(128, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/gold_bar.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c3lshombp5ddb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_3anac\"]\n\n[resource]\natlas = ExtResource(\"1_3anac\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/hammer_drop.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c51sj37ulgdqp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_ekr3x\"]\n\n[resource]\natlas = ExtResource(\"1_ekr3x\")\nregion = Rect2(128, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/holy_grail.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cp2vrv08ceg4b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_t4w8w\"]\n\n[resource]\natlas = ExtResource(\"1_t4w8w\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/horned_helm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d4g2ksl6hmriu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_5rfs8\"]\n\n[resource]\natlas = ExtResource(\"1_5rfs8\")\nregion = Rect2(384, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/hourglass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b34cyfbyfhk6p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_xleyd\"]\n\n[resource]\natlas = ExtResource(\"1_xleyd\")\nregion = Rect2(0, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/knocked_out_stars.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2yy3ibmn8nfw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_3edkw\"]\n\n[resource]\natlas = ExtResource(\"1_3edkw\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/liberty_wing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnv4lugvnwqjt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_bp2w3\"]\n\n[resource]\natlas = ExtResource(\"1_bp2w3\")\nregion = Rect2(256, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/meat.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dyaarp6hgeswd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_sp305\"]\n\n[resource]\natlas = ExtResource(\"1_sp305\")\nregion = Rect2(256, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/mighty_force.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cl4hkgbwaqpo5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_1ydhp\"]\n\n[resource]\natlas = ExtResource(\"1_1ydhp\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/mine_explosion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dbjti87s5rie4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_f1xgw\"]\n\n[resource]\natlas = ExtResource(\"1_f1xgw\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/moebius_trefoil.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cghaedw51shn4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_4ue40\"]\n\n[resource]\natlas = ExtResource(\"1_4ue40\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/omega.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xcruhv1n8wnd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_gdsmc\"]\n\n[resource]\natlas = ExtResource(\"1_gdsmc\")\nregion = Rect2(0, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/open_wound.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://li7ju5hlg8rb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_6m3sg\"]\n\n[resource]\natlas = ExtResource(\"1_6m3sg\")\nregion = Rect2(384, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/ophiucus.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cqi7jcn16pgoc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_qf8wy\"]\n\n[resource]\natlas = ExtResource(\"1_qf8wy\")\nregion = Rect2(0, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/orc_head.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b3let6vwpgfp1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_rgi8v\"]\n\n[resource]\natlas = ExtResource(\"1_rgi8v\")\nregion = Rect2(128, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/over_infinity.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bo0c4w2nvf7q7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_2knny\"]\n\n[resource]\natlas = ExtResource(\"1_2knny\")\nregion = Rect2(0, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/perpendicular_rings.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c3yr4au2yukn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_54wd3\"]\n\n[resource]\natlas = ExtResource(\"1_54wd3\")\nregion = Rect2(128, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/pisces.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dxwtuus1sd40x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_lfp52\"]\n\n[resource]\natlas = ExtResource(\"1_lfp52\")\nregion = Rect2(256, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/poison_gas.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b5y6lds2sth7u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_408c0\"]\n\n[resource]\natlas = ExtResource(\"1_408c0\")\nregion = Rect2(384, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/pokecog.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b37u11w37lqw0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_uogpp\"]\n\n[resource]\natlas = ExtResource(\"1_uogpp\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/polar_star.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1vbf1m1dlxcu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_mtjun\"]\n\n[resource]\natlas = ExtResource(\"1_mtjun\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/rolling_energy.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c22xwqvy346pp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_qixl0\"]\n\n[resource]\natlas = ExtResource(\"1_qixl0\")\nregion = Rect2(384, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/root_tip.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cx5tr6m5d1tm7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_hidtg\"]\n\n[resource]\natlas = ExtResource(\"1_hidtg\")\nregion = Rect2(256, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/round_potion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bcwpmcuwu65td\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_u6n7s\"]\n\n[resource]\natlas = ExtResource(\"1_u6n7s\")\nregion = Rect2(256, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/rss.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bq54vh6mtqtdw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_v48b7\"]\n\n[resource]\natlas = ExtResource(\"1_v48b7\")\nregion = Rect2(384, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/semi_closed_eye.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bl4odykcddi37\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_u74bc\"]\n\n[resource]\natlas = ExtResource(\"1_u74bc\")\nregion = Rect2(0, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/shiny_omega.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://beq6yjrsvld5e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_0dnyv\"]\n\n[resource]\natlas = ExtResource(\"1_0dnyv\")\nregion = Rect2(128, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/spell_book.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b0bccstg28j18\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_kpk0k\"]\n\n[resource]\natlas = ExtResource(\"1_kpk0k\")\nregion = Rect2(384, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/spider_web.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://m04q3k41lnkq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_hhfya\"]\n\n[resource]\natlas = ExtResource(\"1_hhfya\")\nregion = Rect2(384, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/sprint.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://btvgi5m658qtv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_btsui\"]\n\n[resource]\natlas = ExtResource(\"1_btsui\")\nregion = Rect2(0, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/star_swirl.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cfimexaqalwcy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_048rt\"]\n\n[resource]\natlas = ExtResource(\"1_048rt\")\nregion = Rect2(128, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/triple_scratches.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ckv2q0fwiirvi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_4uwbq\"]\n\n[resource]\natlas = ExtResource(\"1_4uwbq\")\nregion = Rect2(128, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/turtle_shell.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dy6pmoeog7xwx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_e5m5y\"]\n\n[resource]\natlas = ExtResource(\"1_e5m5y\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/generic_icons/wolf_howl.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b36lvmv2m8g31\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bjf87xc5r8rig\" path=\"res://assets/icons/generic_icons.png\" id=\"1_ah3n3\"]\n\n[resource]\natlas = ExtResource(\"1_ah3n3\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/curse.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbyvxfbbqpf46\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_webav\"]\n\n[resource]\natlas = ExtResource(\"1_webav\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://di14tm24t02oi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_oh8nm\"]\n\n[resource]\natlas = ExtResource(\"1_oh8nm\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dx7e3bp8y73qi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_borwt\"]\n\n[resource]\natlas = ExtResource(\"1_borwt\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bgadits5pvujh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_chlox\"]\n\n[resource]\natlas = ExtResource(\"1_chlox\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0pdetqvnc77n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_2v7ds\"]\n\n[resource]\natlas = ExtResource(\"1_2v7ds\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bo53rlno855cy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_pqcl3\"]\n\n[resource]\natlas = ExtResource(\"1_pqcl3\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://08uojib1oy7j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_0yec0\"]\n\n[resource]\natlas = ExtResource(\"1_0yec0\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dppe4ly5ax4sg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_b210b\"]\n\n[resource]\natlas = ExtResource(\"1_b210b\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/gloves_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dqqwxpofdiq4e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_giftb\"]\n\n[resource]\natlas = ExtResource(\"1_giftb\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/heal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0npkf7jas08m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_om5g1\"]\n\n[resource]\natlas = ExtResource(\"1_om5g1\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/gloves/steal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://nk8vys5n0rup\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dnqge0ttmsxhg\" path=\"res://assets/icons/gloves.png\" id=\"1_8oeun\"]\n\n[resource]\natlas = ExtResource(\"1_8oeun\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/crown_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0ayor4c1d3hd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_s2rog\"]\n\n[resource]\natlas = ExtResource(\"1_s2rog\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/crown_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dywbvctjhwww8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_lbun7\"]\n\n[resource]\natlas = ExtResource(\"1_lbun7\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/crown_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bo53ec5cimev8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_qkm5l\"]\n\n[resource]\natlas = ExtResource(\"1_qkm5l\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://clqfmxlxib20v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_1meml\"]\n\n[resource]\natlas = ExtResource(\"1_1meml\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://opr2g5bevxo3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_w5ypo\"]\n\n[resource]\natlas = ExtResource(\"1_w5ypo\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfhhocuo4f20w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_x85hm\"]\n\n[resource]\natlas = ExtResource(\"1_x85hm\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://va043tuylqow\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_hxfat\"]\n\n[resource]\natlas = ExtResource(\"1_hxfat\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://brvd2yx3mvuyu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_3fjy2\"]\n\n[resource]\natlas = ExtResource(\"1_3fjy2\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dsa4174mibicy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_db0tt\"]\n\n[resource]\natlas = ExtResource(\"1_db0tt\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bwri54rpc8y0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_tlkvi\"]\n\n[resource]\natlas = ExtResource(\"1_tlkvi\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/helmet_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxfbes60jo1tg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_g5hav\"]\n\n[resource]\natlas = ExtResource(\"1_g5hav\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/wizard_hat_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://by2c2hexv140n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_vjdqf\"]\n\n[resource]\natlas = ExtResource(\"1_vjdqf\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/helmets/wizard_hat_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c3uwdmkttd6y6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c5xyjl0m53xv0\" path=\"res://assets/icons/helmets.png\" id=\"1_ekxcn\"]\n\n[resource]\natlas = ExtResource(\"1_ekxcn\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/altar.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://hayy3ijnnw0k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_c3fwi\"]\n\n[resource]\natlas = ExtResource(\"1_c3fwi\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/axe.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2scqcavvqc1v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_77vna\"]\n\n[resource]\natlas = ExtResource(\"1_77vna\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/cross_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d04sbvha2dc6e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_vfj8m\"]\n\n[resource]\natlas = ExtResource(\"1_vfj8m\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/cross_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqvfj8xolwem0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_b3pnr\"]\n\n[resource]\natlas = ExtResource(\"1_b3pnr\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/cross_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dabv6i74x31qw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_is6hu\"]\n\n[resource]\natlas = ExtResource(\"1_is6hu\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/orb.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2qnt4rtm4srb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_qnpej\"]\n\n[resource]\natlas = ExtResource(\"1_qnpej\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/tombstone.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b3kmi0oh6ia1p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_l25ia\"]\n\n[resource]\natlas = ExtResource(\"1_l25ia\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/holy/white_trinket.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bisk7s5fd6l3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cj5n47n5k4p46\" path=\"res://assets/icons/holy.png\" id=\"1_8ewa5\"]\n\n[resource]\natlas = ExtResource(\"1_8ewa5\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/dice.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c7uoycvu5ii8v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_mh1d2\"]\n\n[resource]\natlas = ExtResource(\"1_mh1d2\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/gem_all_rarities.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://775ninjr2sio\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_c31af\"]\n\n[resource]\natlas = ExtResource(\"1_c31af\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/gem_common.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnfyls46vqccy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_wgk62\"]\n\n[resource]\natlas = ExtResource(\"1_wgk62\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/gem_rare.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://do0ipsu6xkehe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_7yitg\"]\n\n[resource]\natlas = ExtResource(\"1_7yitg\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/gem_uncommon.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bbgnvq4hx2ady\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_0bmk6\"]\n\n[resource]\natlas = ExtResource(\"1_0bmk6\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/gem_unique.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://fhntdx77to0k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_63c3j\"]\n\n[resource]\natlas = ExtResource(\"1_63c3j\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/gold.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bxqh2nddd7eni\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_id1ki\"]\n\n[resource]\natlas = ExtResource(\"1_id1ki\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/item_stash.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://boxxhen27xatf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_fio6f\"]\n\n[resource]\natlas = ExtResource(\"1_fio6f\")\nregion = Rect2(256, 128, 128, 128)\nmargin = Rect2(2, 2, 2.08165e-12, 2.08165e-12)\n"
  },
  {
    "path": "resources/icons/hud/knowledge_tome.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1d4h6m0klgw1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_apct5\"]\n\n[resource]\natlas = ExtResource(\"1_apct5\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/oils.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c50etdjubvudf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_f5rl5\"]\n\n[resource]\natlas = ExtResource(\"1_f5rl5\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/recipe_distill.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfqns87v0xu7x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_2bjxv\"]\n\n[resource]\natlas = ExtResource(\"1_2bjxv\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/recipe_perfect.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvclahxp4mvge\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_vmog1\"]\n\n[resource]\natlas = ExtResource(\"1_vmog1\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/recipe_reassemble.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bk4dvb16ukwx8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_l87be\"]\n\n[resource]\natlas = ExtResource(\"1_l87be\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/recipe_rebrew.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b1oind72lxrm4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_gykxp\"]\n\n[resource]\natlas = ExtResource(\"1_gykxp\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/research_elements.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1sklksk2awnr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_xsxy2\"]\n\n[resource]\natlas = ExtResource(\"1_xsxy2\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/tower_food.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://baig85lpi88u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_prt50\"]\n\n[resource]\natlas = ExtResource(\"1_prt50\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/hud/tower_stash.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://r7qkt7vep0ar\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bwcmn5v70q23p\" path=\"res://assets/icons/hud.png\" id=\"1_vh3id\"]\n\n[resource]\natlas = ExtResource(\"1_vh3id\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/bowl_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bk0b7kbrelsfr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_0b731\"]\n\n\n[resource]\natlas = ExtResource(\"1_0b731\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/bowl_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dk4ykniutwr0c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_odp1x\"]\n\n\n[resource]\natlas = ExtResource(\"1_odp1x\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/claw_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6efjaqca5hup\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_m00rc\"]\n\n\n[resource]\natlas = ExtResource(\"1_m00rc\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/claw_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://7i3l7uua7f4n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_86rmx\"]\n\n[resource]\natlas = ExtResource(\"1_86rmx\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/claw_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dgwsqre4c0soi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_gbjoa\"]\n\n\n[resource]\natlas = ExtResource(\"1_gbjoa\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/claw_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://l45c48acjiam\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_r22b7\"]\n\n\n[resource]\natlas = ExtResource(\"1_r22b7\")\nregion = Rect2(384, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/eye.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://duhfxvv00ok6t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_8c4c0\"]\n\n\n[resource]\natlas = ExtResource(\"1_8c4c0\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/eye_blue.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cm77f48kx48x5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_6hsu6\"]\n\n\n[resource]\natlas = ExtResource(\"1_6hsu6\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/eyes_many.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dauymcd52yvhx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_am3wi\"]\n\n\n[resource]\natlas = ExtResource(\"1_am3wi\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/fire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dex352lerjhwq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_5k3ia\"]\n\n\n[resource]\natlas = ExtResource(\"1_5k3ia\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/lantern.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xobavcifq8s5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_xk25v\"]\n\n\n[resource]\natlas = ExtResource(\"1_xk25v\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/lock_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bib82nktwe4qx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_ho8al\"]\n\n[resource]\natlas = ExtResource(\"1_ho8al\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/lock_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cv3d38cidtlgp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_s5d0s\"]\n\n\n[resource]\natlas = ExtResource(\"1_s5d0s\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/lock_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfg41yrbhb4hu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_fb47s\"]\n\n\n[resource]\natlas = ExtResource(\"1_fb47s\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/lock_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b5dnvyk3quah8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_soe3o\"]\n\n[resource]\natlas = ExtResource(\"1_soe3o\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/magic_stone.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bkmyw11w5jqjw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_l4klk\"]\n\n\n[resource]\natlas = ExtResource(\"1_l4klk\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/magic/magic_stone_green.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://do03rvvm3ubam\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://6r3vtu5yr06v\" path=\"res://assets/icons/magic.png\" id=\"1_vttry\"]\n\n[resource]\natlas = ExtResource(\"1_vttry\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0vpryqf162jt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_pxv6a\"]\n\n[resource]\natlas = ExtResource(\"1_pxv6a\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c4i2mt3v8nkyt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_11hjs\"]\n\n[resource]\natlas = ExtResource(\"1_11hjs\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfs1iu4x065hb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_2i7bj\"]\n\n[resource]\natlas = ExtResource(\"1_2i7bj\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://btig5g4yhpid5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_i3eh0\"]\n\n[resource]\natlas = ExtResource(\"1_i3eh0\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1wjdelwf5565\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_vvprc\"]\n\n[resource]\natlas = ExtResource(\"1_vvprc\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ccq5paddksook\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_620s0\"]\n\n[resource]\natlas = ExtResource(\"1_620s0\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/masks/mask_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://blccyl4jo0im5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbusfslop4dph\" path=\"res://assets/icons/masks.png\" id=\"1_fifqe\"]\n\n[resource]\natlas = ExtResource(\"1_fifqe\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/alchemy_kit_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b30yt0bkbmhsj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_djbdm\"]\n\n[resource]\natlas = ExtResource(\"1_djbdm\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/alchemy_kit_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ddt7tbq3lvqdt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_4e2nj\"]\n\n[resource]\natlas = ExtResource(\"1_4e2nj\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/alchemy_kit_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqsnuywmbb5c1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_kn6tx\"]\n\n[resource]\natlas = ExtResource(\"1_kn6tx\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://o41e2p7lsrt4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_knbnp\"]\n\n[resource]\natlas = ExtResource(\"1_knbnp\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/black_gold_calculator.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://day3lrb84itt1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_ohgn8\"]\n\n[resource]\natlas = ExtResource(\"1_ohgn8\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/circuit_board.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://y7p7lvhlxine\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_wesgw\"]\n\n[resource]\natlas = ExtResource(\"1_wesgw\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/compass.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bbax2xlr25ajb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_2gdh7\"]\n\n[resource]\natlas = ExtResource(\"1_2gdh7\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/factory_fumes.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://k788v4egssjm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_lh5bh\"]\n\n[resource]\natlas = ExtResource(\"1_lh5bh\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/factory_gears.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bwi0hj5vp0dlt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_wi7oy\"]\n\n[resource]\natlas = ExtResource(\"1_wi7oy\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/gold_machine.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bt3rltbsw78rg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_hkfr7\"]\n\n[resource]\natlas = ExtResource(\"1_hkfr7\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/lamp.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://l5ev14c1fsjk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_gbl7e\"]\n\n[resource]\natlas = ExtResource(\"1_gbl7e\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/mech_badge.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://y8gaj453mjt8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_tsecr\"]\n\n[resource]\natlas = ExtResource(\"1_tsecr\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/mechanical/mech_umbrella.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d7bsy0k00yoe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ceq6tdm7gc1tw\" path=\"res://assets/icons/mechanical.png\" id=\"1_vevis\"]\n\n[resource]\natlas = ExtResource(\"1_vevis\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/balls_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bh7pnlyv0j3aa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_diirh\"]\n\n[resource]\natlas = ExtResource(\"1_diirh\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/balls_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cy018aja0at7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_11v7g\"]\n\n[resource]\natlas = ExtResource(\"1_11v7g\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/balls_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://2hekjlnrsafo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_pg57v\"]\n\n[resource]\natlas = ExtResource(\"1_pg57v\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/cauldron.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bj137t8r7jrse\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_fkrla\"]\n\n[resource]\natlas = ExtResource(\"1_fkrla\")\nregion = Rect2(384, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/flag_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1yi211mhf7ov\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_vmdiv\"]\n\n[resource]\natlas = ExtResource(\"1_vmdiv\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/flag_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bywjgbjhtyduf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_av4sg\"]\n\n[resource]\natlas = ExtResource(\"1_av4sg\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/flag_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnbgyfpor85q6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_xtqu4\"]\n\n[resource]\natlas = ExtResource(\"1_xtqu4\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/gold_cart.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://chqc7p1uytvbc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_le4gy\"]\n\n[resource]\natlas = ExtResource(\"1_le4gy\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/grenade.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0i1xdy60nvcr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_xmp25\"]\n\n[resource]\natlas = ExtResource(\"1_xmp25\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/poison_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bfdsci6m5tbg6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_yhfcd\"]\n\n[resource]\natlas = ExtResource(\"1_yhfcd\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/poison_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2s11yy0hn57t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_avalq\"]\n\n[resource]\natlas = ExtResource(\"1_avalq\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/quiver.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bghlgra7k5wjm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_k1kdr\"]\n\n[resource]\natlas = ExtResource(\"1_k1kdr\")\nregion = Rect2(0, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/red_knight.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dm04fq8uj7b7a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_gu18b\"]\n\n[resource]\natlas = ExtResource(\"1_gu18b\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/spiky_totem_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bl54642fpnwov\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_diirh\"]\n\n[resource]\natlas = ExtResource(\"1_diirh\")\nregion = Rect2(128, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/spiky_totem_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhq34lkvh8ntj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_x51yo\"]\n\n[resource]\natlas = ExtResource(\"1_x51yo\")\nregion = Rect2(256, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/teapot_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dspb66ieiukd6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_u0hnk\"]\n\n[resource]\natlas = ExtResource(\"1_u0hnk\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/teapot_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cc7wi6hj246bg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_vkp0p\"]\n\n[resource]\natlas = ExtResource(\"1_vkp0p\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/teapot_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpkcoe28q4gig\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_4kf22\"]\n\n[resource]\natlas = ExtResource(\"1_4kf22\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/teapot_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dns5dtn0eknau\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_8mjsr\"]\n\n[resource]\natlas = ExtResource(\"1_8mjsr\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/toolbox_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cya5l8q03m0pu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_f856v\"]\n\n[resource]\natlas = ExtResource(\"1_f856v\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/misc/toolbox_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dolv7ch5n066w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://5mmfa2rctix6\" path=\"res://assets/icons/misc.png\" id=\"1_v57hi\"]\n\n[resource]\natlas = ExtResource(\"1_v57hi\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/moon.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bdbefp8h28y52\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_xk0kn\"]\n\n[resource]\natlas = ExtResource(\"1_xk0kn\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_fire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ct0qx266qb475\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_o2ibd\"]\n\n[resource]\natlas = ExtResource(\"1_o2ibd\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_green.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://brrbuiqs6010w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_3m6ib\"]\n\n[resource]\natlas = ExtResource(\"1_3m6ib\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_ice.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dpauy63vc7suf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_ycusn\"]\n\n[resource]\natlas = ExtResource(\"1_ycusn\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_ice_melting.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://csaal375067id\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_2geki\"]\n\n[resource]\natlas = ExtResource(\"1_2geki\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_molten.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d0ym0jkw0qxe3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_rkses\"]\n\n[resource]\natlas = ExtResource(\"1_rkses\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_molten_dull.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cu48idpy4nlgn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_0neaq\"]\n\n[resource]\natlas = ExtResource(\"1_0neaq\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_shadow.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0f4m6hyn2f7e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_mh5vg\"]\n\n[resource]\natlas = ExtResource(\"1_mh5vg\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/orbs/orb_small.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://nulsr20vaarf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqgh5nkwvbvbg\" path=\"res://assets/icons/orbs.png\" id=\"1_5jwq4\"]\n\n[resource]\natlas = ExtResource(\"1_5jwq4\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/branch_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://das2yaxe5ncb0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_reanf\"]\n\n[resource]\natlas = ExtResource(\"1_reanf\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/branch_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dg6viewp1lb52\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_30x31\"]\n\n[resource]\natlas = ExtResource(\"1_30x31\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/flower_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1pu50pfvec26\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_hswj4\"]\n\n[resource]\natlas = ExtResource(\"1_hswj4\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/flower_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxnpai2dhescc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_67i34\"]\n\n[resource]\natlas = ExtResource(\"1_67i34\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/flower_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bklu8bxml86bb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_k76bj\"]\n\n[resource]\natlas = ExtResource(\"1_k76bj\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/flower_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://klb152orwqy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_1g5at\"]\n\n[resource]\natlas = ExtResource(\"1_1g5at\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/flower_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://df2vorh8m2nbl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_1ocyb\"]\n\n[resource]\natlas = ExtResource(\"1_1ocyb\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/flower_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://u5ax3xkstpp5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_tqfin\"]\n\n[resource]\natlas = ExtResource(\"1_tqfin\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/leaf_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://got0rv6eu4rv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_aacc7\"]\n\n[resource]\natlas = ExtResource(\"1_aacc7\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/leaf_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c7mvq5qj0b3h1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_i6ir2\"]\n\n[resource]\natlas = ExtResource(\"1_i6ir2\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/leaf_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b88tf1esf3fji\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_ym83u\"]\n\n[resource]\natlas = ExtResource(\"1_ym83u\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/plant_in_pot.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ds65p6hdoa4wj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_qxlxo\"]\n\n[resource]\natlas = ExtResource(\"1_qxlxo\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/stump.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://de1f0367670pf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_w0oa7\"]\n\n[resource]\natlas = ExtResource(\"1_w0oa7\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/plants/tree.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://je78vk8p11vc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b3a12s53ygdfh\" path=\"res://assets/icons/plants.png\" id=\"1_6a3in\"]\n\n[resource]\natlas = ExtResource(\"1_6a3in\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/beaker_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dtl68k5ir65hq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_0nvg7\"]\n\n[resource]\natlas = ExtResource(\"1_0nvg7\")\nregion = Rect2(0, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/beaker_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://hqc8vl8amt46\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_otjyw\"]\n\n[resource]\natlas = ExtResource(\"1_otjyw\")\nregion = Rect2(128, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/beaker_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://44t7b1dtey62\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_1sb4x\"]\n\n[resource]\natlas = ExtResource(\"1_1sb4x\")\nregion = Rect2(256, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cvtny6ia28wa6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_uv4f1\"]\n\n[resource]\natlas = ExtResource(\"1_uv4f1\")\nregion = Rect2(0, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://beyew5uiwmhex\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_8p7fa\"]\n\n[resource]\natlas = ExtResource(\"1_8p7fa\")\nregion = Rect2(384, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bq71rkm3nkj2w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_lmino\"]\n\n[resource]\natlas = ExtResource(\"1_lmino\")\nregion = Rect2(256, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2i1hw00tgryy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_cv3f6\"]\n\n[resource]\natlas = ExtResource(\"1_cv3f6\")\nregion = Rect2(384, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b3m07qg5islct\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_dijuj\"]\n\n[resource]\natlas = ExtResource(\"1_dijuj\")\nregion = Rect2(384, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://jjngvqbvp18l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_7wxiv\"]\n\n[resource]\natlas = ExtResource(\"1_7wxiv\")\nregion = Rect2(128, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnb6r5h8kncth\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_xcydg\"]\n\n[resource]\natlas = ExtResource(\"1_xcydg\")\nregion = Rect2(256, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://e5tn5lotmtbh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_uv4f1\"]\n\n[resource]\natlas = ExtResource(\"1_uv4f1\")\nregion = Rect2(0, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_09.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dyphyiom0p30y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_bhlm7\"]\n\n[resource]\natlas = ExtResource(\"1_bhlm7\")\nregion = Rect2(128, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_10.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bn56vik3ngmd8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_qw6uk\"]\n\n[resource]\natlas = ExtResource(\"1_qw6uk\")\nregion = Rect2(256, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_blue_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://clusigr3qsaa8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_7tft8\"]\n\n[resource]\natlas = ExtResource(\"1_7tft8\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_blue_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dp7h2whsyx1re\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_h8dk7\"]\n\n[resource]\natlas = ExtResource(\"1_h8dk7\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_blue_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b6uppctxb6lwo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_oroxb\"]\n\n[resource]\natlas = ExtResource(\"1_oroxb\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_blue_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cnoqu56etskrp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_7imae\"]\n\n[resource]\natlas = ExtResource(\"1_7imae\")\nregion = Rect2(256, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_blue_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://x4155jlpifv1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_yf2oc\"]\n\n[resource]\natlas = ExtResource(\"1_yf2oc\")\nregion = Rect2(384, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_cyan_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://kr0p3s1rx1ry\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_wrfhf\"]\n\n[resource]\natlas = ExtResource(\"1_wrfhf\")\nregion = Rect2(0, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_cyan_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bsc5beraf3usa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_rukxk\"]\n\n[resource]\natlas = ExtResource(\"1_rukxk\")\nregion = Rect2(128, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_cyan_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dqq31e8yqptkm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_31mck\"]\n\n[resource]\natlas = ExtResource(\"1_31mck\")\nregion = Rect2(256, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_green_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cdsibn0u82im0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_d3pkg\"]\n\n[resource]\natlas = ExtResource(\"1_d3pkg\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_green_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dsy0fd5a64ep3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_a1dka\"]\n\n[resource]\natlas = ExtResource(\"1_a1dka\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_green_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bafi3vljf6goc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_1m5mp\"]\n\n[resource]\natlas = ExtResource(\"1_1m5mp\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_heart_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cjwsvqeuujhl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_p3ccp\"]\n\n[resource]\natlas = ExtResource(\"1_p3ccp\")\nregion = Rect2(0, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_heart_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cj1b5ljia3dit\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_j8sj7\"]\n\n[resource]\natlas = ExtResource(\"1_j8sj7\")\nregion = Rect2(128, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_orange_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c7ct6fho0otes\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_nm4bk\"]\n\n[resource]\natlas = ExtResource(\"1_nm4bk\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_orange_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d0d56lcpbv5p0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_fy44v\"]\n\n[resource]\natlas = ExtResource(\"1_fy44v\")\nregion = Rect2(128, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_orange_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://v2i7fkar6cfh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_jihdy\"]\n\n[resource]\natlas = ExtResource(\"1_jihdy\")\nregion = Rect2(256, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_purple_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bhmlur6rfu7rj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_vpdba\"]\n\n[resource]\natlas = ExtResource(\"1_vpdba\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_purple_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dixy0uq7v5lpy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_1o11e\"]\n\n[resource]\natlas = ExtResource(\"1_1o11e\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_purple_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2j1toluglyab\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_vjdub\"]\n\n[resource]\natlas = ExtResource(\"1_vjdub\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_red_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b0102gaot2up1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_rbn1p\"]\n\n[resource]\natlas = ExtResource(\"1_rbn1p\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_red_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://crpg4e56rhlcj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_vii3e\"]\n\n[resource]\natlas = ExtResource(\"1_vii3e\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_red_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cobp620wxtchu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_2hker\"]\n\n[resource]\natlas = ExtResource(\"1_2hker\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_yellow_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ce7x5kmki0a6e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_7susy\"]\n\n[resource]\natlas = ExtResource(\"1_7susy\")\nregion = Rect2(0, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/potions/potion_yellow_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bjs05fgpwhq37\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p1qub7re6sdg\" path=\"res://assets/icons/potion_icons_m.png\" id=\"1_glnf4\"]\n\n[resource]\natlas = ExtResource(\"1_glnf4\")\nregion = Rect2(128, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dvc8jp00nqegf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_s8ra7\"]\n\n[resource]\natlas = ExtResource(\"1_s8ra7\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bmtw1mhdtrhfi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_jd1q6\"]\n\n[resource]\natlas = ExtResource(\"1_jd1q6\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://v62i7pmi12fq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_ugb48\"]\n\n[resource]\natlas = ExtResource(\"1_ugb48\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnxd285fuarc7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_xjuvi\"]\n\n[resource]\natlas = ExtResource(\"1_xjuvi\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c32xtnysqhnxp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_2wrr3\"]\n\n[resource]\natlas = ExtResource(\"1_2wrr3\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://jjgyjr50nfh3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_trxgv\"]\n\n[resource]\natlas = ExtResource(\"1_trxgv\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1c3jnjfnh35y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_ld1oq\"]\n\n[resource]\natlas = ExtResource(\"1_ld1oq\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/rings/ring_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://byn27u8mw8p3x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ujgb13e5v2s8\" path=\"res://assets/icons/rings.png\" id=\"1_7iyki\"]\n\n[resource]\natlas = ExtResource(\"1_7iyki\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwn467be5iqff\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_1ppj0\"]\n\n[resource]\natlas = ExtResource(\"1_1ppj0\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bbsymkbpaqnmh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_yd86v\"]\n\n[resource]\natlas = ExtResource(\"1_yd86v\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bkxbdrb23tby0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_neirv\"]\n\n[resource]\natlas = ExtResource(\"1_neirv\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://clvalsxcvuhlo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_3lpae\"]\n\n[resource]\natlas = ExtResource(\"1_3lpae\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ckb2soah83qpl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_2f0pb\"]\n\n[resource]\natlas = ExtResource(\"1_2f0pb\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://del012wqusxbe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_sndx1\"]\n\n[resource]\natlas = ExtResource(\"1_sndx1\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/rockets/rocket_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cx3yii5der5w7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cu33x7mcwrwhh\" path=\"res://assets/icons/rockets.png\" id=\"1_7dncu\"]\n\n[resource]\natlas = ExtResource(\"1_7dncu\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0vcguvu7pw63\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_f38my\"]\n\n[resource]\natlas = ExtResource(\"1_f38my\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvc0pqytbcamw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_fbhnt\"]\n\n[resource]\natlas = ExtResource(\"1_fbhnt\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bh8u6vh326jsv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_4roen\"]\n\n[resource]\natlas = ExtResource(\"1_4roen\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bw24wp2ti4plx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_05v45\"]\n\n[resource]\natlas = ExtResource(\"1_05v45\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c776akte03sof\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_tni2m\"]\n\n[resource]\natlas = ExtResource(\"1_tni2m\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bho5tdv6jspb0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_ptfo7\"]\n\n[resource]\natlas = ExtResource(\"1_ptfo7\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvstjfoa3c3lv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_yig1a\"]\n\n[resource]\natlas = ExtResource(\"1_yig1a\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/scrolls/scroll_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmse6xah400qn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4f11knnb7xlr\" path=\"res://assets/icons/scrolls.png\" id=\"1_jh7a7\"]\n\n[resource]\natlas = ExtResource(\"1_jh7a7\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_bronze.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cy5k7173vi4ww\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_2ball\"]\n\n[resource]\natlas = ExtResource(\"1_2ball\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_castle.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xhl53xla45c1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_4xndd\"]\n\n[resource]\natlas = ExtResource(\"1_4xndd\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_gray_with_gold_emblem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dvu2bhse8igyk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_13hq7\"]\n\n[resource]\natlas = ExtResource(\"1_13hq7\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_green.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1sk2u7fsgy2c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_rdq5q\"]\n\n[resource]\natlas = ExtResource(\"1_rdq5q\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_skull.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c3vq4c8n52xna\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_t23k4\"]\n\n[resource]\natlas = ExtResource(\"1_t23k4\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_white.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cprjvhwkb7x8s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_epgu2\"]\n\n[resource]\natlas = ExtResource(\"1_epgu2\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_with_emblem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bl47mcieckudx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_gq8cs\"]\n\n[resource]\natlas = ExtResource(\"1_gq8cs\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_with_gold_helmet.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://uro44tr4rh68\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_eax7d\"]\n\n[resource]\natlas = ExtResource(\"1_eax7d\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_wood.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwkgg1eg5cja4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_wql3l\"]\n\n[resource]\natlas = ExtResource(\"1_wql3l\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_wood_small.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvt6og0fsdldh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_yrwl4\"]\n\n[resource]\natlas = ExtResource(\"1_yrwl4\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/shields/shield_wood_small_glowing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dbh1hk6ctxei4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wty1fqppvwo4\" path=\"res://assets/icons/shields.png\" id=\"1_sqw0i\"]\n\n[resource]\natlas = ExtResource(\"1_sqw0i\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/spears/many_spears_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xiieqx6xitdo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://btgpo8wni6hc7\" path=\"res://assets/icons/spears.png\" id=\"1_amlp7\"]\n\n[resource]\natlas = ExtResource(\"1_amlp7\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/spears/many_spears_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cupmxlm2exwqg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://btgpo8wni6hc7\" path=\"res://assets/icons/spears.png\" id=\"1_l5dni\"]\n\n[resource]\natlas = ExtResource(\"1_l5dni\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/spears/spear_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://roh4gthqfw58\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://btgpo8wni6hc7\" path=\"res://assets/icons/spears.png\" id=\"1_e6o8p\"]\n\n[resource]\natlas = ExtResource(\"1_e6o8p\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/spears/spear_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://wvj2re0bs46j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://btgpo8wni6hc7\" path=\"res://assets/icons/spears.png\" id=\"1_s7ck1\"]\n\n[resource]\natlas = ExtResource(\"1_s7ck1\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/spears/spear_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ctwgx4e4hkilv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://btgpo8wni6hc7\" path=\"res://assets/icons/spears.png\" id=\"1_e8qbo\"]\n\n[resource]\natlas = ExtResource(\"1_e8qbo\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/statues/statue_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://18q45mv7chfu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1awjrjgaxq71\" path=\"res://assets/icons/statues.png\" id=\"1_mbb6p\"]\n\n[resource]\natlas = ExtResource(\"1_mbb6p\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/statues/statue_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cpmanl28tph1l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1awjrjgaxq71\" path=\"res://assets/icons/statues.png\" id=\"1_e187v\"]\n\n[resource]\natlas = ExtResource(\"1_e187v\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/statues/statue_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b41b0dib5s1s1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1awjrjgaxq71\" path=\"res://assets/icons/statues.png\" id=\"1_aob1q\"]\n\n[resource]\natlas = ExtResource(\"1_aob1q\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/statues/statue_dwarf_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c55lkuuikehxl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1awjrjgaxq71\" path=\"res://assets/icons/statues.png\" id=\"1_yosbj\"]\n\n[resource]\natlas = ExtResource(\"1_yosbj\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/statues/statue_dwarf_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://q3x3tdenfg3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1awjrjgaxq71\" path=\"res://assets/icons/statues.png\" id=\"1_qxxvb\"]\n\n[resource]\natlas = ExtResource(\"1_qxxvb\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/statues/statue_warrior.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfobe3epekxr7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1awjrjgaxq71\" path=\"res://assets/icons/statues.png\" id=\"1_ty67b\"]\n\n[resource]\natlas = ExtResource(\"1_ty67b\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6w66wcqs5prm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_xgycf\"]\n\n[resource]\natlas = ExtResource(\"1_xgycf\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://hs4wuufpvny0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_y4rd6\"]\n\n[resource]\natlas = ExtResource(\"1_y4rd6\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxq77co0q3ja7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_02twk\"]\n\n[resource]\natlas = ExtResource(\"1_02twk\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bxgkc7pylswh4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_qf18o\"]\n\n[resource]\natlas = ExtResource(\"1_qf18o\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dm7qkwmsagj67\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_gqay2\"]\n\n[resource]\natlas = ExtResource(\"1_gqay2\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bh57hqg7pb5sd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_hl3mu\"]\n\n[resource]\natlas = ExtResource(\"1_hl3mu\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/staff_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b81k6nypeq62g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_6qf7b\"]\n\n[resource]\natlas = ExtResource(\"1_6qf7b\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/wand_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c5bfiwlf5w54v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_ytbx3\"]\n\n[resource]\natlas = ExtResource(\"1_ytbx3\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/wand_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b41412cxhkmom\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_q2xhw\"]\n\n[resource]\natlas = ExtResource(\"1_q2xhw\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/wand_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b8tmf0p33baoa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_4oala\"]\n\n[resource]\natlas = ExtResource(\"1_4oala\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/wand_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b7fillsdkt7mh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_jaat1\"]\n\n[resource]\natlas = ExtResource(\"1_jaat1\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/wand_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://mka4lk57luyi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_yu2bw\"]\n\n[resource]\natlas = ExtResource(\"1_yu2bw\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/staves/wand_glowing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dic7c17mbif4e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cl7c26i3sw0e\" path=\"res://assets/icons/staves.png\" id=\"1_fkgmj\"]\n\n[resource]\natlas = ExtResource(\"1_fkgmj\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/greatsword_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c1en4n3mkpfxv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_bvj8e\"]\n\n[resource]\natlas = ExtResource(\"1_bvj8e\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/greatsword_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://71vi682rqd7j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_t5v0x\"]\n\n[resource]\natlas = ExtResource(\"1_t5v0x\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/greatsword_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dxcfnbi3fuftw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_jmjtr\"]\n\n[resource]\natlas = ExtResource(\"1_jmjtr\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/greatsword_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bjb4mx8w3cmqt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_3bymf\"]\n\n[resource]\natlas = ExtResource(\"1_3bymf\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/greatsword_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bfv81y5phsndb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_tghxg\"]\n\n[resource]\natlas = ExtResource(\"1_tghxg\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/sword_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfp1e08dq7tt3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_ob562\"]\n\n[resource]\natlas = ExtResource(\"1_ob562\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/sword_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cni0qkabmky0v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_rvo75\"]\n\n[resource]\natlas = ExtResource(\"1_rvo75\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/sword_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dp12sunjg2y7v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_f1hvq\"]\n\n[resource]\natlas = ExtResource(\"1_f1hvq\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/sword_swing_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b1jabsyei2yy1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_inevu\"]\n\n[resource]\natlas = ExtResource(\"1_inevu\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/swords/sword_swing_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bgbaf4jqca1ai\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d1wqk36oa6jix\" path=\"res://assets/icons/swords.png\" id=\"1_hkkak\"]\n\n[resource]\natlas = ExtResource(\"1_hkkak\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_1.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://14q4k0e8cj84\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_xcsis\"]\n\n\n[resource]\natlas = ExtResource(\"1_xcsis\")\nregion = Rect2(0, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_2.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dx2jrdgvac1jr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_vl2bd\"]\n\n\n[resource]\natlas = ExtResource(\"1_vl2bd\")\nregion = Rect2(64, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_3.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhe13fgmnl58t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_5gna3\"]\n\n\n[resource]\natlas = ExtResource(\"1_5gna3\")\nregion = Rect2(128, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_4.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0a5ahm6fq8ax\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_75fhh\"]\n\n\n[resource]\natlas = ExtResource(\"1_75fhh\")\nregion = Rect2(192, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_5.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dojc6ivbp6pkp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_q7hbb\"]\n\n\n[resource]\natlas = ExtResource(\"1_q7hbb\")\nregion = Rect2(256, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_6.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://p38rgpy0gool\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_x0upb\"]\n\n\n[resource]\natlas = ExtResource(\"1_x0upb\")\nregion = Rect2(0, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/common_7.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bcqiph4pi56qd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_8sy56\"]\n\n\n[resource]\natlas = ExtResource(\"1_8sy56\")\nregion = Rect2(384, 0, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_1.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b1fjnrycky08t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_pbuga\"]\n\n[resource]\natlas = ExtResource(\"1_pbuga\")\nregion = Rect2(0, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_2.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://br0n6ecchi117\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_v1n8h\"]\n\n\n[resource]\natlas = ExtResource(\"1_v1n8h\")\nregion = Rect2(64, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_3.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bdxlwr1y3o00s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_mgfqe\"]\n\n\n[resource]\natlas = ExtResource(\"1_mgfqe\")\nregion = Rect2(128, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_4.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ddq32iv31tmul\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_0x2es\"]\n\n\n[resource]\natlas = ExtResource(\"1_0x2es\")\nregion = Rect2(192, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_5.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dsqdlkhmw1odx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_84mbv\"]\n\n\n[resource]\natlas = ExtResource(\"1_84mbv\")\nregion = Rect2(256, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_6.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c1sogfbtqu1cq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_0t4yf\"]\n\n\n[resource]\natlas = ExtResource(\"1_0t4yf\")\nregion = Rect2(320, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/rare_7.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bc2wdx8gojcn0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_pyemm\"]\n\n\n[resource]\natlas = ExtResource(\"1_pyemm\")\nregion = Rect2(384, 128, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_1.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmom6j2800etv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_3tcpr\"]\n\n[resource]\natlas = ExtResource(\"1_3tcpr\")\nregion = Rect2(0, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_2.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c15cdus22l1xm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_p8x48\"]\n\n\n[resource]\natlas = ExtResource(\"1_p8x48\")\nregion = Rect2(64, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_3.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbcbck1y7duou\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_xeu4d\"]\n\n\n[resource]\natlas = ExtResource(\"1_xeu4d\")\nregion = Rect2(128, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_4.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://db1dyv752kvxn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_udkcc\"]\n\n\n[resource]\natlas = ExtResource(\"1_udkcc\")\nregion = Rect2(192, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_5.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://nxh41a4fpgpr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_rq4vw\"]\n\n\n[resource]\natlas = ExtResource(\"1_rq4vw\")\nregion = Rect2(256, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_6.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cb5p7kwk6by3a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_oip2k\"]\n\n\n[resource]\natlas = ExtResource(\"1_oip2k\")\nregion = Rect2(384, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/uncommon_7.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b1m70rb7mx6iq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_58x58\"]\n\n\n[resource]\natlas = ExtResource(\"1_58x58\")\nregion = Rect2(0, 64, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_1.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://vegvbfihp1f4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_0k7dj\"]\n\n\n[resource]\natlas = ExtResource(\"1_0k7dj\")\nregion = Rect2(0, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_2.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dsxyexm6fiwbb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_medgf\"]\n\n\n[resource]\natlas = ExtResource(\"1_medgf\")\nregion = Rect2(64, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_3.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cplcdaed06wgr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_vmo1f\"]\n\n\n[resource]\natlas = ExtResource(\"1_vmo1f\")\nregion = Rect2(128, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_4.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://tihcv7ag5u54\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_h2rbw\"]\n\n\n[resource]\natlas = ExtResource(\"1_h2rbw\")\nregion = Rect2(192, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_5.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cgx2py58rrb63\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_xvkl2\"]\n\n\n[resource]\natlas = ExtResource(\"1_xvkl2\")\nregion = Rect2(256, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_6.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ctl5vnpr8p3yq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_s06hb\"]\n\n\n[resource]\natlas = ExtResource(\"1_s06hb\")\nregion = Rect2(320, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tier_icons/unique_7.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://fld7uis4jcpr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"1_brcug\"]\n\n\n[resource]\natlas = ExtResource(\"1_brcug\")\nregion = Rect2(384, 192, 64, 64)\n"
  },
  {
    "path": "resources/icons/tower_icons/abandoned_pit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://btgwk6qdfvjpr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_1f2h2\"]\n\n\n[resource]\natlas = ExtResource(\"1_1f2h2\")\nregion = Rect2(640, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/abominable_snowman.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b7msnpghg33ei\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_d6xpi\"]\n\n\n[resource]\natlas = ExtResource(\"1_d6xpi\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/afflicted_obelisk.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cjjaq48n4oum1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_f5gwr\"]\n\n\n[resource]\natlas = ExtResource(\"1_f5gwr\")\nregion = Rect2(128, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ancient_energy_converter.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://0iub01fdfqc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_gl5pi\"]\n\n\n[resource]\natlas = ExtResource(\"1_gl5pi\")\nregion = Rect2(768, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/annoyed_tree.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://btth7yis1c1o3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_cvdlf\"]\n\n\n[resource]\natlas = ExtResource(\"1_cvdlf\")\nregion = Rect2(128, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/arcane_storm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dvxyutv37xt7n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_m45by\"]\n\n\n[resource]\natlas = ExtResource(\"1_m45by\")\nregion = Rect2(768, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/area_roaster.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnrjlne6fu3dp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ubpsy\"]\n\n\n[resource]\natlas = ExtResource(\"1_ubpsy\")\nregion = Rect2(256, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ash_geyser.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://da3mj8ten17d5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_aq25d\"]\n\n\n[resource]\natlas = ExtResource(\"1_aq25d\")\nregion = Rect2(256, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/astral_lantern.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://57vll02fn6ub\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_prd58\"]\n\n\n[resource]\natlas = ExtResource(\"1_prd58\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/astral_rift.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c40fs77nxjabg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_82ghu\"]\n\n\n[resource]\natlas = ExtResource(\"1_82ghu\")\nregion = Rect2(384, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/baby_plant.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bfke1sof2bng5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_wrpwb\"]\n\n\n[resource]\natlas = ExtResource(\"1_wrpwb\")\nregion = Rect2(128, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/baby_tuskin.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dk8sn1h5a3e17\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_m81bx\"]\n\n\n[resource]\natlas = ExtResource(\"1_m81bx\")\nregion = Rect2(0, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ball_lightning_accelerator.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bjix137ahg8b6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_lb4th\"]\n\n\n[resource]\natlas = ExtResource(\"1_lb4th\")\nregion = Rect2(640, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/basic_knowledge.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cpb51kqlgymm4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_akc1a\"]\n\n\n[resource]\natlas = ExtResource(\"1_akc1a\")\nregion = Rect2(384, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/black_dragon_roost.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwe7v6uhpen4s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_sc3jj\"]\n\n\n[resource]\natlas = ExtResource(\"1_sc3jj\")\nregion = Rect2(512, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/black_rock_totem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cts2q1h7oojeg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_dpac6\"]\n\n\n[resource]\natlas = ExtResource(\"1_dpac6\")\nregion = Rect2(256, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/bomb_turret.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c8rafdltdowfe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_oqrhw\"]\n\n\n[resource]\natlas = ExtResource(\"1_oqrhw\")\nregion = Rect2(640, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/bone_shrine.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://rkixve2vjvpd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_hcq4a\"]\n\n\n[resource]\natlas = ExtResource(\"1_hcq4a\")\nregion = Rect2(512, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/bonk_the_living_mountain.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://djjgggccjysco\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4ikgs\"]\n\n\n[resource]\natlas = ExtResource(\"1_4ikgs\")\nregion = Rect2(128, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/broken_cage.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwvxmv4hnromm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_lphue\"]\n\n\n[resource]\natlas = ExtResource(\"1_lphue\")\nregion = Rect2(512, 896, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/broken_circle_of_wind.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bhfn6vlvj7alx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_bhxcf\"]\n\n\n[resource]\natlas = ExtResource(\"1_bhxcf\")\nregion = Rect2(768, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/broken_fire_pit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://e8dj6sewl2tw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_0bi7p\"]\n\n[resource]\natlas = ExtResource(\"1_0bi7p\")\nregion = Rect2(256, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/broken_lightning_rod.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b0j0d6nr53oef\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_g8ks6\"]\n\n[resource]\natlas = ExtResource(\"1_g8ks6\")\nregion = Rect2(768, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/bronze_dragon_roost.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://coyaejfkdlg10\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_5eyru\"]\n\n\n[resource]\natlas = ExtResource(\"1_5eyru\")\nregion = Rect2(640, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/buried_soul.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqqcfvhvla2xe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3q8ne\"]\n\n\n[resource]\natlas = ExtResource(\"1_3q8ne\")\nregion = Rect2(512, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/burning_watchtower.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://02tc10lc4p1a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_inhch\"]\n\n\n[resource]\natlas = ExtResource(\"1_inhch\")\nregion = Rect2(256, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/burrow.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhpk1epaqltdi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_bff27\"]\n\n\n[resource]\natlas = ExtResource(\"1_bff27\")\nregion = Rect2(640, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/caged_fire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://8dijjoeuxnol\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_fwpcf\"]\n\n\n[resource]\natlas = ExtResource(\"1_fwpcf\")\nregion = Rect2(256, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cenarion.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dw3iafrt034y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_r8ktg\"]\n\n\n[resource]\natlas = ExtResource(\"1_r8ktg\")\nregion = Rect2(128, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/chaining_storm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bif2dbfxjfp7k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xoi08\"]\n\n\n[resource]\natlas = ExtResource(\"1_xoi08\")\nregion = Rect2(768, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/chaos_warlock.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bhxpqyoenlaqg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_rmq7o\"]\n\n\n[resource]\natlas = ExtResource(\"1_rmq7o\")\nregion = Rect2(512, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/charged_obelisk.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://evhd1j3iuogl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ntr5w\"]\n\n\n[resource]\natlas = ExtResource(\"1_ntr5w\")\nregion = Rect2(768, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/chilled_spire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cj8qvnl3j7r5v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_5yagq\"]\n\n\n[resource]\natlas = ExtResource(\"1_5yagq\")\nregion = Rect2(0, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cloud_warrior.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://2sl21u525i8b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_71c4q\"]\n\n\n[resource]\natlas = ExtResource(\"1_71c4q\")\nregion = Rect2(768, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cloudy_temple_of_absorption.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqjkldk8fnaid\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_46y06\"]\n\n\n[resource]\natlas = ExtResource(\"1_46y06\")\nregion = Rect2(768, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/coconut_sapling.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1tuun3vcl8ix\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4nh87\"]\n\n\n[resource]\natlas = ExtResource(\"1_4nh87\")\nregion = Rect2(128, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/coin_machine.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbp831hnrnu0s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_18rwh\"]\n\n\n[resource]\natlas = ExtResource(\"1_18rwh\")\nregion = Rect2(640, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cold_obelisk.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cixm6e7xb2h6r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_cmkp3\"]\n\n\n[resource]\natlas = ExtResource(\"1_cmkp3\")\nregion = Rect2(0, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cold_troll.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://o0xqp7kabxq5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_nuvu5\"]\n\n\n[resource]\natlas = ExtResource(\"1_nuvu5\")\nregion = Rect2(0, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/contraption.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6nbo3jq3hal3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_i4ay8\"]\n\n[resource]\natlas = ExtResource(\"1_i4ay8\")\nregion = Rect2(640, 2048, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/crimson_wyrm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dlv7wlp53fo00\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_2m0gx\"]\n\n\n[resource]\natlas = ExtResource(\"1_2m0gx\")\nregion = Rect2(256, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cruel_fire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3j66y82wj84v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_y4mhl\"]\n\n\n[resource]\natlas = ExtResource(\"1_y4mhl\")\nregion = Rect2(256, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cursed_grounds.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cx5euswmhr1n6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_dkvqk\"]\n\n\n[resource]\natlas = ExtResource(\"1_dkvqk\")\nregion = Rect2(512, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/cute_small_spider.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bh1vuw3e7cxqj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_kka4m\"]\n\n\n[resource]\natlas = ExtResource(\"1_kka4m\")\nregion = Rect2(128, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dark_battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://rwxiktawm52b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xj3e8\"]\n\n\n[resource]\natlas = ExtResource(\"1_xj3e8\")\nregion = Rect2(512, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dark_fire_pit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c8orps7ybd5iw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_culkj\"]\n\n\n[resource]\natlas = ExtResource(\"1_culkj\")\nregion = Rect2(512, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/death_knight.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bcf3hrdayvuhr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_cbv0s\"]\n\n\n[resource]\natlas = ExtResource(\"1_cbv0s\")\nregion = Rect2(512, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dimensional_flux_collector.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2ml5dup2k6c2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_y70fn\"]\n\n\n[resource]\natlas = ExtResource(\"1_y70fn\")\nregion = Rect2(768, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dragon_sorcerer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dkk13bsf8bc7n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3kiu5\"]\n\n\n[resource]\natlas = ExtResource(\"1_3kiu5\")\nregion = Rect2(256, 4608, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/drake_whisperer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cqywbe64j2hle\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_q1nev\"]\n\n\n[resource]\natlas = ExtResource(\"1_q1nev\")\nregion = Rect2(384, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dreadlord.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://rtcjb88frm36\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_42v06\"]\n\n\n[resource]\natlas = ExtResource(\"1_42v06\")\nregion = Rect2(512, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dutchmans_grave.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://fkwicow6v0qa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_td1ej\"]\n\n\n[resource]\natlas = ExtResource(\"1_td1ej\")\nregion = Rect2(512, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/dwarven_forgery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://obnuuou4qpi5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_52iir\"]\n\n\n[resource]\natlas = ExtResource(\"1_52iir\")\nregion = Rect2(640, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ebonfrost_crystal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b6a02oold0qud\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_vbfep\"]\n\n\n[resource]\natlas = ExtResource(\"1_vbfep\")\nregion = Rect2(0, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/embershell_turtle_hatchling.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://t7qt1dybabdq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_1icbl\"]\n\n\n[resource]\natlas = ExtResource(\"1_1icbl\")\nregion = Rect2(256, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/energy_junction.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwvyt5jfls8xq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_8dxje\"]\n\n\n[resource]\natlas = ExtResource(\"1_8dxje\")\nregion = Rect2(640, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/essence_of_fury.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cj463d83oa61t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4dstb\"]\n\n\n[resource]\natlas = ExtResource(\"1_4dstb\")\nregion = Rect2(512, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/felweed.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bamj6uhmg0x37\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_j3pg0\"]\n\n\n[resource]\natlas = ExtResource(\"1_j3pg0\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/fenced_flames.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://clju7f121l2ui\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3uhm6\"]\n\n[resource]\natlas = ExtResource(\"1_3uhm6\")\nregion = Rect2(256, 2048, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/fiery_dog.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://by013g00loihl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4gl1w\"]\n\n\n[resource]\natlas = ExtResource(\"1_4gl1w\")\nregion = Rect2(256, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/fiery_pebble.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://di68vsu8wllp6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_a86gt\"]\n\n\n[resource]\natlas = ExtResource(\"1_a86gt\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/fire_battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c02t1l8gx37im\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_srv0r\"]\n\n\n[resource]\natlas = ExtResource(\"1_srv0r\")\nregion = Rect2(256, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/fire_star.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://qvdplv1psash\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_hnv6w\"]\n\n\n[resource]\natlas = ExtResource(\"1_hnv6w\")\nregion = Rect2(256, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/firestorm_cell.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://buv1sqwhmqba2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_auigh\"]\n\n\n[resource]\natlas = ExtResource(\"1_auigh\")\nregion = Rect2(256, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/fisherman.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bnb13uodxxrss\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_pvfq5\"]\n\n\n[resource]\natlas = ExtResource(\"1_pvfq5\")\nregion = Rect2(0, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/forest_archer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://elimg4cabnmm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_o1wcs\"]\n\n\n[resource]\natlas = ExtResource(\"1_o1wcs\")\nregion = Rect2(128, 3072, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/forest_protectress.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0rbdwtgb1xv7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_vmwa8\"]\n\n\n[resource]\natlas = ExtResource(\"1_vmwa8\")\nregion = Rect2(128, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/forest_troll.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://y2nfhtws5vwu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_45s1d\"]\n\n\n[resource]\natlas = ExtResource(\"1_45s1d\")\nregion = Rect2(128, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/frost_root.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cvkd03pux1lya\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_r188v\"]\n\n\n[resource]\natlas = ExtResource(\"1_r188v\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/frosty_rock.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://mrhq56t4fj7c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_l8k2v\"]\n\n\n[resource]\natlas = ExtResource(\"1_l8k2v\")\nregion = Rect2(0, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/frozen_well.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cyvtoiv1afw5n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3el2f\"]\n\n\n[resource]\natlas = ExtResource(\"1_3el2f\")\nregion = Rect2(0, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/garden_of_eden.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ck6ppqyc5peff\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xxxrg\"]\n\n\n[resource]\natlas = ExtResource(\"1_xxxrg\")\nregion = Rect2(128, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/gatling_gun.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bfo57gsnaaiw4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xuxjk\"]\n\n\n[resource]\natlas = ExtResource(\"1_xuxjk\")\nregion = Rect2(640, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/genis_sage.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dehnyydom8ghd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_7agq0\"]\n\n\n[resource]\natlas = ExtResource(\"1_7agq0\")\nregion = Rect2(0, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/geothermal_extractor.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cqiag67qif367\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_aeyio\"]\n\n\n[resource]\natlas = ExtResource(\"1_aeyio\")\nregion = Rect2(256, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/glaive_master.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b1uy6b6psusvo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_hyh67\"]\n\n\n[resource]\natlas = ExtResource(\"1_hyh67\")\nregion = Rect2(640, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/glowing_solar_orb.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ce1w01cjnd4l5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_6q4u1\"]\n\n\n[resource]\natlas = ExtResource(\"1_6q4u1\")\nregion = Rect2(384, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/gnoll_thunder_mage.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://t0c7g51mvbli\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_lw5dt\"]\n\n\n[resource]\natlas = ExtResource(\"1_lw5dt\")\nregion = Rect2(768, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/goblin_stronghold.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://qgcet36vs0of\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ll6cm\"]\n\n\n[resource]\natlas = ExtResource(\"1_ll6cm\")\nregion = Rect2(640, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/grab-o-bot.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bq020rt0kjkkc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xhwgp\"]\n\n\n[resource]\natlas = ExtResource(\"1_xhwgp\")\nregion = Rect2(640, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/green_dragon_roost.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cw74dv0dt8tl7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ays1w\"]\n\n\n[resource]\natlas = ExtResource(\"1_ays1w\")\nregion = Rect2(128, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/green_lightning.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbaow4pyqrgfy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ne7l0\"]\n\n\n[resource]\natlas = ExtResource(\"1_ne7l0\")\nregion = Rect2(768, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/greyfang.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bjbc0aakwd3na\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ahajc\"]\n\n[resource]\natlas = ExtResource(\"1_ahajc\")\nregion = Rect2(128, 4608, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/gryphon_rider.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bukrx06nups7h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_7ad51\"]\n\n\n[resource]\natlas = ExtResource(\"1_7ad51\")\nregion = Rect2(768, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/hall_of_souls.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c7f2il5so4yae\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4opf8\"]\n\n\n[resource]\natlas = ExtResource(\"1_4opf8\")\nregion = Rect2(512, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/harby.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmq0hma0p8k8a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_wr7jr\"]\n\n\n[resource]\natlas = ExtResource(\"1_wr7jr\")\nregion = Rect2(512, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/harpy_witch.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cf54vj1se14b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_voqnd\"]\n\n\n[resource]\natlas = ExtResource(\"1_voqnd\")\nregion = Rect2(768, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/haunted_rubble.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dplh71elp71ht\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_oib6l\"]\n\n\n[resource]\natlas = ExtResource(\"1_oib6l\")\nregion = Rect2(512, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/healing_obelisk.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bu1bvs1rrvjo3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_16sk1\"]\n\n\n[resource]\natlas = ExtResource(\"1_16sk1\")\nregion = Rect2(384, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/helicopter_zone.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvu8xgf2nh13n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_shbkg\"]\n\n[resource]\natlas = ExtResource(\"1_shbkg\")\nregion = Rect2(640, 4736, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/hell_bat.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bc3goalcjh2lb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xfe8f\"]\n\n\n[resource]\natlas = ExtResource(\"1_xfe8f\")\nregion = Rect2(512, 3072, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/holy_energy.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bv61bkpicgfsh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_587g1\"]\n\n\n[resource]\natlas = ExtResource(\"1_587g1\")\nregion = Rect2(384, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ice_battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://pepvxbf57cim\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_v37l3\"]\n\n\n[resource]\natlas = ExtResource(\"1_v37l3\")\nregion = Rect2(0, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/icy_core.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cdfm58pqnq12n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_20sje\"]\n\n\n[resource]\natlas = ExtResource(\"1_20sje\")\nregion = Rect2(0, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/icy_skulls.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ciocf5fspfh4m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ci8db\"]\n\n\n[resource]\natlas = ExtResource(\"1_ci8db\")\nregion = Rect2(0, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/icy_spirit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://byj70aiu2ss8j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_qqytg\"]\n\n\n[resource]\natlas = ExtResource(\"1_qqytg\")\nregion = Rect2(0, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/igloo.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dgiu6lh6pemjk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_u27nk\"]\n\n\n[resource]\natlas = ExtResource(\"1_u27nk\")\nregion = Rect2(0, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/inexperienced_huntress.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c20xxiqp4cn3u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_nqqpv\"]\n\n\n[resource]\natlas = ExtResource(\"1_nqqpv\")\nregion = Rect2(128, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/inflamed_stone.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bli0lftlfmwws\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_txcyi\"]\n\n\n[resource]\natlas = ExtResource(\"1_txcyi\")\nregion = Rect2(256, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/initiate_elementalist.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://hgewcl13l1jj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_rkx8s\"]\n\n\n[resource]\natlas = ExtResource(\"1_rkx8s\")\nregion = Rect2(384, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/it.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c6yl3qfw6ae6a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_h8j5r\"]\n\n\n[resource]\natlas = ExtResource(\"1_h8j5r\")\nregion = Rect2(512, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/jungle_stalker.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://co0of1fy7kr1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_fob34\"]\n\n\n[resource]\natlas = ExtResource(\"1_fob34\")\nregion = Rect2(128, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/kraken.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dkx0ty662xum2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_eo0hm\"]\n\n[resource]\natlas = ExtResource(\"1_eo0hm\")\nregion = Rect2(512, 5120, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_astral_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dcq5tsbahpmkg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_pey2x\"]\n\n\n[resource]\natlas = ExtResource(\"1_pey2x\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_dark_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bt0dbcxppydyl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_5u1ar\"]\n\n\n[resource]\natlas = ExtResource(\"1_5u1ar\")\nregion = Rect2(512, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_elemental_ghost.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://h6ss0mg1d4ue\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_namax\"]\n\n\n[resource]\natlas = ExtResource(\"1_namax\")\nregion = Rect2(256, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_flamy_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ddhd8am7ebqlk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_76xcb\"]\n\n\n[resource]\natlas = ExtResource(\"1_76xcb\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_ice_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c2fuqgvcwurd8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_kwelb\"]\n\n\n[resource]\natlas = ExtResource(\"1_kwelb\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_iron_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b0cvl7ota8rxq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_qf18r\"]\n\n\n[resource]\natlas = ExtResource(\"1_qf18r\")\nregion = Rect2(640, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_natural_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d258qbljc5daa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_qprop\"]\n\n\n[resource]\natlas = ExtResource(\"1_qprop\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_priest.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c464hmp5as6do\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_x7hqx\"]\n\n\n[resource]\natlas = ExtResource(\"1_x7hqx\")\nregion = Rect2(384, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_skeletal_mage.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://7ejgsaltv1ii\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_yxoix\"]\n\n\n[resource]\natlas = ExtResource(\"1_yxoix\")\nregion = Rect2(512, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_storm_defender.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dmxvlp64pva2u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_m2fqs\"]\n\n\n[resource]\natlas = ExtResource(\"1_m2fqs\")\nregion = Rect2(768, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lesser_wolves_den.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2yid8sxgs1na\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_a335e\"]\n\n\n[resource]\natlas = ExtResource(\"1_a335e\")\nregion = Rect2(128, 2176, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/library_of_alexandria.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://4ydpkp8pod4a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_60cyt\"]\n\n\n[resource]\natlas = ExtResource(\"1_60cyt\")\nregion = Rect2(384, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lich_king.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ccpfmub6uw5se\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_g4dd3\"]\n\n\n[resource]\natlas = ExtResource(\"1_g4dd3\")\nregion = Rect2(0, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lightning_eye.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://gwg4s5j1dtx1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_mwy24\"]\n\n\n[resource]\natlas = ExtResource(\"1_mwy24\")\nregion = Rect2(768, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lightning_generator.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dx205ox2140ql\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_2mw1q\"]\n\n\n[resource]\natlas = ExtResource(\"1_2mw1q\")\nregion = Rect2(768, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lightning_totem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://fhi83mblgg7v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_l2m6p\"]\n\n\n[resource]\natlas = ExtResource(\"1_l2m6p\")\nregion = Rect2(768, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/little_phoenix.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dlb5bniqdse1d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_bpook\"]\n\n\n[resource]\natlas = ExtResource(\"1_bpook\")\nregion = Rect2(256, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/living_volcano.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bnoe0v4lxnu42\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_p0m00\"]\n\n\n[resource]\natlas = ExtResource(\"1_p0m00\")\nregion = Rect2(256, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lunar_emitter.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bipexwjqa1awp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_rh8fj\"]\n\n\n[resource]\natlas = ExtResource(\"1_rh8fj\")\nregion = Rect2(512, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/lunar_sentinel.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwvvm01epf0gw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_q8lcb\"]\n\n\n[resource]\natlas = ExtResource(\"1_q8lcb\")\nregion = Rect2(384, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/magic_battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2w6wyec3ivj8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_v74c6\"]\n\n\n[resource]\natlas = ExtResource(\"1_v74c6\")\nregion = Rect2(384, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/magic_mushroom.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://s3byhvxl1y2t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3ohcw\"]\n\n\n[resource]\natlas = ExtResource(\"1_3ohcw\")\nregion = Rect2(128, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/magna_warrior.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://deuq56laycat4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_qmmtm\"]\n\n\n[resource]\natlas = ExtResource(\"1_qmmtm\")\nregion = Rect2(0, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/mana-touched_drake.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbgiyaxr0thji\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_prccv\"]\n\n\n[resource]\natlas = ExtResource(\"1_prccv\")\nregion = Rect2(384, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/marine.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://boo8d51ojiaj2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_nyn8i\"]\n\n\n[resource]\natlas = ExtResource(\"1_nyn8i\")\nregion = Rect2(640, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/meteor_totem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://4efgdwwaascf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_i0fdt\"]\n\n\n[resource]\natlas = ExtResource(\"1_i0fdt\")\nregion = Rect2(256, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/militia_watchtower.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c6sfst0o0hkhl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_e7avw\"]\n\n\n[resource]\natlas = ExtResource(\"1_e7avw\")\nregion = Rect2(640, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/miner.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dgobhnn8rbs46\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_gbglq\"]\n\n\n[resource]\natlas = ExtResource(\"1_gbglq\")\nregion = Rect2(640, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/minor_magic_ruin.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dtuhyued54ao2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_27ysn\"]\n\n\n[resource]\natlas = ExtResource(\"1_27ysn\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/mister_fireflies.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cw7mj5ckmqx7r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_o13nd\"]\n\n[resource]\natlas = ExtResource(\"1_o13nd\")\nregion = Rect2(384, 5120, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/monolith_of_chaos.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://yey6wpc3vc58\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_32t64\"]\n\n\n[resource]\natlas = ExtResource(\"1_32t64\")\nregion = Rect2(512, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/morphling.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://3mt217n53ii6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_lqv5a\"]\n\n\n[resource]\natlas = ExtResource(\"1_lqv5a\")\nregion = Rect2(128, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/mossy_acid_sprayer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dxkidlwsvcp5m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_11gw5\"]\n\n\n[resource]\natlas = ExtResource(\"1_11gw5\")\nregion = Rect2(640, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/mud_golem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cqnvumlbo2mxy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_atpdw\"]\n\n\n[resource]\natlas = ExtResource(\"1_atpdw\")\nregion = Rect2(128, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/nature_sprites.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqndjwrwtb1td\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_hxex2\"]\n\n\n[resource]\natlas = ExtResource(\"1_hxex2\")\nregion = Rect2(128, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/necromantic_altar.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cbig2if41wb4n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_m2swg\"]\n\n\n[resource]\natlas = ExtResource(\"1_m2swg\")\nregion = Rect2(512, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/nortrom_the_silencer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2sbys74x55l2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_8xasa\"]\n\n\n[resource]\natlas = ExtResource(\"1_8xasa\")\nregion = Rect2(384, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/nuclear_missile_launcher.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://f31oqlcrf41t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_sy0ci\"]\n\n\n[resource]\natlas = ExtResource(\"1_sy0ci\")\nregion = Rect2(640, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/obelisk_of_fortuity.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhblrxave2k52\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_0nwdj\"]\n\n[resource]\natlas = ExtResource(\"1_0nwdj\")\nregion = Rect2(640, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/owl_of_wisdom.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dnufr47hldolg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_pv6s5\"]\n\n\n[resource]\natlas = ExtResource(\"1_pv6s5\")\nregion = Rect2(384, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/particle_accelerator.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cl54db4rwr8m0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_gp27q\"]\n\n\n[resource]\natlas = ExtResource(\"1_gp27q\")\nregion = Rect2(640, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/phantom.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpy1e8k0b2em4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_pjphu\"]\n\n\n[resource]\natlas = ExtResource(\"1_pjphu\")\nregion = Rect2(768, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/plagued_crypt.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bjn8rmsumvg5g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_op216\"]\n\n\n[resource]\natlas = ExtResource(\"1_op216\")\nregion = Rect2(512, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/planar_gate.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b624vtsjkhv2w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_5e25t\"]\n\n\n[resource]\natlas = ExtResource(\"1_5e25t\")\nregion = Rect2(384, 3712, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/poison_battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dltv2evsw1s1v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_vkjvx\"]\n\n\n[resource]\natlas = ExtResource(\"1_vkjvx\")\nregion = Rect2(128, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/polar_bear_cub.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://k6k281leuc1h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ue7ts\"]\n\n\n[resource]\natlas = ExtResource(\"1_ue7ts\")\nregion = Rect2(0, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/portal_to_swine_purgatory.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3v0i5tvwqssu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_dm2ae\"]\n\n[resource]\natlas = ExtResource(\"1_dm2ae\")\nregion = Rect2(256, 3072, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/prince_of_lightning.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c0el2q8nom4dl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_lh1jc\"]\n\n\n[resource]\natlas = ExtResource(\"1_lh1jc\")\nregion = Rect2(768, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/princess_of_light.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cq16m5glbv36p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_vgknv\"]\n\n\n[resource]\natlas = ExtResource(\"1_vgknv\")\nregion = Rect2(384, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/razorboar_thornweaver.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://svq7qnfddj8v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_u4u5j\"]\n\n\n[resource]\natlas = ExtResource(\"1_u4u5j\")\nregion = Rect2(128, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/red_ball_lightning.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cb5msl88opear\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_re6mb\"]\n\n\n[resource]\natlas = ExtResource(\"1_re6mb\")\nregion = Rect2(768, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/regenerating_well.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://crafawpw8svdo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_e1kdt\"]\n\n\n[resource]\natlas = ExtResource(\"1_e1kdt\")\nregion = Rect2(128, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/rooted_chasm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://kmnyccnlyq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_1kv6m\"]\n\n\n[resource]\natlas = ExtResource(\"1_1kv6m\")\nregion = Rect2(128, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/rotted_flashing_grave.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bc35mu605twwa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xb124\"]\n\n\n[resource]\natlas = ExtResource(\"1_xb124\")\nregion = Rect2(768, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/rowing_boat.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3x6mfc1up3vs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_obdmt\"]\n\n\n[resource]\natlas = ExtResource(\"1_obdmt\")\nregion = Rect2(640, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ruined_monolith.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cplqhihhedsxc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_50lfs\"]\n\n\n[resource]\natlas = ExtResource(\"1_50lfs\")\nregion = Rect2(768, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ruined_storm_cap.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://casebnwebibm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_rvghf\"]\n\n[resource]\natlas = ExtResource(\"1_rvghf\")\nregion = Rect2(768, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ruined_sun_pedestal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bc7uwi8qvelhk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_vi0wh\"]\n\n\n[resource]\natlas = ExtResource(\"1_vi0wh\")\nregion = Rect2(384, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ruined_wind_tower.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c52nw60350x1n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_bsjmj\"]\n\n\n[resource]\natlas = ExtResource(\"1_bsjmj\")\nregion = Rect2(768, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/rundown_iron_sentry.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b2s2x2imqrkt4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_u25wh\"]\n\n\n[resource]\natlas = ExtResource(\"1_u25wh\")\nregion = Rect2(640, 3072, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sacred_altar.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bk6mp56c22xol\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ji3fu\"]\n\n\n[resource]\natlas = ExtResource(\"1_ji3fu\")\nregion = Rect2(128, 3328, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sacrificial_lamb.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xdcevndx7tq2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_13sh7\"]\n\n\n[resource]\natlas = ExtResource(\"1_13sh7\")\nregion = Rect2(512, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/safirons_cold_grave.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c24jbivhkew35\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_a0mgo\"]\n\n\n[resource]\natlas = ExtResource(\"1_a0mgo\")\nregion = Rect2(0, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/scales.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ctah61hsixunr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4i8ea\"]\n\n\n[resource]\natlas = ExtResource(\"1_4i8ea\")\nregion = Rect2(768, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sea_turtle.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ciihp1igkm3rs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_tc8pp\"]\n\n\n[resource]\natlas = ExtResource(\"1_tc8pp\")\nregion = Rect2(0, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/servant_of_the_twin_flames.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cl1katqvjwgjc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_c2oje\"]\n\n\n[resource]\natlas = ExtResource(\"1_c2oje\")\nregion = Rect2(256, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sewer_connection.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dfs7tldhncouv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_kl7ed\"]\n\n\n[resource]\natlas = ExtResource(\"1_kl7ed\")\nregion = Rect2(640, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/shadow.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bya1fwg3o01gm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_23gub\"]\n\n\n[resource]\natlas = ExtResource(\"1_23gub\")\nregion = Rect2(512, 4608, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/shaman.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cym0rlxdnttnm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_wh2i3\"]\n\n\n[resource]\natlas = ExtResource(\"1_wh2i3\")\nregion = Rect2(256, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/shard_of_souls.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1lmub0o5ro0e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_tofgj\"]\n\n\n[resource]\natlas = ExtResource(\"1_tofgj\")\nregion = Rect2(512, 3200, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/silver_knight.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bkf5sbtf526b1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_dugxb\"]\n\n\n[resource]\natlas = ExtResource(\"1_dugxb\")\nregion = Rect2(640, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/skink.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpm3bun43gq7g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4gt7n\"]\n\n\n[resource]\natlas = ExtResource(\"1_4gt7n\")\nregion = Rect2(128, 1408, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_brazier.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bqyv1jcxx7yhs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ajqi5\"]\n\n\n[resource]\natlas = ExtResource(\"1_ajqi5\")\nregion = Rect2(256, 1280, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_bug_nest.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dv3vg18dfkwku\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_577i2\"]\n\n\n[resource]\natlas = ExtResource(\"1_577i2\")\nregion = Rect2(512, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_cactus.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cb6jve266lpw8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_mkev0\"]\n\n[resource]\natlas = ExtResource(\"1_mkev0\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_fire_sprayer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cylvh1fh8xfpb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_q086y\"]\n\n\n[resource]\natlas = ExtResource(\"1_q086y\")\nregion = Rect2(256, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_frost_fire.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cvxulouh77olu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_tbgqw\"]\n\n\n[resource]\natlas = ExtResource(\"1_tbgqw\")\nregion = Rect2(512, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_frozen_mushroom.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dykiyc8ykqrk4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_s6nsk\"]\n\n\n[resource]\natlas = ExtResource(\"1_s6nsk\")\nregion = Rect2(0, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_ice_mine.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dd1wcoks67kp0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_eab03\"]\n\n\n[resource]\natlas = ExtResource(\"1_eab03\")\nregion = Rect2(0, 1024, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_light.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://8xuy1w0y7sui\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_hkxmp\"]\n\n\n[resource]\natlas = ExtResource(\"1_hkxmp\")\nregion = Rect2(384, 2048, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_pocket_rocket.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dwbnxyrbri5b0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_a4844\"]\n\n\n[resource]\natlas = ExtResource(\"1_a4844\")\nregion = Rect2(640, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_ray_blaster.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2dlbltx0vqhg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_k8mgw\"]\n\n\n[resource]\natlas = ExtResource(\"1_k8mgw\")\nregion = Rect2(640, 1536, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_serpent_ward.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cqbo8wxeq7qvd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_wkkjs\"]\n\n\n[resource]\natlas = ExtResource(\"1_wkkjs\")\nregion = Rect2(384, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/small_torch.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c4ew5wb32joqv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_8ln0p\"]\n\n\n[resource]\natlas = ExtResource(\"1_8ln0p\")\nregion = Rect2(256, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sniper.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bp8vcs4w5gy4p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_4ptrd\"]\n\n\n[resource]\natlas = ExtResource(\"1_4ptrd\")\nregion = Rect2(640, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/snowy_pebble.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://tjdldj1cq2r3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_hat81\"]\n\n\n[resource]\natlas = ExtResource(\"1_hat81\")\nregion = Rect2(0, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/solar_collector.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bj0vj01mi5ppr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ly1tf\"]\n\n\n[resource]\natlas = ExtResource(\"1_ly1tf\")\nregion = Rect2(640, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/solar_emitter.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2ms4xsvxra2g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ulbja\"]\n\n\n[resource]\natlas = ExtResource(\"1_ulbja\")\nregion = Rect2(384, 2688, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sorceress.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bmdqejjw3vf2d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_637ae\"]\n\n\n[resource]\natlas = ExtResource(\"1_637ae\")\nregion = Rect2(384, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/soul_vault.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://fhmes0nppo2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ey74u\"]\n\n\n[resource]\natlas = ExtResource(\"1_ey74u\")\nregion = Rect2(512, 4864, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/soulflame_device.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://83udpyuo3s68\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_twywt\"]\n\n\n[resource]\natlas = ExtResource(\"1_twywt\")\nregion = Rect2(512, 4736, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/spell_collector.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://vmmvfwvg5khv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_a42kn\"]\n\n\n[resource]\natlas = ExtResource(\"1_a42kn\")\nregion = Rect2(768, 3072, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/spider_queen.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bgufxpki0x4oq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_0s5px\"]\n\n\n[resource]\natlas = ExtResource(\"1_0s5px\")\nregion = Rect2(512, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/star_gazer.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cnnmf7v1dt0mg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_gpkil\"]\n\n\n[resource]\natlas = ExtResource(\"1_gpkil\")\nregion = Rect2(384, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/storm_battery.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxla403swprad\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_e7glr\"]\n\n\n[resource]\natlas = ExtResource(\"1_e7glr\")\nregion = Rect2(768, 2304, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/storm_coil.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ch5abhjastlat\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_38mnu\"]\n\n\n[resource]\natlas = ExtResource(\"1_38mnu\")\nregion = Rect2(768, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/storm_focus.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cxj5t1smsj381\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_0pakq\"]\n\n\n[resource]\natlas = ExtResource(\"1_0pakq\")\nregion = Rect2(768, 4608, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/stormy_dog.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ditjr5sbxayol\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_28kg3\"]\n\n\n[resource]\natlas = ExtResource(\"1_28kg3\")\nregion = Rect2(768, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/sun_crusader.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cgfomid6k07u4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_2bpak\"]\n\n\n[resource]\natlas = ExtResource(\"1_2bpak\")\nregion = Rect2(384, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/taita_the_hermit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b4fmjchp1tgy0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_1cd4n\"]\n\n\n[resource]\natlas = ExtResource(\"1_1cd4n\")\nregion = Rect2(0, 3456, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/teacher.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://op03b5e4ve37\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_x6jor\"]\n\n\n[resource]\natlas = ExtResource(\"1_x6jor\")\nregion = Rect2(384, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tentacle_spawn.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvnwiykuqbson\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_p7im8\"]\n\n\n[resource]\natlas = ExtResource(\"1_p7im8\")\nregion = Rect2(512, 640, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_conduit.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://btirku2kyewbk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_yhwo6\"]\n\n\n[resource]\natlas = ExtResource(\"1_yhwo6\")\nregion = Rect2(768, 4736, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_council_of_demons.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cliwaocrwyrgc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_gax6n\"]\n\n\n[resource]\natlas = ExtResource(\"1_gax6n\")\nregion = Rect2(512, 4992, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_fire_lord.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bgdwtcpwkky1c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_plaba\"]\n\n\n[resource]\natlas = ExtResource(\"1_plaba\")\nregion = Rect2(256, 4096, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_frozen_wyrm.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2q72kp10hsp0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_68t8s\"]\n\n\n[resource]\natlas = ExtResource(\"1_68t8s\")\nregion = Rect2(0, 3840, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_furnace.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dplr34lfjnky7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3svaw\"]\n\n\n[resource]\natlas = ExtResource(\"1_3svaw\")\nregion = Rect2(256, 4224, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_omnislasher.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://p2pqppdp4tl2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_xtlsf\"]\n\n\n[resource]\natlas = ExtResource(\"1_xtlsf\")\nregion = Rect2(256, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/the_steam_engine.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://y0772bn76jt8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_qrywr\"]\n\n\n[resource]\natlas = ExtResource(\"1_qrywr\")\nregion = Rect2(640, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/thief_apprentice.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cjpeb06i2tj6d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_fmulx\"]\n\n\n[resource]\natlas = ExtResource(\"1_fmulx\")\nregion = Rect2(512, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tidewater_stream.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://3i8lc5mf4kiv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_ebcwb\"]\n\n\n[resource]\natlas = ExtResource(\"1_ebcwb\")\nregion = Rect2(0, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/time_manipulator.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cfhuuokmdhb8v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3gr3v\"]\n\n\n[resource]\natlas = ExtResource(\"1_3gr3v\")\nregion = Rect2(384, 3968, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/timevault.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d1yy4q3w2qbav\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_y20it\"]\n\n\n[resource]\natlas = ExtResource(\"1_y20it\")\nregion = Rect2(384, 3584, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tiny_shrub.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://con45sfpg7pr3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_bn0ix\"]\n\n\n[resource]\natlas = ExtResource(\"1_bn0ix\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tiny_storm_lantern.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://28g2vw7f7bvh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_p807k\"]\n\n\n[resource]\natlas = ExtResource(\"1_p807k\")\nregion = Rect2(768, 1664, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tombstone.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpr4nqj21s53b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_44tns\"]\n\n\n[resource]\natlas = ExtResource(\"1_44tns\")\nregion = Rect2(512, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/trash_heap.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://lkasncoaxuxa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_eulrv\"]\n\n\n[resource]\natlas = ExtResource(\"1_eulrv\")\nregion = Rect2(640, 768, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tree_stump.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c4h2cslwmu85c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_2bwuy\"]\n\n[resource]\natlas = ExtResource(\"1_2bwuy\")\nregion = Rect2(128, 512, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/tundra_stalker.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://6psrtkdf23d8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_85s1n\"]\n\n\n[resource]\natlas = ExtResource(\"1_85s1n\")\nregion = Rect2(0, 1152, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/undisturbed_crypt.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cejd7uoev6xsu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_64mvo\"]\n\n\n[resource]\natlas = ExtResource(\"1_64mvo\")\nregion = Rect2(512, 2816, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/valor.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dne383jl807nh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_u0je2\"]\n\n\n[resource]\natlas = ExtResource(\"1_u0je2\")\nregion = Rect2(640, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/village_witch.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://p8seopn0pvwe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_r6ftx\"]\n\n\n[resource]\natlas = ExtResource(\"1_r6ftx\")\nregion = Rect2(512, 1920, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/void_drake.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cwpm5og72knbp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_8eitm\"]\n\n\n[resource]\natlas = ExtResource(\"1_8eitm\")\nregion = Rect2(512, 2560, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/vulshok_the_berserker.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c3of4u3efvcom\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_mmwia\"]\n\n\n[resource]\natlas = ExtResource(\"1_mmwia\")\nregion = Rect2(256, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/warrior_of_light.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://drtqthftpkkv2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_qwiyk\"]\n\n\n[resource]\natlas = ExtResource(\"1_qwiyk\")\nregion = Rect2(384, 2944, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/wild_warbeast.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://rsw8idwdnvkn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_3t3m5\"]\n\n\n[resource]\natlas = ExtResource(\"1_3t3m5\")\nregion = Rect2(128, 4480, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/witch_doctor.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c5q2gwcy1iv51\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_81ijk\"]\n\n\n[resource]\natlas = ExtResource(\"1_81ijk\")\nregion = Rect2(384, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/wooden_trap.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bo07t013y17xm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_6iihs\"]\n\n\n[resource]\natlas = ExtResource(\"1_6iihs\")\nregion = Rect2(640, 1792, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/xeno_research_facility.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b6wbtu0itrpgv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_14657\"]\n\n\n[resource]\natlas = ExtResource(\"1_14657\")\nregion = Rect2(640, 4608, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/ymir.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cgsc0ev2rrb4d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_8nf8y\"]\n\n\n[resource]\natlas = ExtResource(\"1_8nf8y\")\nregion = Rect2(0, 4352, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/young_northern_troll.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ds2jnuwu2yu0n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_uxf8l\"]\n\n\n[resource]\natlas = ExtResource(\"1_uxf8l\")\nregion = Rect2(0, 2432, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/zealot.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c1n1tq731b27p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_oy8ir\"]\n\n\n[resource]\natlas = ExtResource(\"1_oy8ir\")\nregion = Rect2(768, 3200, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_icons/zeus.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bjihjf02734fl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://de76st4td7ff1\" path=\"res://assets/icons/tower_icons_m.png\" id=\"1_nm1wl\"]\n\n\n[resource]\natlas = ExtResource(\"1_nm1wl\")\nregion = Rect2(768, 4864, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/ash_geyser_blue.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cjn6hkigx24vy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_bbgsw\"]\n\n[resource]\natlas = ExtResource(\"1_bbgsw\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/ash_geyser_green.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dhccvsj8ayl3l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_sqooi\"]\n\n[resource]\natlas = ExtResource(\"1_sqooi\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/ash_geyser_purple.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d22wus4f1tsiy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_qxjxc\"]\n\n[resource]\natlas = ExtResource(\"1_qxjxc\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/bonk_the_living_mountain_small.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ciitoyrxosdxm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_leuo4\"]\n\n[resource]\natlas = ExtResource(\"1_leuo4\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/forest_troll_small.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bgh2p5edcvk3u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_xsmxg\"]\n\n[resource]\natlas = ExtResource(\"1_xsmxg\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/meteor_totem_blue.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dpbm27qwysnv6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_k1kdl\"]\n\n[resource]\natlas = ExtResource(\"1_k1kdl\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/meteor_totem_purple.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ddkat6sw565op\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_uwjr3\"]\n\n[resource]\natlas = ExtResource(\"1_uwjr3\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/mossy_acid_sprayer_gray.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://pke0vh2ey1dt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_fina3\"]\n\n[resource]\natlas = ExtResource(\"1_fina3\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/mossy_acid_sprayer_red.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://22uwsktvbm1x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_f83oo\"]\n\n[resource]\natlas = ExtResource(\"1_f83oo\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/undisturbed_crypt_gold.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ynl4suy5850o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_mjh6a\"]\n\n[resource]\natlas = ExtResource(\"1_mjh6a\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/tower_variations/vulshok_the_berserker_blue.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b0380f4vevrx1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqf21oho5q27w\" path=\"res://assets/icons/tower_variations.png\" id=\"1_hoqda\"]\n\n[resource]\natlas = ExtResource(\"1_hoqda\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/claw_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://n2ydwtqx74r1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_oafdu\"]\n\n[resource]\natlas = ExtResource(\"1_oafdu\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/claw_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://te1w04jmkngs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_gmbma\"]\n\n[resource]\natlas = ExtResource(\"1_gmbma\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/claw_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cmoonjh0e5kjf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_ye85r\"]\n\n[resource]\natlas = ExtResource(\"1_ye85r\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/key_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://blmuohi33wqtk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_y0xi2\"]\n\n[resource]\natlas = ExtResource(\"1_y0xi2\")\nregion = Rect2(384, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/key_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ckycglhcigase\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_nuh5s\"]\n\n[resource]\natlas = ExtResource(\"1_nuh5s\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/key_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dk8k12qv423ab\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_xnwur\"]\n\n[resource]\natlas = ExtResource(\"1_xnwur\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cig4sp6okt1d1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_askwa\"]\n\n[resource]\natlas = ExtResource(\"1_askwa\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dpyls0ghlei1p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_3dys0\"]\n\n[resource]\natlas = ExtResource(\"1_3dys0\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://drr8pkfh3i5in\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_lp228\"]\n\n[resource]\natlas = ExtResource(\"1_lp228\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bw017uca7k7dv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_h8sli\"]\n\n[resource]\natlas = ExtResource(\"1_h8sli\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://1pr3u18ul2b8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_i4tun\"]\n\n[resource]\natlas = ExtResource(\"1_i4tun\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bi476leiki7a5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_dg4j5\"]\n\n[resource]\natlas = ExtResource(\"1_dg4j5\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_07.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c57mqbchpsiyq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_1f21e\"]\n\n[resource]\natlas = ExtResource(\"1_1f21e\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_08.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://4ntv7dv6c6vo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_w42b0\"]\n\n[resource]\natlas = ExtResource(\"1_w42b0\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_09.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://df1fycletuk3p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_k5wmr\"]\n\n[resource]\natlas = ExtResource(\"1_k5wmr\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/trinkets/trinket_10.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bordvpac3xqvn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brf81bkx3v35k\" path=\"res://assets/icons/trinkets.png\" id=\"1_waqu2\"]\n\n[resource]\natlas = ExtResource(\"1_waqu2\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/demon_emblem.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dt3enkx454u07\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_8auq1\"]\n\n[resource]\natlas = ExtResource(\"1_8auq1\")\nregion = Rect2(384, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/monster_hand.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://vl20m0llacix\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_n03vv\"]\n\n[resource]\natlas = ExtResource(\"1_n03vv\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b8qkka7i4vdpk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_xuwi3\"]\n\n[resource]\natlas = ExtResource(\"1_xuwi3\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dmyyap4xlfkb6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_weerj\"]\n\n[resource]\natlas = ExtResource(\"1_weerj\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b5tbf76t4tugq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_tbe40\"]\n\n[resource]\natlas = ExtResource(\"1_tbe40\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dmo72s68tds0r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_uesbv\"]\n\n[resource]\natlas = ExtResource(\"1_uesbv\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_05.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3utkoxxin7o6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_von8j\"]\n\n[resource]\natlas = ExtResource(\"1_von8j\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_06.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dydt0siqwp4e4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_7rjnt\"]\n\n[resource]\natlas = ExtResource(\"1_7rjnt\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_doll.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://f2ijlp2xyvog\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_46xpo\"]\n\n[resource]\natlas = ExtResource(\"1_46xpo\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_phazing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://xqwtsrbpu18b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_dlx2r\"]\n\n[resource]\natlas = ExtResource(\"1_dlx2r\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_wand_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bad05j6sydymx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_oaedd\"]\n\n[resource]\natlas = ExtResource(\"1_oaedd\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_wand_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d07ycj5rol3kd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_emcdv\"]\n\n[resource]\natlas = ExtResource(\"1_emcdv\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_wand_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://do8jh6sklt37l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_3hxr4\"]\n\n[resource]\natlas = ExtResource(\"1_3hxr4\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/undead/skull_wand_04.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b32vwnh5prc5l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cavgrswpec0v7\" path=\"res://assets/icons/undead.png\" id=\"1_h8n5f\"]\n\n[resource]\natlas = ExtResource(\"1_h8n5f\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/axe_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://7d8m3y0bajoc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_8iivx\"]\n\n[resource]\natlas = ExtResource(\"1_8iivx\")\nregion = Rect2(0, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/axe_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dogku0c45xwpd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_jpet2\"]\n\n[resource]\natlas = ExtResource(\"1_jpet2\")\nregion = Rect2(128, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/barbed_spike.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b6cej2k3kwo5o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_p8q7j\"]\n\n[resource]\natlas = ExtResource(\"1_p8q7j\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/glaive_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dxoyxe1nlguph\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_fiqtb\"]\n\n[resource]\natlas = ExtResource(\"1_fiqtb\")\nregion = Rect2(128, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/glaive_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d0ca5iqhcka7k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_dmn7t\"]\n\n[resource]\natlas = ExtResource(\"1_dmn7t\")\nregion = Rect2(256, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/glaive_03.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bvpyb5ftflrbu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_d80um\"]\n\n[resource]\natlas = ExtResource(\"1_d80um\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/mining_pick_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cvh0v5mvjv1us\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_nkt7p\"]\n\n[resource]\natlas = ExtResource(\"1_nkt7p\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/mining_pick_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dm1yh7y7wbqiw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_7rkxi\"]\n\n[resource]\natlas = ExtResource(\"1_7rkxi\")\nregion = Rect2(128, 256, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/trident_01.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dvnvuearlupts\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_rrvvv\"]\n\n[resource]\natlas = ExtResource(\"1_rrvvv\")\nregion = Rect2(256, 0, 128, 128)\n"
  },
  {
    "path": "resources/icons/weapons_misc/trident_02.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bl4u16tx3rd6d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwjw6jt0jadwx\" path=\"res://assets/icons/weapons_misc.png\" id=\"1_ysgr3\"]\n\n[resource]\natlas = ExtResource(\"1_ysgr3\")\nregion = Rect2(384, 0, 128, 128)\n"
  },
  {
    "path": "resources/misc/barrel.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://itq2i72y2h0w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8kaotwoawygm\" path=\"res://assets/tiles/barrels.png\" id=\"1_udos8\"]\n\n[resource]\natlas = ExtResource(\"1_udos8\")\nregion = Rect2(80, 122, 100, 83)\n"
  },
  {
    "path": "resources/misc/pulsing_dot.tres",
    "content": "[gd_resource type=\"AnimatedTexture\" load_steps=7 format=3 uid=\"uid://yn18gvcjmrkp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://uev086xwodkt\" path=\"res://assets/misc/circle_03.png\" id=\"1\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cxl665kwsrclr\" path=\"res://assets/misc/circle_05.png\" id=\"2\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dx62w7m5jucm5\" path=\"res://assets/misc/circle_04.png\" id=\"3\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dti6d2c71hvuh\" path=\"res://assets/misc/circle_02.png\" id=\"4\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dl05rggm0meke\" path=\"res://assets/misc/circle_01.png\" id=\"5\"]\n\n[sub_resource type=\"GDScript\" id=\"1\"]\nscript/source = \"extends AnimatedTexture\n\n\"\n\n[resource]\nframes = 5\nspeed_scale = 10.0\nframe_0/texture = ExtResource(\"2\")\nframe_1/texture = ExtResource(\"4\")\nframe_1/duration = 1.0\nframe_2/texture = ExtResource(\"1\")\nframe_2/duration = 1.0\nframe_3/texture = ExtResource(\"5\")\nframe_3/duration = 1.0\nframe_4/texture = ExtResource(\"3\")\nframe_4/duration = 1.0\nscript = SubResource(\"1\")\n"
  },
  {
    "path": "resources/shaders/foggy_camera.gdshader",
    "content": "shader_type canvas_item;\n\nuniform float vignette_intensity : hint_range(0.0, 1.0) = 0.4;\nuniform float vignette_opacity : hint_range(0.0, 1.0) = 0.5;\nuniform vec4 vignette_rgb : source_color = vec4(0.0, 0.0, 0.0, 1.0);\n\nuniform sampler2D screen_vec : hint_screen_texture;\n\nfloat vignette(vec2 uv){\n\tuv *= 1.0 - uv.xy;\n\tfloat vignette = uv.x * uv.y * 15.0;\n\treturn pow(vignette, vignette_intensity * vignette_opacity);\n}\n\nvoid fragment(){\n\tvec4 color = texture(screen_vec, SCREEN_UV);\n\tvec4 text = texture(TEXTURE, UV);\n\t\n\ttext.rgba *= (vignette_rgb.rgba);\n\ttext.rgba *= (1.0 - vignette(UV));\n\t\n\tCOLOR = vec4((text.rgb)*color.rgb,text.a);\n}"
  },
  {
    "path": "resources/shaders/glowing_outline.gdshader",
    "content": "shader_type canvas_item;\nrender_mode unshaded;\n\nuniform vec4 line_color : source_color = vec4(1);\nuniform float line_thickness : hint_range(0, 10) = 1.0;\n\nvoid fragment() {\n\tvec4 pixel_color = texture(TEXTURE, UV);\n\tif (pixel_color.a > 0.5) {\n\t\tdiscard;\n\t}\n\t\n\tvec2 size = TEXTURE_PIXEL_SIZE * line_thickness;\n\t\n\tfloat outline = texture(TEXTURE, UV + vec2(-size.x, 0)).a;\n\toutline += texture(TEXTURE, UV + vec2(0, size.y)).a;\n\toutline += texture(TEXTURE, UV + vec2(size.x, 0)).a;\n\toutline += texture(TEXTURE, UV + vec2(0, -size.y)).a;\n\toutline += texture(TEXTURE, UV + vec2(-size.x, size.y)).a;\n\toutline += texture(TEXTURE, UV + vec2(size.x, size.y)).a;\n\toutline += texture(TEXTURE, UV + vec2(-size.x, -size.y)).a;\n\toutline += texture(TEXTURE, UV + vec2(size.x, -size.y)).a;\n\toutline = min(outline, 1.0);\n\t\n\tvec4 color = texture(TEXTURE, UV);\n\tCOLOR = mix(color, line_color, outline - color.a);\n}"
  },
  {
    "path": "resources/shaders/glowing_outline_2.gdshader",
    "content": "shader_type canvas_item;\n\nuniform float max_line_width = 3.0;\nuniform float min_line_width = 0.0;\nuniform float freq = 10;\nuniform float block_size = 4.0;\nuniform vec4 outline_colour : source_color = vec4(0,0,0,1);\nuniform vec4 base_colour : source_color = vec4(0,0,0,1);\n\nconst float pi = 3.1415;\nconst int ang_res = 16;\n\n\nfloat hash(vec2 p, float s) {\n\treturn fract(35.1 * sin(dot(vec3(112.3, 459.2, 753.2), vec3(p, s))));\n}\n\nfloat noise(vec2 p, float s) {\n\tvec2 d = vec2(0, 1);\n\tvec2 b = floor(p);\n\tvec2 f = fract(p);\n\treturn mix(\n\t\tmix(hash(b + d.xx, s), hash(b + d.yx, s), f.x),\n\t\tmix(hash(b + d.xy, s), hash(b + d.yy, s), f.x), f.y);\n}\n\nfloat get_line_width(vec2 p, float s) {\n\tp /= block_size;\n\tfloat w = 0.0;\n\tfloat intensity = 1.0;\n\tfor (int i = 0; i < 3; i++) {\n\t\tw = mix(w, noise(p, s), intensity);\n\t\tp /= 2.0;\n\t\tintensity /= 2.0;\n\t}\n\t\n\treturn mix(max_line_width, min_line_width, w);\n}\n\nvoid fragment() {\n\n\tfloat alpha = 0.0;\n\tfloat timeStep = floor(TIME * freq);\n\tvec2 scale = TEXTURE_PIXEL_SIZE;\n\tscale *= get_line_width(UV / TEXTURE_PIXEL_SIZE, timeStep);\n\tfor (int i = 0; i < ang_res; i++) {\n\t\tfloat angle = 2.0 * pi * float(i) / float(ang_res);\n\t\tvec2 disp = scale * vec2(cos(angle), sin(angle));\n\t\talpha += texture(TEXTURE, UV + disp).a;\n\t}\n\t\n\tif ((alpha > 0.0) && (texture(TEXTURE, UV).a < 0.1)) {\n\t\tCOLOR = outline_colour;\n\t}\n\telse {\n\t\tCOLOR = texture(TEXTURE, UV);\n\t}\n\tif (texture(TEXTURE, UV).a > 0.1) {\n\t\tCOLOR = base_colour;\n\t}\n}"
  },
  {
    "path": "resources/shaders/saturation_burn.gdshader",
    "content": "shader_type canvas_item;\n\nuniform float vignette_intensity : hint_range(0.0, 2.0) = 0.5;\nuniform float edge_saturation : hint_range(0.0, 1.0) = 0.5;\nuniform sampler2D screen_vec : hint_screen_texture;\n\n\nvoid fragment() {\n    vec4 tex_color = texture(screen_vec, SCREEN_UV);\n\tfloat dist = distance(SCREEN_UV, vec2(0.5, 0.5));\n\tfloat vignette = smoothstep(0.0, vignette_intensity, dist);\n\n\tfloat desaturation = mix(1.0, edge_saturation, vignette);\n\tvec3 desaturated_color = mix(vec3(dot(tex_color.rgb, vec3(0.299, 0.587, 0.114))), tex_color.rgb, desaturation);\n\n\tCOLOR.rgb = desaturated_color;\n\tCOLOR.a = tex_color.a;\n}"
  },
  {
    "path": "resources/theme/common/rect_container_center_l.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://crr0tkfd2ggb8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cfgwdmgl12iia\" path=\"res://resources/ui_textures/rect_container_center_l.tres\" id=\"1_w7ymc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gjf4r\"]\natlas = ExtResource(\"1_w7ymc\")\n\n[resource]\ncontent_margin_left = 20.0\ncontent_margin_right = 20.0\ntexture = SubResource(\"AtlasTexture_gjf4r\")\ntexture_margin_left = 40.0\ntexture_margin_top = 40.0\ntexture_margin_right = 40.0\ntexture_margin_bottom = 40.0\nregion_rect = Rect2(1105, 367, 156, 176)\n"
  },
  {
    "path": "resources/theme/common/rect_container_l.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://vnjg5mo0nmg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://s4h31j7p5184\" path=\"res://resources/ui_textures/rect_container_l.tres\" id=\"1_w115j\"]\n\n[resource]\ntexture = ExtResource(\"1_w115j\")\ntexture_margin_left = 40.0\ntexture_margin_top = 40.0\ntexture_margin_right = 40.0\ntexture_margin_bottom = 40.0\nregion_rect = Rect2(1095, 180, 176, 178)\n"
  },
  {
    "path": "resources/theme/common/rect_container_m.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://cwmhuo2ppjfx2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"1_yu6dh\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"1_yu6dh\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 154)\n"
  },
  {
    "path": "resources/theme/common/rect_container_s.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://d1lgejw2sv1ip\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_flgcy\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1v3kw\"]\natlas = ExtResource(\"1_flgcy\")\nregion = Rect2(853, 74, 48, 48)\n\n[resource]\ncontent_margin_left = 0.0\ncontent_margin_top = 0.0\ncontent_margin_right = 0.0\ncontent_margin_bottom = 0.0\ntexture = SubResource(\"AtlasTexture_1v3kw\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 11.0\ntexture_margin_bottom = 11.0\nmodulate_color = Color(0.72549, 0.72549, 0.72549, 1)\n"
  },
  {
    "path": "resources/theme/common/tab_container_m.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://0s5reeigcpqf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"1_se5rt\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"1_se5rt\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 141)\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 0.784314)\n"
  },
  {
    "path": "resources/theme/element_towers_info/empty_button_style_box.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://ccdh5fd3bpu1w\"]\n\n[resource]\nbg_color = Color(0.6, 0.6, 0.6, 0.172549)\ncorner_radius_top_left = 10\ncorner_radius_top_right = 10\ncorner_radius_bottom_right = 10\ncorner_radius_bottom_left = 10\n"
  },
  {
    "path": "resources/theme/health_bar_background.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://b5iupqqmqci6d\"]\n\n[resource]\nbg_color = Color(0.0862745, 0.00392157, 0, 0.721569)\ncorner_radius_top_left = 2\ncorner_radius_top_right = 2\ncorner_radius_bottom_right = 2\ncorner_radius_bottom_left = 2\nexpand_margin_left = 2.0\nexpand_margin_top = 2.0\nexpand_margin_right = 2.0\nexpand_margin_bottom = 2.0\n"
  },
  {
    "path": "resources/theme/health_bar_fill.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://b3ycwn0t4rl5u\"]\n\n[resource]\nbg_color = Color(1, 1, 1, 1)\n"
  },
  {
    "path": "resources/theme/item_button_hover.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://bdt0si03bssd5\"]\n\n[resource]\nbg_color = Color(0, 0, 0, 0)\nborder_width_left = 1\nborder_width_bottom = 1\nborder_color = Color(1, 1, 1, 0.847059)\ncorner_radius_bottom_left = 3\nexpand_margin_left = 3.0\nexpand_margin_bottom = 3.0\nanti_aliasing_size = 0.732\n"
  },
  {
    "path": "resources/theme/item_button_normal.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://xj6rw0giypad\"]\n\n[resource]\nbg_color = Color(0, 0, 0, 0)\nborder_width_left = 1\nborder_width_bottom = 1\nborder_color = Color(1, 1, 1, 0.352941)\ncorner_radius_bottom_left = 3\nexpand_margin_left = 2.0\nexpand_margin_bottom = 2.0\nanti_aliasing_size = 0.732\n"
  },
  {
    "path": "resources/theme/item_button_pressed.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://caup80g6uwfi2\"]\n\n[resource]\nbg_color = Color(0, 0, 0, 0)\nborder_width_left = 2\nborder_width_bottom = 2\nborder_color = Color(1, 1, 1, 0.8)\nborder_blend = true\ncorner_radius_bottom_left = 3\nexpand_margin_left = 4.0\nexpand_margin_bottom = 4.0\nshadow_color = Color(1, 1, 1, 0.6)\nshadow_size = 4\nanti_aliasing_size = 0.732\n"
  },
  {
    "path": "resources/theme/mission_complete_indicator.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://cjho6n8sw5utc\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_top = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\nbg_color = Color(0.0784314, 0.0784314, 0.0784314, 1)\nborder_width_left = 3\nborder_width_top = 3\nborder_width_right = 3\nborder_width_bottom = 3\nborder_color = Color(0.466181, 0.466181, 0.466181, 1)\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n"
  },
  {
    "path": "resources/theme/player_resource_display/circle_container_l.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://bgbcsbfa5tgnm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://butcq5anduco8\" path=\"res://resources/ui_textures/portal_lives_round_bg.tres\" id=\"1_rnes8\"]\n\n[resource]\ntexture = ExtResource(\"1_rnes8\")\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n"
  },
  {
    "path": "resources/theme/player_resource_display/rect_container_center_l.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://bw4wtqgmpri3j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_mjv18\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1i5vi\"]\natlas = ExtResource(\"1_mjv18\")\nregion = Rect2(1105, 367, 156, 176)\n\n[resource]\ntexture = SubResource(\"AtlasTexture_1i5vi\")\ntexture_margin_left = 29.8477\ntexture_margin_top = 30.2329\ntexture_margin_right = 30.2329\ntexture_margin_bottom = 29.8477\nregion_rect = Rect2(1105, 367, 156, 176)\n"
  },
  {
    "path": "resources/theme/player_resource_display/rect_container_left_l.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://yk4phpxsa6q7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_ki88r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1i5vi\"]\natlas = ExtResource(\"1_ki88r\")\nregion = Rect2(1094, 4, 167, 169)\n\n[resource]\ncontent_margin_left = 20.0\ncontent_margin_right = 10.0\ntexture = SubResource(\"AtlasTexture_1i5vi\")\ntexture_margin_left = 39.6148\ntexture_margin_top = 40.0\ntexture_margin_right = 40.0\ntexture_margin_bottom = 39.6148\nregion_rect = Rect2(1094, 4, 167, 169)\n"
  },
  {
    "path": "resources/theme/player_resource_display/rect_container_right_l.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://uiev7wofsglu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_odlbf\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ytjf\"]\natlas = ExtResource(\"1_odlbf\")\nregion = Rect2(1266, 5, 167, 169)\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_right = 20.0\ntexture = SubResource(\"AtlasTexture_3ytjf\")\ntexture_margin_left = 39.6148\ntexture_margin_top = 40.0\ntexture_margin_right = 40.0\ntexture_margin_bottom = 39.6148\nregion_rect = Rect2(1266, 5, 167, 169)\n"
  },
  {
    "path": "resources/theme/player_resource_display/rect_container_top_menu.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://dt873umx4sexx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"1_ac6rd\"]\n\n[resource]\ncontent_margin_left = 0.0\ncontent_margin_top = 4.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 4.0\ntexture = ExtResource(\"1_ac6rd\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 154)\n"
  },
  {
    "path": "resources/theme/player_resource_display/resource_status_panel.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://8o35dfhhk4km\"]\n\n[resource]\nbg_color = Color(0.6, 0.6, 0.6, 0.196078)\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n"
  },
  {
    "path": "resources/theme/player_resource_display/stash_panel_background.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://c4rv27uxbm00c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_hq5m6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_58l2a\"]\natlas = ExtResource(\"1_hq5m6\")\nregion = Rect2(1, 136, 1087, 161)\n\n[resource]\ntexture = SubResource(\"AtlasTexture_58l2a\")\naxis_stretch_horizontal = 1\n"
  },
  {
    "path": "resources/theme/selected_unit_info/mana_bar_fill.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://bumf4iv4im8nj\"]\n\n[resource]\nbg_color = Color(0.0980392, 0, 0.584314, 1)\nborder_width_left = 3\nborder_width_top = 3\nborder_width_right = 3\nborder_width_bottom = 3\nborder_color = Color(0.8, 0.8, 0.8, 0)\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n"
  },
  {
    "path": "resources/theme/selected_unit_info/panel_container.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://bw17avoi3cj5m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_xwpeu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iu5cl\"]\natlas = ExtResource(\"1_xwpeu\")\nregion = Rect2(853, 74, 48, 48)\n\n[resource]\ntexture = SubResource(\"AtlasTexture_iu5cl\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 11.0\ntexture_margin_bottom = 11.0\nmodulate_color = Color(1, 1, 1, 0.682353)\n"
  },
  {
    "path": "resources/theme/selected_unit_info/progress_bar_background.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://cmn4jl7cthd0l\"]\n\n[resource]\nbg_color = Color(0, 0, 0, 1)\nborder_color = Color(0.8, 0.8, 0.8, 0)\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n"
  },
  {
    "path": "resources/theme/tower_actions/button_disabled.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://11b5t8jsfbdk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_jh16m\"]\n\n[resource]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"1_jh16m\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\nmodulate_color = Color(0.427451, 0.427451, 0.427451, 0.658824)\n"
  },
  {
    "path": "resources/theme/tower_actions/button_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://6go01ssqkmws\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_37354\"]\n\n[resource]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"1_37354\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\nmodulate_color = Color(1, 1, 1, 0.784314)\n"
  },
  {
    "path": "resources/theme/tower_actions/button_pressed.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://cp7fygn5qoudb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_ii2cc\"]\n\n[resource]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"1_ii2cc\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\n"
  },
  {
    "path": "resources/theme/unit_button/button_disabled.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://c8x6v1g5py6r6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://diwdxkuywfhj5\" path=\"res://resources/ui_textures/button_container_hover.tres\" id=\"1_dm7nd\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_top = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 10.0\ntexture = ExtResource(\"1_dm7nd\")\ntexture_margin_left = 14.0\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 14.0\nregion_rect = Rect2(790, 443, 124, 124)\nmodulate_color = Color(0.403922, 0.403922, 0.403922, 1)\n"
  },
  {
    "path": "resources/theme/unit_button/button_hover.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://ceml4iosll1ur\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://diwdxkuywfhj5\" path=\"res://resources/ui_textures/button_container_hover.tres\" id=\"1_aqjk1\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_top = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 10.0\ntexture = ExtResource(\"1_aqjk1\")\ntexture_margin_left = 14.0\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 14.0\nregion_rect = Rect2(790, 443, 124, 124)\n"
  },
  {
    "path": "resources/theme/unit_button/button_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://dcjhupdk2mwkl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://diwdxkuywfhj5\" path=\"res://resources/ui_textures/button_container_hover.tres\" id=\"1_ueee4\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_top = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 10.0\ntexture = ExtResource(\"1_ueee4\")\ntexture_margin_left = 14.0\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 14.0\nregion_rect = Rect2(790, 443, 124, 124)\nmodulate_color = Color(0.6, 0.6, 0.6, 1)\n"
  },
  {
    "path": "resources/theme/unit_button/common_rarity_panel_container.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://b8m81drahps4x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://m5xtdjyjr2xu\" path=\"res://resources/ui_textures/common_background.tres\" id=\"1_oqp4v\"]\n\n[resource]\ntexture = ExtResource(\"1_oqp4v\")\ntexture_margin_left = 16.5289\ntexture_margin_top = 17.0\ntexture_margin_right = 16.5289\ntexture_margin_bottom = 17.0\n"
  },
  {
    "path": "resources/theme/unit_button/passive_ability_button.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://d1kpcknbt4bgj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://diwdxkuywfhj5\" path=\"res://resources/ui_textures/button_container_hover.tres\" id=\"1_aw2bh\"]\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_top = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 10.0\ntexture = ExtResource(\"1_aw2bh\")\ntexture_margin_left = 14.0\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 14.0\nregion_rect = Rect2(790, 443, 124, 124)\nmodulate_color = Color(0.4, 0.4, 0.4, 1)\n"
  },
  {
    "path": "resources/theme/unit_button/rare_rarity_panel_container.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://dvslmk5lro1u0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://byo5dkh3m5rlm\" path=\"res://resources/ui_textures/rare_background.tres\" id=\"1_6pbq4\"]\n\n[resource]\ntexture = ExtResource(\"1_6pbq4\")\ntexture_margin_left = 16.5289\ntexture_margin_top = 17.0\ntexture_margin_right = 16.5289\ntexture_margin_bottom = 17.0\n"
  },
  {
    "path": "resources/theme/unit_button/small_button_disabled.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://rhsusiehbqjb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_nkrt3\"]\n\n[resource]\ncontent_margin_left = 30.0\ncontent_margin_top = 15.0\ncontent_margin_right = 30.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"1_nkrt3\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\nmodulate_color = Color(0.435294, 0.435294, 0.435294, 1)\n"
  },
  {
    "path": "resources/theme/unit_button/small_button_hover.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://k235emid2ajj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_3831y\"]\n\n[resource]\ncontent_margin_left = 30.0\ncontent_margin_top = 15.0\ncontent_margin_right = 30.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"1_3831y\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\n"
  },
  {
    "path": "resources/theme/unit_button/small_button_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://carc5koied5gk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_eiumh\"]\n\n[resource]\ncontent_margin_left = 30.0\ncontent_margin_top = 15.0\ncontent_margin_right = 30.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"1_eiumh\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\nmodulate_color = Color(0.607843, 0.607843, 0.607843, 1)\n"
  },
  {
    "path": "resources/theme/unit_button/uncommon_rarity_panel_container.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://dqn63cj0ar4qv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://jetwabbmtpbn\" path=\"res://resources/ui_textures/uncommon_background.tres\" id=\"1_oa8c0\"]\n\n[resource]\ntexture = ExtResource(\"1_oa8c0\")\ntexture_margin_left = 16.5289\ntexture_margin_top = 17.0\ntexture_margin_right = 16.5289\ntexture_margin_bottom = 17.0\n"
  },
  {
    "path": "resources/theme/unit_button/unique_rarity_panel_container.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://b6c3y3hvg15qk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://esujtr6kx747\" path=\"res://resources/ui_textures/unique_background.tres\" id=\"1_17cer\"]\n\n[resource]\ntexture = ExtResource(\"1_17cer\")\ntexture_margin_left = 16.5289\ntexture_margin_top = 17.0\ntexture_margin_right = 16.5289\ntexture_margin_bottom = 17.0\n"
  },
  {
    "path": "resources/theme/unit_button_container/counter_label_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://de41wrip7to2f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"1_15iwe\"]\n\n[resource]\ntexture = ExtResource(\"1_15iwe\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 10.89\ntexture_margin_bottom = 11.0\n"
  },
  {
    "path": "resources/theme/unit_menu/button_disalbed.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://ln3gwpdseci7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_l1d4w\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fjpfd\"]\natlas = ExtResource(\"1_l1d4w\")\nregion = Rect2(790, 74, 48, 48)\n\n[resource]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_fjpfd\")\nmodulate_color = Color(0.392157, 0.392157, 0.392157, 1)\n"
  },
  {
    "path": "resources/theme/unit_menu/button_hover.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://b284lwmb62g6v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_qrfg5\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fjpfd\"]\natlas = ExtResource(\"1_qrfg5\")\nregion = Rect2(790, 74, 48, 48)\n\n[resource]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_fjpfd\")\n"
  },
  {
    "path": "resources/theme/unit_menu/button_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://di63wj0o7etx1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_5ywko\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_us0y7\"]\natlas = ExtResource(\"1_5ywko\")\nregion = Rect2(790, 74, 48, 48)\n\n[resource]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_us0y7\")\nmodulate_color = Color(0.627451, 0.627451, 0.627451, 1)\n"
  },
  {
    "path": "resources/theme/unit_menu/exp_bar_background.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://bxmrnso7h7np1\"]\n\n[resource]\nbg_color = Color(0.329412, 0.2, 0.407843, 1)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.545098, 0.545098, 0.545098, 1)\ncorner_radius_top_left = 3\ncorner_radius_top_right = 3\ncorner_radius_bottom_right = 3\ncorner_radius_bottom_left = 3\n"
  },
  {
    "path": "resources/theme/unit_menu/exp_bar_fill.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://dab1qvryjypqs\"]\n\n[resource]\nbg_color = Color(0.552941, 0.368627, 0.666667, 1)\nborder_width_left = 3\nborder_width_top = 3\nborder_width_right = 3\nborder_width_bottom = 3\nborder_color = Color(0.8, 0.8, 0.8, 0)\ncorner_radius_top_left = 3\ncorner_radius_top_right = 3\ncorner_radius_bottom_right = 3\ncorner_radius_bottom_left = 3\n"
  },
  {
    "path": "resources/theme/unit_menu/health_bar_background.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://bg0camfo41dqc\"]\n\n[resource]\nbg_color = Color(0, 0.278431, 0.101961, 1)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.545098, 0.545098, 0.545098, 1)\ncorner_radius_top_left = 3\ncorner_radius_top_right = 3\ncorner_radius_bottom_right = 3\ncorner_radius_bottom_left = 3\n"
  },
  {
    "path": "resources/theme/unit_menu/health_bar_fill.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://1g0617tasr0m\"]\n\n[resource]\nbg_color = Color(0, 0.552941, 0.235294, 1)\nborder_width_left = 3\nborder_width_top = 3\nborder_width_right = 3\nborder_width_bottom = 3\nborder_color = Color(0.8, 0.8, 0.8, 0)\ncorner_radius_top_left = 3\ncorner_radius_top_right = 3\ncorner_radius_bottom_right = 3\ncorner_radius_bottom_left = 3\n"
  },
  {
    "path": "resources/theme/unit_menu/mana_bar_background.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://cefr72vfj04ja\"]\n\n[resource]\nbg_color = Color(0.0352941, 0.188235, 0.294118, 1)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.545098, 0.545098, 0.545098, 1)\ncorner_radius_top_left = 3\ncorner_radius_top_right = 3\ncorner_radius_bottom_right = 3\ncorner_radius_bottom_left = 3\n"
  },
  {
    "path": "resources/theme/unit_menu/mana_bar_fill.tres",
    "content": "[gd_resource type=\"StyleBoxFlat\" format=3 uid=\"uid://rku7yxxl0iit\"]\n\n[resource]\nbg_color = Color(0.172549, 0.498039, 0.733333, 1)\nborder_width_left = 3\nborder_width_top = 3\nborder_width_right = 3\nborder_width_bottom = 3\nborder_color = Color(0.8, 0.8, 0.8, 0)\ncorner_radius_top_left = 3\ncorner_radius_top_right = 3\ncorner_radius_bottom_right = 3\ncorner_radius_bottom_left = 3\n"
  },
  {
    "path": "resources/theme/unit_menu/title_button_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://nik74qhp637u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_pp7wa\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c67wk\"]\natlas = ExtResource(\"1_pp7wa\")\nregion = Rect2(1275, 219, 139, 154)\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = SubResource(\"AtlasTexture_c67wk\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1275, 219, 139, 154)\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n"
  },
  {
    "path": "resources/theme/unit_menu/unit_level_label_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://c2wcu6a3ywhdl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_rp3oq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_07qhs\"]\natlas = ExtResource(\"1_rp3oq\")\nregion = Rect2(768, 128, 128, 128)\n\n[resource]\ncontent_margin_top = 0.0\ncontent_margin_right = 0.0\ncontent_margin_bottom = 0.0\ntexture = SubResource(\"AtlasTexture_07qhs\")\n"
  },
  {
    "path": "resources/theme/unit_menu/unit_menu_panel.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=2 format=3 uid=\"uid://woorl376lbra\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://s4h31j7p5184\" path=\"res://resources/ui_textures/rect_container_l.tres\" id=\"1_swoaf\"]\n\n[resource]\ntexture = ExtResource(\"1_swoaf\")\ntexture_margin_left = 39.6148\ntexture_margin_top = 40.0\ntexture_margin_right = 40.0\ntexture_margin_bottom = 39.6148\nregion_rect = Rect2(1085, 207, 176, 178)\n"
  },
  {
    "path": "resources/theme/unit_menu/unit_name_label_normal.tres",
    "content": "[gd_resource type=\"StyleBoxTexture\" load_steps=3 format=3 uid=\"uid://btaejtkq2p7e8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_u5ffc\"]\n\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c67wk\"]\natlas = ExtResource(\"1_u5ffc\")\nregion = Rect2(1275, 219, 139, 154)\n\n[resource]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = SubResource(\"AtlasTexture_c67wk\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1275, 219, 139, 154)\n"
  },
  {
    "path": "resources/theme/wc3_theme.tres",
    "content": "[gd_resource type=\"Theme\" load_steps=97 format=3 uid=\"uid://bql5sxaowafw3\"]\n\n[ext_resource type=\"FontFile\" uid=\"uid://d1pnwehsosppo\" path=\"res://assets/fonts/Friz Quadrata Std Medium.otf\" id=\"1\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://vnjg5mo0nmg\" path=\"res://resources/theme/common/rect_container_l.tres\" id=\"1_7apqd\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://11b5t8jsfbdk\" path=\"res://resources/theme/tower_actions/button_disabled.tres\" id=\"1_vdqn7\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://ceml4iosll1ur\" path=\"res://resources/theme/unit_button/button_hover.tres\" id=\"1_xn0v5\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://cp7fygn5qoudb\" path=\"res://resources/theme/tower_actions/button_pressed.tres\" id=\"2_1ucqc\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://crr0tkfd2ggb8\" path=\"res://resources/theme/common/rect_container_center_l.tres\" id=\"2_4l726\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://h5ppp14fvtrd\" path=\"res://assets/hud/horadric_cube.png\" id=\"2_uaxwg\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://6go01ssqkmws\" path=\"res://resources/theme/tower_actions/button_normal.tres\" id=\"3_o7vtc\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://b8m81drahps4x\" path=\"res://resources/theme/unit_button/common_rarity_panel_container.tres\" id=\"4_28e2h\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://bw4wtqgmpri3j\" path=\"res://resources/theme/player_resource_display/rect_container_center_l.tres\" id=\"4_enpnq\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://ccdh5fd3bpu1w\" path=\"res://resources/theme/element_towers_info/empty_button_style_box.tres\" id=\"5_ggt4h\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://de41wrip7to2f\" path=\"res://resources/theme/unit_button_container/counter_label_normal.tres\" id=\"5_rng1l\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://c4rv27uxbm00c\" path=\"res://resources/theme/player_resource_display/stash_panel_background.tres\" id=\"5_uofvg\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://dvslmk5lro1u0\" path=\"res://resources/theme/unit_button/rare_rarity_panel_container.tres\" id=\"6_unpbn\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bxfq60uwqny4m\" path=\"res://assets/hud/checkbox.png\" id=\"7_0ykvr\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://lu1adtr8xmdf\" path=\"res://resources/ui_textures/rect_container_s.tres\" id=\"7_7y0mp\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://rhsusiehbqjb\" path=\"res://resources/theme/unit_button/small_button_disabled.tres\" id=\"7_mn43h\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://bdt0si03bssd5\" path=\"res://resources/theme/item_button_hover.tres\" id=\"8_332gl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"8_dlncl\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://k235emid2ajj\" path=\"res://resources/theme/unit_button/small_button_hover.tres\" id=\"8_pql3q\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://xj6rw0giypad\" path=\"res://resources/theme/item_button_normal.tres\" id=\"8_t77il\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://carc5koied5gk\" path=\"res://resources/theme/unit_button/small_button_normal.tres\" id=\"9_xj4hs\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"10_7mhq7\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://butcq5anduco8\" path=\"res://resources/ui_textures/portal_lives_round_bg.tres\" id=\"10_r42uk\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://dqn63cj0ar4qv\" path=\"res://resources/theme/unit_button/uncommon_rarity_panel_container.tres\" id=\"12_klcgr\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://b6c3y3hvg15qk\" path=\"res://resources/theme/unit_button/unique_rarity_panel_container.tres\" id=\"13_15oyb\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"14_02q6i\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://d1kpcknbt4bgj\" path=\"res://resources/theme/unit_button/passive_ability_button.tres\" id=\"14_bh3ro\"]\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_q5aqc\"]\ntexture = ExtResource(\"10_r42uk\")\nmodulate_color = Color(0.392157, 0.392157, 0.392157, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_o1y8y\"]\ntexture = ExtResource(\"10_r42uk\")\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_rt2ji\"]\ntexture = ExtResource(\"10_r42uk\")\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_q5ln1\"]\ntexture = ExtResource(\"10_r42uk\")\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_nrl13\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"7_7y0mp\")\nmodulate_color = Color(0.466667, 0.466667, 0.466667, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_brhe4\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"7_7y0mp\")\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_d8adj\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"7_7y0mp\")\nmodulate_color = Color(0.627451, 0.627451, 0.627451, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_bjyac\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = ExtResource(\"7_7y0mp\")\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r2ior\"]\natlas = ExtResource(\"7_0ykvr\")\nregion = Rect2(32, 0, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1tbsw\"]\natlas = ExtResource(\"7_0ykvr\")\nregion = Rect2(0, 0, 32, 32)\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_axp0f\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_v3ojd\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_n2dwr\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_rvhuf\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_yd317\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_b7i3v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fjpfd\"]\natlas = ExtResource(\"8_dlncl\")\nregion = Rect2(790, 74, 48, 48)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_03gih\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_fjpfd\")\nmodulate_color = Color(0.466667, 0.466667, 0.466667, 1)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wfurf\"]\natlas = ExtResource(\"8_dlncl\")\nregion = Rect2(790, 74, 48, 48)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_ts633\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_wfurf\")\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_us0y7\"]\natlas = ExtResource(\"8_dlncl\")\nregion = Rect2(790, 74, 48, 48)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_eyvb8\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_us0y7\")\nmodulate_color = Color(0.627451, 0.627451, 0.627451, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_6ua8f\"]\ncontent_margin_left = 2.0\ncontent_margin_top = 2.0\ncontent_margin_right = 2.0\ncontent_margin_bottom = 2.0\ntexture = SubResource(\"AtlasTexture_wfurf\")\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_s43g1\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_s61dw\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_6l34k\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_5cxbq\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_efi1j\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_f8clf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o3xv5\"]\natlas = ExtResource(\"10_7mhq7\")\nregion = Rect2(640, 128, 128, 128)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_c46h0\"]\ntexture = SubResource(\"AtlasTexture_o3xv5\")\ntexture_margin_left = 5.0\ntexture_margin_top = 5.0\ntexture_margin_right = 5.0\ntexture_margin_bottom = 5.0\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dldvb\"]\natlas = ExtResource(\"10_7mhq7\")\nregion = Rect2(640, 128, 128, 128)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_wifc2\"]\ntexture = SubResource(\"AtlasTexture_dldvb\")\ntexture_margin_left = 10.0\ntexture_margin_top = 10.0\ntexture_margin_right = 10.0\ntexture_margin_bottom = 10.0\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_ehwjq\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_6boc5\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_3rl6t\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_5u1yn\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_e1jfq\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_atyef\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_2t7ys\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_sxyqq\"]\ncontent_margin_left = 8.0\ncontent_margin_right = 8.0\nbg_color = Color(0, 0, 0, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_7t6hr\"]\ntexture = ExtResource(\"10_r42uk\")\nmodulate_color = Color(0.392157, 0.392157, 0.392157, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_q1dmk\"]\ntexture = ExtResource(\"10_r42uk\")\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_e3c08\"]\ntexture = ExtResource(\"10_r42uk\")\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_htago\"]\ntexture = ExtResource(\"10_r42uk\")\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1v3kw\"]\natlas = ExtResource(\"8_dlncl\")\nregion = Rect2(853, 74, 48, 48)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_6lvfq\"]\ncontent_margin_left = 0.0\ncontent_margin_top = 0.0\ncontent_margin_right = 0.0\ncontent_margin_bottom = 0.0\ntexture = SubResource(\"AtlasTexture_1v3kw\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 11.0\ntexture_margin_bottom = 11.0\nmodulate_color = Color(0.392157, 0.392157, 0.392157, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_raa15\"]\ncontent_margin_left = 0.0\ncontent_margin_top = 0.0\ncontent_margin_right = 0.0\ncontent_margin_bottom = 0.0\ntexture = SubResource(\"AtlasTexture_1v3kw\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 11.0\ntexture_margin_bottom = 11.0\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_v0wbc\"]\ncontent_margin_left = 0.0\ncontent_margin_top = 0.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 0.0\ntexture = SubResource(\"AtlasTexture_1v3kw\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 11.0\ntexture_margin_bottom = 11.0\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_uye1s\"]\ncontent_margin_left = 0.0\ncontent_margin_top = 0.0\ncontent_margin_right = 0.0\ncontent_margin_bottom = 0.0\ntexture = SubResource(\"AtlasTexture_1v3kw\")\ntexture_margin_left = 11.0\ntexture_margin_top = 11.0\ntexture_margin_right = 11.0\ntexture_margin_bottom = 11.0\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_vfmo2\"]\ndraw_center = false\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(1, 1, 1, 0.47451)\ncorner_radius_top_left = 10\ncorner_radius_top_right = 10\ncorner_radius_bottom_right = 10\ncorner_radius_bottom_left = 10\n\n[sub_resource type=\"StyleBoxFlat\" id=\"8\"]\nbg_color = Color(0.215686, 0.215686, 0.258824, 0.376471)\ncorner_radius_top_left = 10\ncorner_radius_top_right = 10\ncorner_radius_bottom_right = 10\ncorner_radius_bottom_left = 10\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_4b6ct\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"14_02q6i\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 141)\nmodulate_color = Color(0.588235, 0.588235, 0.588235, 0.784314)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_t5v3h\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"14_02q6i\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 141)\nmodulate_color = Color(1, 1, 1, 0.784314)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_hqcpk\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"14_02q6i\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 141)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_86j4s\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"14_02q6i\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 141)\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 0.784314)\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_wdruh\"]\ncontent_margin_left = 4.0\ncontent_margin_top = 4.0\ncontent_margin_right = 4.0\ncontent_margin_bottom = 4.0\nbg_color = Color(0.6, 0.6, 0.6, 0)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.392157, 0.392157, 0.392157, 1)\nborder_blend = true\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_6ub3i\"]\nbg_color = Color(0.6, 0.6, 0.6, 0)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(1, 1, 1, 1)\nborder_blend = true\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_afavw\"]\ncontent_margin_left = 4.0\ncontent_margin_top = 4.0\ncontent_margin_right = 4.0\ncontent_margin_bottom = 4.0\nbg_color = Color(0.6, 0.6, 0.6, 0)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.784314, 0.784314, 0.784314, 1)\nborder_blend = true\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_o8qqj\"]\nbg_color = Color(0.6, 0.6, 0.6, 0)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(1, 1, 1, 1)\nborder_blend = true\ncorner_radius_top_left = 8\ncorner_radius_top_right = 8\ncorner_radius_bottom_right = 8\ncorner_radius_bottom_left = 8\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_sa26r\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"14_02q6i\")\ntexture_margin_left = 14.0\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 14.0\nregion_rect = Rect2(1283, 192, 139, 154)\nmodulate_color = Color(1, 1, 1, 0.72549)\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"11\"]\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_88crg\"]\ntexture = ExtResource(\"2_uaxwg\")\nmodulate_color = Color(0.392157, 0.392157, 0.392157, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_cge4u\"]\ntexture = ExtResource(\"2_uaxwg\")\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_jahl7\"]\ntexture = ExtResource(\"2_uaxwg\")\nmodulate_color = Color(0.784314, 0.784314, 0.784314, 1)\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_52r8a\"]\ntexture = ExtResource(\"2_uaxwg\")\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_esyqb\"]\natlas = ExtResource(\"7_7y0mp\")\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_j2qvk\"]\ntexture = SubResource(\"AtlasTexture_esyqb\")\ntexture_margin_left = 8.0\ntexture_margin_top = 8.26446\ntexture_margin_right = 8.26446\ntexture_margin_bottom = 8.0\nregion_rect = Rect2(853, 74, 48, 48)\n\n[resource]\ndefault_font = ExtResource(\"1\")\ndefault_font_size = 24\nBigCircleButton/base_type = &\"Button\"\nBigCircleButton/styles/disabled = SubResource(\"StyleBoxTexture_q5aqc\")\nBigCircleButton/styles/hover = SubResource(\"StyleBoxTexture_o1y8y\")\nBigCircleButton/styles/normal = SubResource(\"StyleBoxTexture_rt2ji\")\nBigCircleButton/styles/pressed = SubResource(\"StyleBoxTexture_q5ln1\")\nBuffGroupButton/base_type = &\"Button\"\nBuffGroupButton/styles/disabled = SubResource(\"StyleBoxTexture_nrl13\")\nBuffGroupButton/styles/hover = SubResource(\"StyleBoxTexture_brhe4\")\nBuffGroupButton/styles/normal = SubResource(\"StyleBoxTexture_d8adj\")\nBuffGroupButton/styles/pressed = SubResource(\"StyleBoxTexture_bjyac\")\nButton/font_sizes/font_size = 24\nButton/styles/disabled = ExtResource(\"7_mn43h\")\nButton/styles/hover = ExtResource(\"8_pql3q\")\nButton/styles/normal = ExtResource(\"9_xj4hs\")\nButton/styles/pressed = ExtResource(\"8_pql3q\")\nButtonLarge/base_type = &\"Button\"\nButtonLarge/font_sizes/font_size = 50\nCenterPanel/base_type = &\"PanelContainer\"\nCenterPanel/styles/panel = ExtResource(\"2_4l726\")\nCheckBox/constants/h_separation = 10\nCheckBox/icons/checked = SubResource(\"AtlasTexture_r2ior\")\nCheckBox/icons/unchecked = SubResource(\"AtlasTexture_1tbsw\")\nCheckBox/styles/disabled = SubResource(\"StyleBoxEmpty_axp0f\")\nCheckBox/styles/focus = SubResource(\"StyleBoxEmpty_v3ojd\")\nCheckBox/styles/hover = SubResource(\"StyleBoxEmpty_n2dwr\")\nCheckBox/styles/hover_pressed = SubResource(\"StyleBoxEmpty_rvhuf\")\nCheckBox/styles/normal = SubResource(\"StyleBoxEmpty_yd317\")\nCheckBox/styles/pressed = SubResource(\"StyleBoxEmpty_b7i3v\")\nCircleButton/base_type = &\"Button\"\nCircleButton/styles/disabled = SubResource(\"StyleBoxTexture_03gih\")\nCircleButton/styles/hover = SubResource(\"StyleBoxTexture_ts633\")\nCircleButton/styles/normal = SubResource(\"StyleBoxTexture_eyvb8\")\nCircleButton/styles/pressed = SubResource(\"StyleBoxTexture_6ua8f\")\nCommonRarityPanelContainer/base_type = &\"PanelContainer\"\nCommonRarityPanelContainer/styles/panel = ExtResource(\"4_28e2h\")\nCounterLabel/base_type = &\"Label\"\nCounterLabel/styles/normal = ExtResource(\"5_rng1l\")\nCustomTextureButton/base_type = &\"Button\"\nCustomTextureButton/colors/icon_hover_color = Color(0, 0, 0, 1)\nCustomTextureButton/font_sizes/font_size = 32\nCustomTextureButton/styles/disabled = SubResource(\"StyleBoxEmpty_s43g1\")\nCustomTextureButton/styles/focus = SubResource(\"StyleBoxEmpty_s61dw\")\nCustomTextureButton/styles/hover = SubResource(\"StyleBoxEmpty_6l34k\")\nCustomTextureButton/styles/normal = SubResource(\"StyleBoxEmpty_5cxbq\")\nCustomTextureButton/styles/pressed = SubResource(\"StyleBoxEmpty_efi1j\")\nEmptySlot/base_type = &\"Button\"\nEmptySlot/styles/disabled = ExtResource(\"5_ggt4h\")\nEmptySlot/styles/focus = ExtResource(\"5_ggt4h\")\nEmptySlot/styles/hover = ExtResource(\"5_ggt4h\")\nEmptySlot/styles/normal = ExtResource(\"5_ggt4h\")\nEmptySlot/styles/pressed = ExtResource(\"5_ggt4h\")\nExpandButton/base_type = &\"Button\"\nExpandButton/styles/disabled = SubResource(\"StyleBoxEmpty_f8clf\")\nExpandButton/styles/hover = SubResource(\"StyleBoxTexture_c46h0\")\nExpandButton/styles/normal = SubResource(\"StyleBoxTexture_wifc2\")\nExpandButton/styles/pressed = SubResource(\"StyleBoxEmpty_ehwjq\")\nFilterButton/base_type = &\"Button\"\nFilterButton/colors/icon_hover_color = Color(0.901961, 0.901961, 0.901961, 1)\nFilterButton/colors/icon_hover_pressed_color = Color(0.901961, 0.901961, 0.901961, 1)\nFilterButton/colors/icon_normal_color = Color(0.501961, 0.501961, 0.501961, 1)\nFilterButton/colors/icon_pressed_color = Color(1, 1, 1, 1)\nFilterButton/styles/disabled = SubResource(\"StyleBoxEmpty_6boc5\")\nFilterButton/styles/focus = SubResource(\"StyleBoxEmpty_3rl6t\")\nFilterButton/styles/hover = SubResource(\"StyleBoxEmpty_5u1yn\")\nFilterButton/styles/normal = SubResource(\"StyleBoxEmpty_e1jfq\")\nFilterButton/styles/pressed = SubResource(\"StyleBoxEmpty_atyef\")\nInfoContainer/base_type = &\"PanelContainer\"\nInfoContainer/styles/panel = SubResource(\"StyleBoxFlat_2t7ys\")\nLabel/font_sizes/font_size = 24\nLabelLarge/base_type = &\"Label\"\nLabelLarge/font_sizes/font_size = 36\nLabelSectionTitle/base_type = &\"Label\"\nLabelSectionTitle/colors/font_color = Color(0.945098, 0.945098, 0, 1)\nLabelSectionTitle/font_sizes/font_size = 26\nLabelSectionTitle/styles/normal = SubResource(\"StyleBoxFlat_sxyqq\")\nLabelSmall/base_type = &\"Label\"\nLabelSmall/font_sizes/font_size = 18\nLabelTitle/base_type = &\"Label\"\nLabelTitle/font_sizes/font_size = 26\nLargeCircleButton/base_type = &\"Button\"\nLargeCircleButton/styles/disabled = SubResource(\"StyleBoxTexture_7t6hr\")\nLargeCircleButton/styles/hover = SubResource(\"StyleBoxTexture_q1dmk\")\nLargeCircleButton/styles/normal = SubResource(\"StyleBoxTexture_e3c08\")\nLargeCircleButton/styles/pressed = SubResource(\"StyleBoxTexture_htago\")\nMainPanelContainer/base_type = &\"PanelContainer\"\nMainPanelContainer/styles/panel = ExtResource(\"1_7apqd\")\nMenuButton/styles/disabled = SubResource(\"StyleBoxTexture_6lvfq\")\nMenuButton/styles/hover = SubResource(\"StyleBoxTexture_raa15\")\nMenuButton/styles/normal = SubResource(\"StyleBoxTexture_v0wbc\")\nMenuButton/styles/pressed = SubResource(\"StyleBoxTexture_uye1s\")\nMessageLabel/base_type = &\"RichTextLabel\"\nMessageLabel/colors/default_color = Color(1, 1, 1, 1)\nMessageLabel/colors/font_shadow_color = Color(0, 0, 0, 1)\nMessageLabel/constants/shadow_outline_size = 1\nMessageLabel/font_sizes/bold_font_size = 32\nMessageLabel/font_sizes/bold_italics_font_size = 32\nMessageLabel/font_sizes/italics_font_size = 32\nMessageLabel/font_sizes/mono_font_size = 32\nMessageLabel/font_sizes/normal_font_size = 32\nPanel/styles/panel = ExtResource(\"4_enpnq\")\nPanelContainer/styles/panel = SubResource(\"StyleBoxFlat_vfmo2\")\nPassiveAbilityButton/base_type = &\"Button\"\nPassiveAbilityButton/styles/disabled = ExtResource(\"14_bh3ro\")\nPassiveAbilityButton/styles/focus = ExtResource(\"14_bh3ro\")\nPassiveAbilityButton/styles/hover = ExtResource(\"14_bh3ro\")\nPassiveAbilityButton/styles/normal = ExtResource(\"14_bh3ro\")\nPassiveAbilityButton/styles/pressed = ExtResource(\"14_bh3ro\")\nRareRarityPanelContainer/base_type = &\"PanelContainer\"\nRareRarityPanelContainer/styles/panel = ExtResource(\"6_unpbn\")\nResourceTab/base_type = &\"Panel\"\nResourceTab/styles/panel = SubResource(\"8\")\nRichTextLabel/font_sizes/bold_font_size = 24\nRichTextLabel/font_sizes/bold_italics_font_size = 24\nRichTextLabel/font_sizes/italics_font_size = 24\nRichTextLabel/font_sizes/mono_font_size = 24\nRichTextLabel/font_sizes/normal_font_size = 24\nRightSidePanel/base_type = &\"PanelContainer\"\nSidePanel/base_type = &\"PanelContainer\"\nSidePanel/styles/panel = ExtResource(\"5_uofvg\")\nSmallButton/base_type = &\"Button\"\nSmallButton/colors/font_disabled_color = Color(1, 1, 1, 1)\nSmallButton/colors/icon_disabled_color = Color(1, 1, 1, 1)\nSmallButton/styles/disabled = ExtResource(\"7_mn43h\")\nSmallButton/styles/hover = ExtResource(\"8_pql3q\")\nSmallButton/styles/normal = ExtResource(\"9_xj4hs\")\nSmallButton/styles/pressed = ExtResource(\"8_pql3q\")\nTabContainer/constants/side_margin = 40\nTabContainer/styles/panel = ExtResource(\"1_7apqd\")\nTabContainer/styles/tab_disabled = SubResource(\"StyleBoxTexture_4b6ct\")\nTabContainer/styles/tab_hovered = SubResource(\"StyleBoxTexture_t5v3h\")\nTabContainer/styles/tab_selected = SubResource(\"StyleBoxTexture_hqcpk\")\nTabContainer/styles/tab_unselected = SubResource(\"StyleBoxTexture_86j4s\")\nTinyUnitButton/base_type = &\"Button\"\nTinyUnitButton/colors/icon_disabled_color = Color(0.392157, 0.392157, 0.392157, 1)\nTinyUnitButton/colors/icon_normal_color = Color(0.784314, 0.784314, 0.784314, 1)\nTinyUnitButton/styles/disabled = SubResource(\"StyleBoxFlat_wdruh\")\nTinyUnitButton/styles/hover = SubResource(\"StyleBoxFlat_6ub3i\")\nTinyUnitButton/styles/normal = SubResource(\"StyleBoxFlat_afavw\")\nTinyUnitButton/styles/pressed = SubResource(\"StyleBoxFlat_o8qqj\")\nTooltipPanel/styles/panel = SubResource(\"StyleBoxTexture_sa26r\")\nTowerActions/base_type = &\"Button\"\nTowerActions/styles/disabled = ExtResource(\"1_vdqn7\")\nTowerActions/styles/hover = ExtResource(\"2_1ucqc\")\nTowerActions/styles/normal = ExtResource(\"3_o7vtc\")\nTowerActions/styles/pressed = ExtResource(\"2_1ucqc\")\nTowerButton/styles/disabled = ExtResource(\"8_332gl\")\nTowerButton/styles/focus = SubResource(\"11\")\nTowerButton/styles/hover = ExtResource(\"8_332gl\")\nTowerButton/styles/normal = ExtResource(\"8_t77il\")\nTowerButton/styles/pressed = ExtResource(\"8_332gl\")\nTransmuteButton/base_type = &\"Button\"\nTransmuteButton/styles/disabled = SubResource(\"StyleBoxTexture_88crg\")\nTransmuteButton/styles/hover = SubResource(\"StyleBoxTexture_cge4u\")\nTransmuteButton/styles/normal = SubResource(\"StyleBoxTexture_jahl7\")\nTransmuteButton/styles/pressed = SubResource(\"StyleBoxTexture_52r8a\")\nUnclickableButton/base_type = &\"Button\"\nUnclickableButton/colors/icon_disabled_color = Color(1, 1, 1, 1)\nUnclickableButton/styles/disabled = SubResource(\"StyleBoxTexture_j2qvk\")\nUncommonRarityPanelContainer/base_type = &\"PanelContainer\"\nUncommonRarityPanelContainer/styles/panel = ExtResource(\"12_klcgr\")\nUniqueRarityPanelContainer/base_type = &\"PanelContainer\"\nUniqueRarityPanelContainer/styles/panel = ExtResource(\"13_15oyb\")\nUnitButton/base_type = &\"Button\"\nUnitButton/colors/font_color = Color(0.875, 0.875, 0.875, 1)\nUnitButton/colors/font_disabled_color = Color(0.875, 0.875, 0.875, 0.5)\nUnitButton/colors/font_focus_color = Color(0.95, 0.95, 0.95, 1)\nUnitButton/colors/font_hover_color = Color(0.95, 0.95, 0.95, 1)\nUnitButton/colors/font_hover_pressed_color = Color(1, 1, 1, 1)\nUnitButton/colors/font_outline_color = Color(1, 1, 1, 1)\nUnitButton/colors/font_pressed_color = Color(1, 1, 1, 1)\nUnitButton/colors/icon_disabled_color = Color(0.392157, 0.392157, 0.392157, 1)\nUnitButton/colors/icon_focus_color = Color(1, 1, 1, 1)\nUnitButton/colors/icon_hover_color = Color(1, 1, 1, 1)\nUnitButton/colors/icon_hover_pressed_color = Color(1, 1, 1, 1)\nUnitButton/colors/icon_normal_color = Color(0.784314, 0.784314, 0.784314, 1)\nUnitButton/colors/icon_pressed_color = Color(1, 1, 1, 1)\nUnitButton/constants/h_separation = 2\nUnitButton/constants/icon_max_width = 0\nUnitButton/constants/outline_size = 0\nUnitButton/styles/disabled = ExtResource(\"1_xn0v5\")\nUnitButton/styles/hover = ExtResource(\"1_xn0v5\")\nUnitButton/styles/normal = ExtResource(\"1_xn0v5\")\nUnitButton/styles/pressed = ExtResource(\"1_xn0v5\")\nUnitButtonBright/base_type = &\"Button\"\nUnitButtonBright/styles/disabled = ExtResource(\"1_xn0v5\")\nUnitButtonBright/styles/hover = ExtResource(\"1_xn0v5\")\nUnitButtonBright/styles/normal = ExtResource(\"1_xn0v5\")\nUnitButtonBright/styles/pressed = ExtResource(\"1_xn0v5\")\n"
  },
  {
    "path": "resources/tilesets/buildable_area_tiles.tres",
    "content": "[gd_resource type=\"TileSet\" load_steps=3 format=3 uid=\"uid://bo62tf3gtehiu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://2v03j2bnie6o\" path=\"res://assets/tiles/empty_tiles.png\" id=\"1_xb6dd\"]\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_cnco2\"]\ntexture = ExtResource(\"1_xb6dd\")\ntexture_region_size = Vector2i(256, 512)\nuse_texture_padding = false\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 192)\n\n[resource]\ntile_shape = 1\ntile_layout = 5\ntile_size = Vector2i(128, 64)\nsources/0 = SubResource(\"TileSetAtlasSource_cnco2\")\n"
  },
  {
    "path": "resources/tilesets/decorations.tres",
    "content": "[gd_resource type=\"TileSet\" load_steps=51 format=3 uid=\"uid://c2ke1gy0rnehu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bb3cy5nc11xm4\" path=\"res://assets/tiles/planks.png\" id=\"1_jnba1\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://8hg2mltwjvch\" path=\"res://assets/tiles/bridges.png\" id=\"2_myw62\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dceqm4jvhllky\" path=\"res://assets/tiles_decoration/vines1.png\" id=\"3_g37rh\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b7wwnn77w8hhb\" path=\"res://assets/tiles_decoration/trees1.png\" id=\"4_da4tk\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cgpcu4ck8c2v5\" path=\"res://assets/tiles_decoration/stones1.png\" id=\"5_3fs12\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cbbl57ekmerku\" path=\"res://assets/tiles_decoration/stones2.png\" id=\"6_l1xps\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cokj6s372752e\" path=\"res://assets/tiles_decoration/stones3.png\" id=\"7_kus2p\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://8k675jm7ssuf\" path=\"res://assets/tiles_decoration/leaves1.png\" id=\"8_okmrw\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://m18bce1kiqho\" path=\"res://assets/tiles_decoration/wall_vines1.png\" id=\"9_y6ry1\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://buuvdmdkvmrqi\" path=\"res://assets/tiles_decoration/bushes1.png\" id=\"10_8vk0w\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://blgrogxcyqgrv\" path=\"res://assets/tiles_decoration/trees2.png\" id=\"12_1fthb\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b8kaotwoawygm\" path=\"res://assets/tiles/barrels.png\" id=\"12_4re2u\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://no8l70qh6xxf\" path=\"res://assets/tiles/chests.png\" id=\"13_7iuuj\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://qy7lhcabenwy\" path=\"res://assets/tiles/tables.png\" id=\"14_mhdnl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bnkqv52xr6jwg\" path=\"res://assets/tiles_decoration/column_overgrown.png\" id=\"15_mthcg\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b1jfa4r4faj77\" path=\"res://assets/tiles/wooden_pile.png\" id=\"16_dki2r\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ui4kf3f3fnc\" path=\"res://assets/tiles/stairs.png\" id=\"18_8rk7a\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ct1fnt7hxgi4o\" path=\"res://assets/tiles/spiral_stairs.png\" id=\"20_7fi8d\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c3wu26qm1m3yu\" path=\"res://assets/tiles_decoration/vines2.png\" id=\"26_fp87b\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://d286468sfnwks\" path=\"res://assets/tiles_decoration/vines3.png\" id=\"30_qsvfe\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bbqc24ypw5f6n\" path=\"res://assets/tiles_decoration/vines4.png\" id=\"32_188qm\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cas6o0y3n1aeq\" path=\"res://assets/tiles_decoration/vines5.png\" id=\"33_ls46m\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://wob80clhcyd3\" path=\"res://assets/tiles_decoration/vines6.png\" id=\"34_crpbh\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://crgo2lc1y87l6\" path=\"res://assets/tiles_decoration/vines7.png\" id=\"35_hhfel\"]\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_3glom\"]\ntile_data = PackedInt32Array(0, 2, 65544, 131074, 2, 65549)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_7h0so\"]\ntile_data = PackedInt32Array(0, 2, 8, 655370, 2, 13)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_6it4p\"]\ntexture = ExtResource(\"1_jnba1\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_jku06\"]\ntexture = ExtResource(\"2_myw62\")\ntexture_region_size = Vector2i(256, 128)\nuse_texture_padding = false\n0:0/0 = 0\n1:0/0 = 0\n0:1/0 = 0\n1:1/0 = 0\n0:2/0 = 0\n1:2/0 = 0\n0:3/0 = 0\n1:3/0 = 0\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_8r7kx\"]\ntexture = ExtResource(\"3_g37rh\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(3, 3)\n0:0/0 = 0\n3:1/size_in_atlas = Vector2i(2, 2)\n3:1/0 = 0\n0:3/size_in_atlas = Vector2i(3, 2)\n0:3/0 = 0\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_adm57\"]\ntexture = ExtResource(\"4_da4tk\")\ntexture_region_size = Vector2i(128, 64)\nuse_texture_padding = false\n7:0/size_in_atlas = Vector2i(6, 10)\n7:0/next_alternative_id = 2\n7:0/0 = 0\n7:0/0/texture_origin = Vector2i(34, 200)\n7:0/1 = 1\n7:0/1/flip_h = true\n7:0/1/texture_origin = Vector2i(0, 128)\n7:0/1/y_sort_origin = -4000\n7:10/size_in_atlas = Vector2i(5, 10)\n7:10/next_alternative_id = 2\n7:10/0 = 0\n7:10/0/texture_origin = Vector2i(0, 160)\n7:10/0/y_sort_origin = -1000\n7:10/1 = 1\n7:10/1/flip_h = true\n7:10/1/texture_origin = Vector2i(0, 128)\n3:14/size_in_atlas = Vector2i(4, 6)\n3:14/next_alternative_id = 2\n3:14/0 = 0\n3:14/0/texture_origin = Vector2i(34, 90)\n3:14/1 = 1\n3:14/1/flip_h = true\n3:14/1/texture_origin = Vector2i(0, 64)\n0:14/size_in_atlas = Vector2i(3, 6)\n0:14/next_alternative_id = 2\n0:14/0 = 0\n0:14/0/texture_origin = Vector2i(0, 96)\n0:14/1 = 1\n0:14/1/flip_h = true\n0:14/1/texture_origin = Vector2i(0, 108)\n0:0/size_in_atlas = Vector2i(7, 14)\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 350)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_7frxb\"]\ntexture = ExtResource(\"5_3fs12\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(3, 3)\n0:0/next_alternative_id = 2\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 72)\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/1/texture_origin = Vector2i(0, 72)\n3:0/size_in_atlas = Vector2i(3, 3)\n3:0/next_alternative_id = 2\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n3:0/1 = 1\n3:0/1/flip_h = true\n3:0/1/texture_origin = Vector2i(0, 66)\n0:3/size_in_atlas = Vector2i(2, 2)\n0:3/next_alternative_id = 2\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 50)\n0:3/1 = 1\n0:3/1/flip_h = true\n0:3/1/texture_origin = Vector2i(0, 40)\n2:3/size_in_atlas = Vector2i(2, 2)\n2:3/next_alternative_id = 2\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 100)\n2:3/1 = 1\n2:3/1/flip_h = true\n2:3/1/texture_origin = Vector2i(0, 36)\n4:3/next_alternative_id = 2\n4:3/0 = 0\n4:3/0/texture_origin = Vector2i(0, 16)\n4:3/1 = 1\n4:3/1/flip_h = true\n4:3/1/texture_origin = Vector2i(0, 16)\n4:4/next_alternative_id = 2\n4:4/0 = 0\n4:4/0/texture_origin = Vector2i(0, 16)\n4:4/1 = 1\n4:4/1/flip_h = true\n4:4/1/texture_origin = Vector2i(0, 16)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_c1qpu\"]\ntexture = ExtResource(\"6_l1xps\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(2, 2)\n0:0/next_alternative_id = 2\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 22)\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/1/texture_origin = Vector2i(0, 32)\n2:0/size_in_atlas = Vector2i(2, 2)\n2:0/next_alternative_id = 2\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 40)\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/1/texture_origin = Vector2i(0, 50)\n5:0/next_alternative_id = 2\n5:0/0 = 0\n5:0/0/texture_origin = Vector2i(0, 16)\n5:0/1 = 1\n5:0/1/flip_h = true\n5:0/1/texture_origin = Vector2i(0, 16)\n4:0/next_alternative_id = 2\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 16)\n4:0/1 = 1\n4:0/1/flip_h = true\n4:0/1/texture_origin = Vector2i(0, 16)\n4:1/next_alternative_id = 2\n4:1/0 = 0\n4:1/0/texture_origin = Vector2i(0, 16)\n4:1/1 = 1\n4:1/1/flip_h = true\n4:1/1/texture_origin = Vector2i(0, 16)\n5:1/next_alternative_id = 2\n5:1/0 = 0\n5:1/0/texture_origin = Vector2i(0, 48)\n5:1/1 = 1\n5:1/1/flip_h = true\n5:1/1/texture_origin = Vector2i(0, 16)\n6:0/next_alternative_id = 2\n6:0/0 = 0\n6:0/0/texture_origin = Vector2i(0, 16)\n6:0/1 = 1\n6:0/1/flip_h = true\n6:0/1/texture_origin = Vector2i(0, 16)\n4:2/size_in_atlas = Vector2i(2, 2)\n4:2/next_alternative_id = 2\n4:2/0 = 0\n4:2/0/texture_origin = Vector2i(0, 34)\n4:2/1 = 1\n4:2/1/flip_h = true\n4:2/1/texture_origin = Vector2i(0, 32)\n2:2/size_in_atlas = Vector2i(2, 2)\n2:2/next_alternative_id = 2\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 90)\n2:2/1 = 1\n2:2/1/flip_h = true\n2:2/1/texture_origin = Vector2i(0, 30)\n0:2/size_in_atlas = Vector2i(2, 2)\n0:2/next_alternative_id = 2\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 36)\n0:2/1 = 1\n0:2/1/flip_h = true\n0:2/1/texture_origin = Vector2i(0, 50)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_k8mwm\"]\ntexture = ExtResource(\"7_kus2p\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(3, 3)\n0:0/next_alternative_id = 2\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 110)\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/1/texture_origin = Vector2i(0, 94)\n3:0/size_in_atlas = Vector2i(3, 3)\n3:0/next_alternative_id = 2\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 90)\n3:0/1 = 1\n3:0/1/flip_h = true\n3:0/1/texture_origin = Vector2i(0, 76)\n3:0/1/y_sort_origin = 3000\n6:0/size_in_atlas = Vector2i(2, 1)\n6:0/next_alternative_id = 2\n6:0/0 = 0\n6:0/0/texture_origin = Vector2i(0, 16)\n6:0/1 = 1\n6:0/1/flip_h = true\n6:0/1/texture_origin = Vector2i(0, 16)\n6:2/next_alternative_id = 2\n6:2/0 = 0\n6:2/0/texture_origin = Vector2i(0, 16)\n6:2/1 = 1\n6:2/1/flip_h = true\n6:2/1/texture_origin = Vector2i(0, 16)\n7:2/next_alternative_id = 2\n7:2/0 = 0\n7:2/0/texture_origin = Vector2i(0, 16)\n7:2/1 = 1\n7:2/1/flip_h = true\n7:2/1/texture_origin = Vector2i(0, 16)\n6:1/next_alternative_id = 2\n6:1/0 = 0\n6:1/0/texture_origin = Vector2i(0, 16)\n6:1/1 = 1\n6:1/1/flip_h = true\n6:1/1/texture_origin = Vector2i(0, 16)\n7:1/next_alternative_id = 2\n7:1/0 = 0\n7:1/0/texture_origin = Vector2i(0, 16)\n7:1/1 = 1\n7:1/1/flip_h = true\n7:1/1/texture_origin = Vector2i(0, 16)\n7:3/next_alternative_id = 2\n7:3/0 = 0\n7:3/0/texture_origin = Vector2i(0, 16)\n7:3/1 = 1\n7:3/1/flip_h = true\n7:3/1/texture_origin = Vector2i(0, 16)\n5:3/size_in_atlas = Vector2i(2, 2)\n5:3/next_alternative_id = 2\n5:3/0 = 0\n5:3/0/texture_origin = Vector2i(0, 60)\n5:3/1 = 1\n5:3/1/flip_h = true\n5:3/1/texture_origin = Vector2i(0, 50)\n0:3/size_in_atlas = Vector2i(3, 2)\n0:3/next_alternative_id = 2\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 36)\n0:3/1 = 1\n0:3/1/flip_h = true\n0:3/1/texture_origin = Vector2i(0, 34)\n3:3/size_in_atlas = Vector2i(2, 2)\n3:3/next_alternative_id = 2\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 62)\n3:3/1 = 1\n3:3/1/flip_h = true\n3:3/1/texture_origin = Vector2i(0, 54)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_dkfhl\"]\ntexture = ExtResource(\"8_okmrw\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(2, 2)\n0:0/next_alternative_id = 4\n0:0/0 = 0\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/2 = 2\n0:0/2/flip_h = true\n0:0/2/flip_v = true\n0:0/3 = 3\n0:0/3/flip_v = true\n2:0/next_alternative_id = 4\n2:0/0 = 0\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/2 = 2\n2:0/2/flip_h = true\n2:0/2/flip_v = true\n2:0/3 = 3\n2:0/3/flip_v = true\n3:0/next_alternative_id = 8\n3:0/0 = 0\n3:0/1 = 1\n3:0/1/flip_h = true\n3:0/2 = 2\n3:0/2/flip_h = true\n3:0/2/flip_v = true\n3:0/3 = 3\n3:0/3/flip_v = true\n3:0/4 = 4\n3:0/4/transpose = true\n3:0/5 = 5\n3:0/5/flip_v = true\n3:0/5/transpose = true\n3:0/6 = 6\n3:0/6/flip_h = true\n3:0/6/transpose = true\n3:0/7 = 7\n3:0/7/flip_h = true\n3:0/7/flip_v = true\n3:0/7/transpose = true\n2:1/next_alternative_id = 4\n2:1/0 = 0\n2:1/1 = 1\n2:1/1/flip_h = true\n2:1/2 = 2\n2:1/2/flip_h = true\n2:1/2/flip_v = true\n2:1/3 = 3\n2:1/3/flip_v = true\n3:1/next_alternative_id = 4\n3:1/0 = 0\n3:1/1 = 1\n3:1/1/flip_h = true\n3:1/2 = 2\n3:1/2/flip_h = true\n3:1/2/flip_v = true\n3:1/3 = 3\n3:1/3/flip_v = true\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_ld48b\"]\ntexture = ExtResource(\"9_y6ry1\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 100)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 100)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 100)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 100)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 100)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 100)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 100)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 100)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 100)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_3i46i\"]\ntexture = ExtResource(\"10_8vk0w\")\ntexture_region_size = Vector2i(128, 64)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(1, 2)\n0:0/next_alternative_id = 2\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 16)\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/1/texture_origin = Vector2i(0, 16)\n1:0/size_in_atlas = Vector2i(1, 2)\n1:0/next_alternative_id = 2\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 16)\n1:0/1 = 1\n1:0/1/flip_h = true\n1:0/1/texture_origin = Vector2i(0, 16)\n2:0/size_in_atlas = Vector2i(2, 4)\n2:0/next_alternative_id = 2\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/1/texture_origin = Vector2i(0, 64)\n1:2/size_in_atlas = Vector2i(1, 2)\n1:2/next_alternative_id = 2\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 16)\n1:2/1 = 1\n1:2/1/flip_h = true\n1:2/1/texture_origin = Vector2i(0, 16)\n0:2/size_in_atlas = Vector2i(1, 2)\n0:2/next_alternative_id = 2\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 16)\n0:2/1 = 1\n0:2/1/flip_h = true\n0:2/1/texture_origin = Vector2i(0, 16)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_tdfoj\"]\ntexture = ExtResource(\"12_1fthb\")\ntexture_region_size = Vector2i(128, 64)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(4, 8)\n0:0/next_alternative_id = 4\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 230)\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/1/texture_origin = Vector2i(0, 182)\n0:0/1/y_sort_origin = 128\n4:0/size_in_atlas = Vector2i(3, 8)\n4:0/next_alternative_id = 3\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 230)\n4:0/1 = 1\n4:0/1/flip_h = true\n4:0/1/texture_origin = Vector2i(-54, 228)\n4:8/size_in_atlas = Vector2i(3, 8)\n4:8/next_alternative_id = 3\n4:8/0 = 0\n4:8/0/texture_origin = Vector2i(44, 214)\n4:8/1 = 1\n4:8/1/flip_h = true\n4:8/1/texture_origin = Vector2i(-36, 216)\n0:8/size_in_atlas = Vector2i(4, 5)\n0:8/next_alternative_id = 4\n0:8/0 = 0\n0:8/0/z_index = 6\n0:8/1 = 1\n0:8/1/flip_h = true\n0:8/1/texture_origin = Vector2i(0, 254)\n0:8/1/z_index = 6\n4:16/size_in_atlas = Vector2i(2, 6)\n4:16/next_alternative_id = 3\n4:16/0 = 0\n4:16/0/texture_origin = Vector2i(0, 160)\n4:16/1 = 1\n4:16/1/flip_h = true\n4:16/1/texture_origin = Vector2i(-36, 158)\n6:16/size_in_atlas = Vector2i(2, 6)\n6:16/next_alternative_id = 3\n6:16/0 = 0\n6:16/0/texture_origin = Vector2i(0, 160)\n6:16/1 = 1\n6:16/1/flip_h = true\n6:16/1/texture_origin = Vector2i(-30, 154)\n8:17/size_in_atlas = Vector2i(1, 3)\n8:17/next_alternative_id = 3\n8:17/0 = 0\n8:17/0/texture_origin = Vector2i(24, 74)\n8:17/1 = 1\n8:17/1/flip_h = true\n8:17/1/texture_origin = Vector2i(-22, 76)\n9:17/size_in_atlas = Vector2i(1, 3)\n9:17/next_alternative_id = 3\n9:17/0 = 0\n9:17/0/texture_origin = Vector2i(20, 76)\n9:17/1 = 1\n9:17/1/flip_h = true\n9:17/1/texture_origin = Vector2i(-12, 72)\n7:10/size_in_atlas = Vector2i(3, 6)\n7:10/next_alternative_id = 3\n7:10/0 = 0\n7:10/0/texture_origin = Vector2i(0, 132)\n7:10/1 = 1\n7:10/1/flip_h = true\n7:10/1/texture_origin = Vector2i(0, 136)\n7:0/size_in_atlas = Vector2i(4, 10)\n7:0/next_alternative_id = 3\n7:0/0 = 0\n7:0/0/texture_origin = Vector2i(0, 250)\n7:0/1 = 1\n7:0/1/flip_h = true\n7:0/1/texture_origin = Vector2i(0, 200)\n2:18/size_in_atlas = Vector2i(2, 6)\n2:18/next_alternative_id = 5\n2:18/0 = 0\n2:18/0/texture_origin = Vector2i(0, 154)\n2:18/1 = 1\n2:18/1/flip_h = true\n2:18/1/texture_origin = Vector2i(0, 156)\n2:18/3 = 3\n2:18/3/z_index = 6\n2:18/4 = 4\n2:18/4/flip_h = true\n2:18/4/z_index = 6\n0:18/size_in_atlas = Vector2i(2, 6)\n0:18/next_alternative_id = 3\n0:18/0 = 0\n0:18/0/texture_origin = Vector2i(0, 150)\n0:18/1 = 1\n0:18/1/flip_h = true\n0:18/1/texture_origin = Vector2i(0, 136)\n8:20/size_in_atlas = Vector2i(2, 4)\n8:20/next_alternative_id = 3\n8:20/0 = 0\n8:20/0/texture_origin = Vector2i(0, 82)\n8:20/1 = 1\n8:20/1/flip_h = true\n8:20/1/texture_origin = Vector2i(0, 88)\n0:13/size_in_atlas = Vector2i(4, 5)\n0:13/next_alternative_id = 3\n0:13/0 = 0\n0:13/1 = 1\n0:13/1/flip_h = true\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_ebcbt\"]\ntexture = ExtResource(\"12_4re2u\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_q3iam\"]\ntexture = ExtResource(\"13_7iuuj\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/next_alternative_id = 2\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/next_alternative_id = 2\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/next_alternative_id = 2\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n0:1/next_alternative_id = 2\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/next_alternative_id = 2\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/next_alternative_id = 2\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_x8mjp\"]\ntexture = ExtResource(\"14_mhdnl\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 64)\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 64)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 64)\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 64)\n0:4/0 = 0\n0:4/0/texture_origin = Vector2i(0, 64)\n1:4/0 = 0\n1:4/0/texture_origin = Vector2i(0, 64)\n2:4/0 = 0\n2:4/0/texture_origin = Vector2i(0, 64)\n3:4/0 = 0\n3:4/0/texture_origin = Vector2i(0, 64)\n0:5/0 = 0\n0:5/0/texture_origin = Vector2i(0, 64)\n1:5/0 = 0\n1:5/0/texture_origin = Vector2i(0, 64)\n2:5/0 = 0\n2:5/0/texture_origin = Vector2i(0, 64)\n3:5/0 = 0\n3:5/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_psi0x\"]\ntexture = ExtResource(\"15_mthcg\")\ntexture_region_size = Vector2i(128, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 96)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 96)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 96)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_ovu2o\"]\ntexture = ExtResource(\"16_dki2r\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_4gi2s\"]\ntexture = ExtResource(\"26_fp87b\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(2, 2)\n0:0/next_alternative_id = 4\n0:0/0 = 0\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/2 = 2\n0:0/2/flip_h = true\n0:0/2/flip_v = true\n0:0/3 = 3\n0:0/3/flip_v = true\n2:0/size_in_atlas = Vector2i(2, 2)\n2:0/next_alternative_id = 4\n2:0/0 = 0\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/2 = 2\n2:0/2/flip_h = true\n2:0/2/flip_v = true\n2:0/3 = 3\n2:0/3/flip_v = true\n4:0/size_in_atlas = Vector2i(2, 1)\n4:0/next_alternative_id = 4\n4:0/0 = 0\n4:0/1 = 1\n4:0/1/flip_h = true\n4:0/2 = 2\n4:0/2/flip_h = true\n4:0/2/flip_v = true\n4:0/3 = 3\n4:0/3/flip_v = true\n6:0/size_in_atlas = Vector2i(2, 1)\n6:0/next_alternative_id = 4\n6:0/0 = 0\n6:0/1 = 1\n6:0/1/flip_h = true\n6:0/2 = 2\n6:0/2/flip_h = true\n6:0/2/flip_v = true\n6:0/3 = 3\n6:0/3/flip_v = true\n4:1/next_alternative_id = 4\n4:1/0 = 0\n4:1/1 = 1\n4:1/1/flip_h = true\n4:1/2 = 2\n4:1/2/flip_h = true\n4:1/2/flip_v = true\n4:1/3 = 3\n4:1/3/flip_v = true\n5:1/next_alternative_id = 4\n5:1/0 = 0\n5:1/1 = 1\n5:1/1/flip_h = true\n5:1/2 = 2\n5:1/2/flip_h = true\n5:1/2/flip_v = true\n5:1/3 = 3\n5:1/3/flip_v = true\n6:1/next_alternative_id = 4\n6:1/0 = 0\n6:1/1 = 1\n6:1/1/flip_h = true\n6:1/2 = 2\n6:1/2/flip_h = true\n6:1/2/flip_v = true\n6:1/3 = 3\n6:1/3/flip_v = true\n7:1/next_alternative_id = 4\n7:1/0 = 0\n7:1/1 = 1\n7:1/1/flip_h = true\n7:1/2 = 2\n7:1/2/flip_h = true\n7:1/2/flip_v = true\n7:1/3 = 3\n7:1/3/flip_v = true\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_827b0\"]\ntexture = ExtResource(\"18_8rk7a\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_0ecfs\"]\ntexture = ExtResource(\"30_qsvfe\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(2, 2)\n0:0/next_alternative_id = 4\n0:0/0 = 0\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/2 = 2\n0:0/2/flip_h = true\n0:0/2/flip_v = true\n0:0/3 = 3\n0:0/3/flip_v = true\n2:0/next_alternative_id = 4\n2:0/0 = 0\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/2 = 2\n2:0/2/flip_h = true\n2:0/2/flip_v = true\n2:0/3 = 3\n2:0/3/flip_v = true\n2:1/next_alternative_id = 4\n2:1/0 = 0\n2:1/1 = 1\n2:1/1/flip_h = true\n2:1/2 = 2\n2:1/2/flip_h = true\n2:1/2/flip_v = true\n2:1/3 = 3\n2:1/3/flip_v = true\n3:0/next_alternative_id = 4\n3:0/0 = 0\n3:0/1 = 1\n3:0/1/flip_h = true\n3:0/2 = 2\n3:0/2/flip_h = true\n3:0/2/flip_v = true\n3:0/3 = 3\n3:0/3/flip_v = true\n3:1/next_alternative_id = 4\n3:1/0 = 0\n3:1/1 = 1\n3:1/1/flip_h = true\n3:1/2 = 2\n3:1/2/flip_h = true\n3:1/2/flip_v = true\n3:1/3 = 3\n3:1/3/flip_v = true\n4:0/next_alternative_id = 4\n4:0/0 = 0\n4:0/1 = 1\n4:0/1/flip_h = true\n4:0/2 = 2\n4:0/2/flip_h = true\n4:0/2/flip_v = true\n4:0/3 = 3\n4:0/3/flip_v = true\n4:1/next_alternative_id = 4\n4:1/0 = 0\n4:1/1 = 1\n4:1/1/flip_h = true\n4:1/2 = 2\n4:1/2/flip_h = true\n4:1/2/flip_v = true\n4:1/3 = 3\n4:1/3/flip_v = true\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_ngq0r\"]\ntexture = ExtResource(\"20_7fi8d\")\ntexture_region_size = Vector2i(256, 384)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 128)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 128)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 128)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 128)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_j1xjs\"]\ntexture = ExtResource(\"32_188qm\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(2, 2)\n0:0/next_alternative_id = 2\n0:0/0 = 0\n0:0/1 = 1\n0:0/1/flip_h = true\n0:2/size_in_atlas = Vector2i(2, 2)\n0:2/next_alternative_id = 2\n0:2/0 = 0\n0:2/1 = 1\n0:2/1/flip_h = true\n0:4/size_in_atlas = Vector2i(2, 2)\n0:4/next_alternative_id = 2\n0:4/0 = 0\n0:4/1 = 1\n0:4/1/flip_h = true\n0:6/size_in_atlas = Vector2i(2, 3)\n0:6/next_alternative_id = 3\n0:6/0 = 0\n0:6/0/texture_origin = Vector2i(36, 30)\n0:6/1 = 1\n0:6/1/flip_h = true\n0:6/1/texture_origin = Vector2i(-36, 26)\n0:6/2 = 2\n0:6/2/flip_h = true\n0:6/2/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_k4jfy\"]\ntexture = ExtResource(\"33_ls46m\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(2, 2)\n0:0/next_alternative_id = 8\n0:0/0 = 0\n0:0/1 = 1\n0:0/1/flip_h = true\n0:0/2 = 2\n0:0/2/flip_h = true\n0:0/2/flip_v = true\n0:0/3 = 3\n0:0/3/flip_v = true\n0:0/4 = 4\n0:0/4/transpose = true\n0:0/5 = 5\n0:0/5/flip_v = true\n0:0/5/transpose = true\n0:0/6 = 6\n0:0/6/flip_h = true\n0:0/6/flip_v = true\n0:0/6/transpose = true\n0:0/7 = 7\n0:0/7/flip_h = true\n0:0/7/transpose = true\n2:0/next_alternative_id = 4\n2:0/0 = 0\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/2 = 2\n2:0/2/flip_h = true\n2:0/2/flip_v = true\n2:0/3 = 3\n2:0/3/flip_v = true\n2:1/next_alternative_id = 9\n2:1/0 = 0\n2:1/1 = 1\n2:1/1/flip_h = true\n2:1/2 = 2\n2:1/2/flip_h = true\n2:1/2/flip_v = true\n2:1/3 = 3\n2:1/3/flip_v = true\n2:1/4 = 4\n2:1/4/transpose = true\n2:1/5 = 5\n2:1/5/flip_v = true\n2:1/5/transpose = true\n2:1/6 = 6\n2:1/6/flip_h = true\n2:1/6/transpose = true\n2:1/8 = 8\n2:1/8/flip_h = true\n2:1/8/flip_v = true\n2:1/8/transpose = true\n3:1/next_alternative_id = 4\n3:1/0 = 0\n3:1/1 = 1\n3:1/1/flip_h = true\n3:1/2 = 2\n3:1/2/flip_h = true\n3:1/2/flip_v = true\n3:1/3 = 3\n3:1/3/flip_v = true\n3:0/next_alternative_id = 4\n3:0/0 = 0\n3:0/1 = 1\n3:0/1/flip_h = true\n3:0/2 = 2\n3:0/2/flip_h = true\n3:0/2/flip_v = true\n3:0/3 = 3\n3:0/3/flip_v = true\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_a1wbi\"]\ntexture = ExtResource(\"34_crpbh\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:0/size_in_atlas = Vector2i(4, 2)\n0:0/next_alternative_id = 5\n0:0/0 = 0\n0:0/1 = 1\n0:0/1/flip_h = true\n4:0/size_in_atlas = Vector2i(2, 2)\n4:0/next_alternative_id = 2\n4:0/0 = 0\n4:0/1 = 1\n4:0/1/flip_h = true\n6:0/size_in_atlas = Vector2i(2, 1)\n6:0/next_alternative_id = 2\n6:0/0 = 0\n6:0/1 = 1\n6:0/1/flip_h = true\n6:1/size_in_atlas = Vector2i(2, 1)\n6:1/next_alternative_id = 2\n6:1/0 = 0\n6:1/1 = 1\n6:1/1/flip_h = true\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_7fm2h\"]\ntexture = ExtResource(\"35_hhfel\")\ntexture_region_size = Vector2i(128, 128)\nuse_texture_padding = false\n0:1/next_alternative_id = 2\n0:1/0 = 0\n0:1/1 = 1\n0:1/1/flip_h = true\n0:2/next_alternative_id = 2\n0:2/0 = 0\n0:2/1 = 1\n0:2/1/flip_h = true\n1:2/size_in_atlas = Vector2i(3, 1)\n1:2/next_alternative_id = 2\n1:2/0 = 0\n1:2/1 = 1\n1:2/1/flip_h = true\n2:0/size_in_atlas = Vector2i(2, 2)\n2:0/next_alternative_id = 2\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n2:0/1 = 1\n2:0/1/flip_h = true\n2:0/1/texture_origin = Vector2i(0, 64)\n4:0/size_in_atlas = Vector2i(4, 3)\n4:0/next_alternative_id = 2\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 128)\n4:0/1 = 1\n4:0/1/flip_h = true\n4:0/1/texture_origin = Vector2i(0, 128)\n1:1/0 = 0\n\n[resource]\ntile_shape = 1\ntile_layout = 5\ntile_size = Vector2i(64, 32)\nsources/2 = SubResource(\"TileSetAtlasSource_tdfoj\")\nsources/4 = SubResource(\"TileSetAtlasSource_4gi2s\")\nsources/5 = SubResource(\"TileSetAtlasSource_0ecfs\")\nsources/6 = SubResource(\"TileSetAtlasSource_j1xjs\")\nsources/7 = SubResource(\"TileSetAtlasSource_k4jfy\")\nsources/8 = SubResource(\"TileSetAtlasSource_a1wbi\")\nsources/9 = SubResource(\"TileSetAtlasSource_7fm2h\")\nsources/10 = SubResource(\"TileSetAtlasSource_8r7kx\")\nsources/11 = SubResource(\"TileSetAtlasSource_adm57\")\nsources/12 = SubResource(\"TileSetAtlasSource_7frxb\")\nsources/13 = SubResource(\"TileSetAtlasSource_c1qpu\")\nsources/14 = SubResource(\"TileSetAtlasSource_k8mwm\")\nsources/15 = SubResource(\"TileSetAtlasSource_dkfhl\")\nsources/17 = SubResource(\"TileSetAtlasSource_3i46i\")\nsources/20 = SubResource(\"TileSetAtlasSource_ebcbt\")\nsources/22 = SubResource(\"TileSetAtlasSource_q3iam\")\nsources/24 = SubResource(\"TileSetAtlasSource_x8mjp\")\nsources/28 = SubResource(\"TileSetAtlasSource_psi0x\")\nsources/32 = SubResource(\"TileSetAtlasSource_ovu2o\")\nsources/49 = SubResource(\"TileSetAtlasSource_827b0\")\nsources/51 = SubResource(\"TileSetAtlasSource_ngq0r\")\nsources/0 = SubResource(\"TileSetAtlasSource_6it4p\")\nsources/1 = SubResource(\"TileSetAtlasSource_jku06\")\nsources/16 = SubResource(\"TileSetAtlasSource_ld48b\")\npattern_0 = SubResource(\"TileMapPattern_3glom\")\npattern_1 = SubResource(\"TileMapPattern_7h0so\")\n"
  },
  {
    "path": "resources/ui_textures/buff_group_both.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b7oawq286s2ex\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_x54e5\"]\n\n\n[resource]\natlas = ExtResource(\"1_x54e5\")\nregion = Rect2(128, 384, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/buff_group_incoming.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://k1kci4ca4byg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_ml2fi\"]\n\n\n[resource]\natlas = ExtResource(\"1_ml2fi\")\nregion = Rect2(256, 384, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/buff_group_none.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dho1jq3a82j7u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_r0cwy\"]\n\n\n[resource]\natlas = ExtResource(\"1_r0cwy\")\nregion = Rect2(0, 256, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/buff_group_outgoing.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bfao5ylpuaon7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_n7ped\"]\n\n\n[resource]\natlas = ExtResource(\"1_n7ped\")\nregion = Rect2(0, 384, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/button_container_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://diwdxkuywfhj5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_712eh\"]\n\n[resource]\natlas = ExtResource(\"1_712eh\")\nregion = Rect2(790, 443, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/common_background.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://m5xtdjyjr2xu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_vst1b\"]\n\n[resource]\natlas = ExtResource(\"1_vst1b\")\nregion = Rect2(139, 451, 108, 108)\n"
  },
  {
    "path": "resources/ui_textures/common_unit_button.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://yp3jg4xvj4g4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_knpsk\"]\n\n\n[resource]\natlas = ExtResource(\"1_knpsk\")\nregion = Rect2(130, 3, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/common_unit_button_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cp0p7pvsidg6k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_81jhl\"]\n\n[resource]\natlas = ExtResource(\"1_81jhl\")\nregion = Rect2(130, 311, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/info_icon.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dkbnigykkqip2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_pswb0\"]\n\n\n[resource]\natlas = ExtResource(\"1_pswb0\")\nregion = Rect2(256, 256, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/menu_option_round_button.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpu8gd07dyjkg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_5e7my\"]\n\n\n[resource]\natlas = ExtResource(\"1_5e7my\")\nregion = Rect2(790, 74, 48, 48)\n"
  },
  {
    "path": "resources/ui_textures/menu_option_round_button_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bpu8gd07dyjkg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_ob6tk\"]\n\n[resource]\natlas = ExtResource(\"1_ob6tk\")\nregion = Rect2(790, 11, 48, 48)\n"
  },
  {
    "path": "resources/ui_textures/portal_lives_round_bg.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://butcq5anduco8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_fq5bn\"]\n\n[resource]\natlas = ExtResource(\"1_fq5bn\")\nregion = Rect2(915, 6, 119, 119)\n"
  },
  {
    "path": "resources/ui_textures/rare_background.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://byo5dkh3m5rlm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_466yc\"]\n\n[resource]\natlas = ExtResource(\"1_466yc\")\nregion = Rect2(397, 450, 108, 108)\n"
  },
  {
    "path": "resources/ui_textures/rare_unit_button.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://diwvf58ei1rx3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_tlmsa\"]\n\n\n[resource]\natlas = ExtResource(\"1_tlmsa\")\nregion = Rect2(390, 3, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/rare_unit_button_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c38vf5tkkqr2c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_k766g\"]\n\n\n[resource]\natlas = ExtResource(\"1_k766g\")\nregion = Rect2(390, 310, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_center_l.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=3 format=3 uid=\"uid://cfgwdmgl12iia\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_bqg8q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hd8h5\"]\natlas = ExtResource(\"1_bqg8q\")\nregion = Rect2(1105, 367, 156, 176)\n\n[resource]\natlas = SubResource(\"AtlasTexture_hd8h5\")\nregion = Rect2(1100, 4, 160, 219)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_l.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://s4h31j7p5184\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_dior7\"]\n\n[resource]\natlas = ExtResource(\"1_dior7\")\nregion = Rect2(1095, 180, 176, 178)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_left_l.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bgbaygvpg0we0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_xwu3p\"]\n\n\n[resource]\natlas = ExtResource(\"1_xwu3p\")\nregion = Rect2(1094, 4, 167, 169)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_m.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dex1xjcdq1fv7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_dior7\"]\n\n[resource]\natlas = ExtResource(\"1_dior7\")\nregion = Rect2(1283, 192, 139, 141)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_right_l.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://b5cjywescmcmr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_7aca7\"]\n\n\n[resource]\natlas = ExtResource(\"1_7aca7\")\nregion = Rect2(1266, 5, 167, 169)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_s.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://lu1adtr8xmdf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_p8vee\"]\n\n[resource]\natlas = ExtResource(\"1_p8vee\")\nregion = Rect2(853, 74, 48, 48)\n"
  },
  {
    "path": "resources/ui_textures/rect_container_s_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d2jajg0v1dwpx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_6247j\"]\n\n\n[resource]\natlas = ExtResource(\"1_6247j\")\nregion = Rect2(853, 11, 48, 48)\n"
  },
  {
    "path": "resources/ui_textures/speed_fast.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cny5e3y68r18y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_ca3h1\"]\n\n[resource]\natlas = ExtResource(\"1_ca3h1\")\nregion = Rect2(768, 384, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/speed_fastest.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c1cbjc01sbgsu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_b804w\"]\n\n[resource]\natlas = ExtResource(\"1_b804w\")\nregion = Rect2(896, 384, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/speed_normal.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://c8fri6mdej3gu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_2n5fd\"]\n\n[resource]\natlas = ExtResource(\"1_2n5fd\")\nregion = Rect2(384, 128, 128, 128)\n"
  },
  {
    "path": "resources/ui_textures/stash_panel_background.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://con8k4q85kahx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_dekp6\"]\n\n\n[resource]\natlas = ExtResource(\"1_dekp6\")\nregion = Rect2(1, 136, 1087, 161)\n"
  },
  {
    "path": "resources/ui_textures/uncommon_background.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://jetwabbmtpbn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_kn3bk\"]\n\n[resource]\natlas = ExtResource(\"1_kn3bk\")\nregion = Rect2(270, 450, 108, 108)\n"
  },
  {
    "path": "resources/ui_textures/uncommon_unit_button.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://ct1psn85fl5p3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_3cl7n\"]\n\n\n[resource]\natlas = ExtResource(\"1_3cl7n\")\nregion = Rect2(260, 3, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/uncommon_unit_button_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://dc3g5tt1o6mxf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_mm4yw\"]\n\n\n[resource]\natlas = ExtResource(\"1_mm4yw\")\nregion = Rect2(260, 311, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/unique_background.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://esujtr6kx747\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_r8agc\"]\n\n[resource]\natlas = ExtResource(\"1_r8agc\")\nregion = Rect2(529, 450, 108, 108)\n"
  },
  {
    "path": "resources/ui_textures/unique_unit_button.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://boffddx5pccy5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_q72rf\"]\n\n\n[resource]\natlas = ExtResource(\"1_q72rf\")\nregion = Rect2(519, 2, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/unique_unit_button_hover.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://d3dsuc1s3cn6y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_ygpw7\"]\n\n\n[resource]\natlas = ExtResource(\"1_ygpw7\")\nregion = Rect2(519, 310, 124, 124)\n"
  },
  {
    "path": "resources/ui_textures/unit_button_disabled.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://bya4q121hruh1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"1_ra1np\"]\n\n[resource]\natlas = ExtResource(\"1_ra1np\")\nregion = Rect2(10, 11, 110, 109)\n"
  },
  {
    "path": "resources/ui_textures/upgrade_icon.tres",
    "content": "[gd_resource type=\"AtlasTexture\" load_steps=2 format=3 uid=\"uid://cgcqdoxetpbmq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"1_wywp5\"]\n\n\n[resource]\natlas = ExtResource(\"1_wywp5\")\nregion = Rect2(0, 128, 128, 128)\n"
  },
  {
    "path": "src/README.md",
    "content": "This folder contains scene files (.tscn) and script files (.gd) - the main code of the game.\n"
  },
  {
    "path": "src/actions/action.gd",
    "content": "class_name Action\n\n\n# Wraps Dictionary which needs to be passed through RPC.\n# Need to pass Dictionaries through RPC because Godot RPC\n# doesn't support passing custom classes.\n# \n# Parameters -> Action:\n#     var action: Action = ActionFoo.make(bar, baz)\n#\n# Action -> Dictionary:\n#     var serialized_action: Dictionary = action.serialize()\n\n\nenum Field {\n\tTYPE,\n\tPLAYER_ID,\n\tCHAT_MESSAGE,\n\tTOWER_ID,\n\tPOSITION,\n\tUID,\n\tUID_2,\n\tUID_LIST,\n\tBUILDER_ID,\n\tSRC_ITEM_CONTAINER_UID,\n\tDEST_ITEM_CONTAINER_UID,\n\tCLICKED_INDEX,\n\tBUFFGROUP,\n\tBUFFGROUP_MODE,\n\tELEMENT,\n\tWISDOM_UPGRADES,\n}\n\nenum Type {\n\tNONE,\n\tIDLE,\n\tCHAT,\n\tSET_PLAYER_NAME,\n\tBUILD_TOWER,\n\tUPGRADE_TOWER,\n\tTRANSFORM_TOWER,\n\tSELL_TOWER,\n\tSELECT_BUILDER,\n\tSELECT_WISDOM_UPGRADES,\n\tTOGGLE_AUTOCAST,\n\tCONSUME_ITEM,\n\tDROP_ITEM,\n\tMOVE_ITEM,\n\tSWAP_ITEMS,\n\tAUTOFILL,\n\tTRANSMUTE,\n\tRESEARCH_ELEMENT,\n\tROLL_TOWERS,\n\tSTART_NEXT_WAVE,\n\tAUTOCAST,\n\tFOCUS_TARGET,\n\tCHANGE_BUFFGROUP,\n\tSELECT_UNIT,\n\tSORT_ITEM_STASH,\n}\n\n\nvar _data: Dictionary\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(data: Dictionary):\n\t_data = data\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc serialize() -> Dictionary:\n\treturn _data\n"
  },
  {
    "path": "src/actions/action_autocast.gd",
    "content": "class_name ActionAutocast\n\n\nstatic func make(autocast_uid: int, target_uid: int, target_pos: Vector2) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.AUTOCAST,\n\t\tAction.Field.UID: autocast_uid,\n\t\tAction.Field.UID_2: target_uid,\n\t\tAction.Field.POSITION: target_pos,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, autocast: Autocast) -> bool:\n\tif autocast == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAILED_TO_CAST\"))\n\n\t\treturn false\n\n\tif !autocast.can_cast():\n\t\tautocast.add_cast_error_message()\n\n\t\treturn false\n\n\tvar caster: Unit = autocast.get_caster()\n\tvar player_match: bool = caster.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\n\t\treturn false\n\n\treturn true\n\n\n# NOTE: not doing range check on purpose. Range check is\n# performed when action is requested and if target went out\n# of range during latency, we still execute the cast.\nstatic func execute(action: Dictionary, player: Player):\n\tvar autocast_uid: int = action[Action.Field.UID]\n\tvar target_uid: int = action[Action.Field.UID_2]\n\tvar target_pos: Vector2 = action[Action.Field.POSITION]\n\t\n\tvar autocast: Autocast = GroupManager.get_by_uid(\"autocasts\", autocast_uid)\n\n\tvar verify_ok: bool = ActionAutocast.verify(player, autocast)\n\n\tif !verify_ok:\n\t\treturn\n\n\tif autocast.type_is_immediate():\n\t\tvar target: Unit = null\n\t\tautocast.do_cast(target)\n\telif autocast.type_is_point():\n\t\tautocast.do_cast_at_pos(target_pos)\n\telse:\n\t\tvar target: Unit = GroupManager.get_by_uid(\"units\", target_uid)\n\n\t\tif target == null:\n\t\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_TARGET_NOT_VALID\"))\n\n\t\t\treturn\n\n\t\tautocast.do_cast(target)\n"
  },
  {
    "path": "src/actions/action_autofill.gd",
    "content": "class_name ActionAutofill\n\n\n# NOTE: autofill action needs to store the item list because\n# it is simpler. An alternative approach would be to pass\n# recipe and rarity filter, which couples multiplayer peers\n# too much to UI state of player who initiated the autofill\n# action.\n\n\nstatic func make(autofill_uid_list: Array[int]) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.AUTOFILL,\n\t\tAction.Field.UID_LIST: autofill_uid_list,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar autofill_uid_list: Array = action[Action.Field.UID_LIST]\n\n\tvar autofill_list: Array[Item] = []\n\tfor item_uid in autofill_uid_list:\n\t\tvar item_node: Node = GroupManager.get_by_uid(\"items\", item_uid)\n\t\tvar item: Item = item_node as Item\n\n\t\tif item == null:\n\t\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAILED_TO_AUTOFILL\"))\n\n\t\t\treturn\n\n\t\tautofill_list.append(item)\n\n\tvar item_stash: ItemContainer = player.get_item_stash()\n\tvar horadric_stash: ItemContainer = player.get_horadric_stash()\n\n# \tReturn current horadric cube contents to item stash\n\tvar horadric_items_initial: Array[Item] = horadric_stash.get_item_list()\n\tfor item in horadric_items_initial:\n\t\thoradric_stash.remove_item(item)\n\t\titem_stash.add_item(item)\n\n#\tMove autofill items from item stash to horadric stash\n\tfor item in autofill_list:\n\t\titem_stash.remove_item(item)\n\t\thoradric_stash.add_item(item)\n"
  },
  {
    "path": "src/actions/action_build_tower.gd",
    "content": "class_name ActionBuildTower\n\n\nstatic func make(tower_id_arg: int, position_arg: Vector2) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.BUILD_TOWER,\n\t\tAction.Field.TOWER_ID: tower_id_arg,\n\t\tAction.Field.POSITION: position_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player, build_space: BuildSpace):\n\tvar tower_id: int = action[Action.Field.TOWER_ID]\n\tvar mouse_pos: Vector2 = action[Action.Field.POSITION]\n\n\tvar verify_ok: bool = ActionBuildTower.verify(player, build_space, tower_id, mouse_pos)\n\n\tif !verify_ok:\n\t\treturn\n\n\tplayer.add_food_for_tower(tower_id)\n\t\n\tvar build_cost: float = TowerProperties.get_cost(tower_id)\n\tplayer.spend_gold(build_cost)\n\t\n\tvar tomes_cost: int = TowerProperties.get_tome_cost(tower_id)\n\tplayer.spend_tomes(tomes_cost)\n\n\tplayer.disable_rolling()\n\n\tvar tower_stash: TowerStash = player.get_tower_stash()\n\ttower_stash.spend_tower(tower_id)\n\n\tvar new_tower: Tower = Tower.make(tower_id, player)\n\n#\tNOTE: need to add tile height to position because towers\n#\tare built at ground floor\n\tvar build_position_canvas: Vector2 = VectorUtils.snap_canvas_pos_to_buildable_pos(mouse_pos)\n\tbuild_position_canvas.y += Constants.TILE_SIZE.y\n\tvar build_position: Vector2 = VectorUtils.canvas_to_wc3_2d(build_position_canvas)\n\tnew_tower.set_position_wc3_2d(build_position)\n\n\tUtils.add_object_to_world(new_tower)\n\n\tbuild_space.set_occupied_by_tower(new_tower, true)\n\n\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/build_tower.tscn\", new_tower, Unit.BodyPart.ORIGIN)\n\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_TOWERS)\n\n\tEventBus.built_a_tower.emit()\n\n\nstatic func verify(player: Player, build_space: BuildSpace, tower_id: int, mouse_pos: Vector2) -> bool:\n\tvar enough_resources: bool = BuildTower.enough_resources_for_tower(tower_id, player)\n\n\tif !enough_resources:\n\t\tBuildTower.add_error_about_building_tower(tower_id, player)\n\n\t\treturn false\n\n\tvar tower_stash: TowerStash = player.get_tower_stash()\n\tvar tower_exists_in_stash: bool = tower_stash.has_tower(tower_id)\n\tif !tower_exists_in_stash:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_HAVE_TOWER\"))\n\n\t\treturn false\n\n\tvar can_build: bool = build_space.can_build_at_pos(player, mouse_pos)\n\n\tif !can_build:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_BUILD\"))\n\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_change_buffgroup.gd",
    "content": "class_name ActionChangeBuffgroup\n\n\nstatic func make(tower_uid: int, buff_group: int, new_mode: BuffGroupMode.enm) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.CHANGE_BUFFGROUP,\n\t\tAction.Field.UID: tower_uid,\n\t\tAction.Field.BUFFGROUP: buff_group,\n\t\tAction.Field.BUFFGROUP_MODE: new_mode,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, tower: Tower) -> bool:\n\tif tower == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_BUFFGROUP\"))\n\n\t\treturn false\n\n\tvar player_match: bool = tower.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\n\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar tower_uid: int = action[Action.Field.UID]\n\tvar buff_group: int = action[Action.Field.BUFFGROUP]\n\tvar new_mode: BuffGroupMode.enm = action[Action.Field.BUFFGROUP_MODE]\n\n\tvar tower_node: Node = GroupManager.get_by_uid(\"towers\", tower_uid)\n\tvar tower: Tower = tower_node as Tower\n\n\tvar verify_ok: bool = ActionChangeBuffgroup.verify(player, tower)\n\tif !verify_ok:\n\t\treturn\n\n\ttower.set_buff_group_mode(buff_group, new_mode)\n"
  },
  {
    "path": "src/actions/action_chat.gd",
    "content": "class_name ActionChat\n\n\nstatic func make(chat_message_arg: String) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.CHAT,\n\t\tAction.Field.CHAT_MESSAGE: chat_message_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player, hud: HUD, chat_commands: ChatCommands):\n\tvar message: String = action[Action.Field.CHAT_MESSAGE]\n\n\tvar is_chat_command: bool = !message.is_empty() && message[0] == \"/\"\n\t\n\tif is_chat_command:\n\t\tchat_commands.process_command(player, message)\n\telse:\n\t\thud.add_chat_message(player, message)\n"
  },
  {
    "path": "src/actions/action_consume_item.gd",
    "content": "class_name ActionConsumeItem\n\n\nstatic func make(item_uid_arg: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.CONSUME_ITEM,\n\t\tAction.Field.UID: item_uid_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, item: Item) -> bool:\n\tif item == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_CONSUME_ITEM\"))\n\n\t\treturn false\n\n\tvar player_match: bool = item.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_ITEM\"))\n\n\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar item_uid: int = action[Action.Field.UID]\n\n\tvar item_node: Node = GroupManager.get_by_uid(\"items\", item_uid)\n\tvar item: Item = item_node as Item\n\n\tvar verify_ok: bool = ActionConsumeItem.verify(player, item)\n\tif !verify_ok:\n\t\treturn\n\n\titem.consume()\n"
  },
  {
    "path": "src/actions/action_drop_item.gd",
    "content": "class_name ActionDropItem\n\n\nstatic func make(item_uid_arg: int, position_arg: Vector2, src_item_container_uid_arg: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.DROP_ITEM,\n\t\tAction.Field.POSITION: position_arg,\n\t\tAction.Field.UID: item_uid_arg,\n\t\tAction.Field.SRC_ITEM_CONTAINER_UID: src_item_container_uid_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar position_canvas: Vector2 = action[Action.Field.POSITION]\n\tvar item_uid: int = action[Action.Field.UID]\n\tvar src_item_container_uid: int = action[Action.Field.SRC_ITEM_CONTAINER_UID]\n\n\tvar item: Item = GroupManager.get_by_uid(\"items\", item_uid)\n\tvar src_item_container: ItemContainer = GroupManager.get_by_uid(\"item_containers\", src_item_container_uid)\n\n\tvar verify_ok: bool = ActionDropItem.verify(player, item, src_item_container)\n\tif !verify_ok:\n\t\treturn\n\n\tsrc_item_container.remove_item(item)\n\n\tvar position_wc3_2d: Vector2 = VectorUtils.canvas_to_wc3_2d(position_canvas)\n\tvar position_wc3: Vector3 = Vector3(position_wc3_2d.x, position_wc3_2d.y, 0)\n\tvar item_drop: ItemDrop = ItemDrop.make(item, position_wc3)\n\tUtils.add_object_to_world(item_drop)\n\titem.fly_to_stash(0.0)\n\n\nstatic func verify(player: Player, item: Item, src_container: ItemContainer) -> bool:\n\tif item == null || src_container == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_DROP_ITEM\"))\n\t\t\n\t\treturn false\n\n\tvar item_exists_in_src_container: bool = src_container.has(item)\n\tif !item_exists_in_src_container:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_DROP_ITEM\"))\n\t\t\n\t\treturn false\n\n\tvar player_match: bool = item.get_player() == player && src_container.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_ITEM\"))\n\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_focus_target.gd",
    "content": "class_name ActionFocusTarget\n\n\nstatic func make(target_uid: int, selected_tower_uid: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.FOCUS_TARGET,\n\t\tAction.Field.UID: target_uid,\n\t\tAction.Field.UID_2: selected_tower_uid,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, target: Unit, selected_tower: Tower) -> bool:\n\tif target == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_INVALID_TARGET\"))\n\n\t\treturn false\n\n\tif selected_tower != null:\n\t\tvar player_match: bool = selected_tower.get_player() == player\n\n\t\tif !player_match:\n\t\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\n\t\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar target_uid: int = action[Action.Field.UID]\n\tvar selected_tower_uid: int = action[Action.Field.UID_2]\n\n\tvar target: Unit = GroupManager.get_by_uid(\"creeps\", target_uid)\n\tvar selected_tower: Unit = GroupManager.get_by_uid(\"towers\", selected_tower_uid)\n\n\tvar verify_ok: bool = ActionFocusTarget.verify(player, target, selected_tower)\n\tif !verify_ok:\n\t\treturn\n\n# \t1. If no tower is selected, then all player towers will\n# \t   switch to the target.\n# \t2. If a tower is selected, then only the selected tower\n# \t   will switch to the target.\n\tvar tower_list: Array[Tower]\n\tif selected_tower != null:\n\t\ttower_list = [selected_tower]\n\telse:\n\t\ttower_list = Utils.get_tower_list()\n\n\tfor tower in tower_list:\n\t\tvar player_match: bool = tower.get_player() == player\n\n\t\tif !player_match:\n\t\t\tcontinue\n\n\t\ttower.force_attack_target(target)\n\n\tvar is_local_player: bool = player == PlayerManager.get_local_player()\n\tif is_local_player:\n\t\tplayer.create_focus_target_effect(target)\n"
  },
  {
    "path": "src/actions/action_idle.gd",
    "content": "class_name ActionIdle\n\n\nstatic func make() -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.IDLE,\n\t\t})\n\n\treturn action\n"
  },
  {
    "path": "src/actions/action_move_item.gd",
    "content": "class_name ActionMoveItem\n\n\nstatic func make(item_uid_arg: int, src_item_container_uid_arg: int, dest_item_container_uid_arg: int, clicked_index: int = -1) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.MOVE_ITEM,\n\t\tAction.Field.UID: item_uid_arg,\n\t\tAction.Field.SRC_ITEM_CONTAINER_UID: src_item_container_uid_arg,\n\t\tAction.Field.DEST_ITEM_CONTAINER_UID: dest_item_container_uid_arg,\n\t\tAction.Field.CLICKED_INDEX: clicked_index,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar item_uid: int = action[Action.Field.UID]\n\tvar src_item_container_uid: int = action[Action.Field.SRC_ITEM_CONTAINER_UID]\n\tvar dest_item_container_uid: int = action[Action.Field.DEST_ITEM_CONTAINER_UID]\n\tvar clicked_index: int = action[Action.Field.CLICKED_INDEX]\n\n\tvar item: Item = GroupManager.get_by_uid(\"items\", item_uid)\n\tvar src_item_container: ItemContainer = GroupManager.get_by_uid(\"item_containers\", src_item_container_uid)\n\tvar dest_item_container: ItemContainer = GroupManager.get_by_uid(\"item_containers\", dest_item_container_uid)\n\n\tvar verify_ok: bool = ActionMoveItem.verify(player, item, src_item_container, dest_item_container, clicked_index)\n\tif !verify_ok:\n\t\treturn\n\n\tsrc_item_container.remove_item(item)\n\tdest_item_container.add_item(item, clicked_index)\n\n\n# Checks if currently moved item can't be placed into\n# container because container belongs to tower and item is\n# consumable. Also adds an error messages if needed.\n# Returns true if can move.\nstatic func verify(player: Player, item: Item, src_container: ItemContainer, dest_container: ItemContainer, clicked_index: int) -> bool:\n\tif item == null || src_container == null || dest_container == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_MOVE_ITEM\"))\n\t\t\n\t\treturn false\n\n\tvar item_player_match: bool = item.get_player() == player\n\tif !item_player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_ITEM\"))\n\t\t\n\t\treturn false\n\n\tvar container_player_match: bool = src_container.get_player() == player && dest_container.get_player() == player\n\tif !container_player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\t\t\n\t\treturn false\n\n\tvar item_exists_in_src_container: bool = src_container.has(item)\n\tif !item_exists_in_src_container:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_MOVE_ITEM\"))\n\t\t\n\t\treturn false\n\n\tvar capacity: int = dest_container.get_capacity()\n\n\tif clicked_index != -1 && clicked_index >= capacity:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_INVALID_SLOT_INDEX\"))\n\n\t\treturn false\n\n#\tNOTE: need to call can_add_item() instead of\n#\thave_item_space() to handle case of adding oil to tower\n\tvar dest_has_space: bool = dest_container.can_add_item(item)\n\n\tif !dest_has_space:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NO_SPACE_FOR_ITEM\"))\n\n\t\treturn false\n\n\tvar trying_to_move_consumable_to_tower: bool = item.is_consumable() && dest_container is TowerItemContainer\n\n\tif trying_to_move_consumable_to_tower:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_EQUIP_CONSUMABLES\"))\n\t\t\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_research_element.gd",
    "content": "class_name ActionResearchElement\n\n\nstatic func make(element_arg: Element.enm) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.RESEARCH_ELEMENT,\n\t\tAction.Field.ELEMENT: element_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar element: Element.enm = action[Action.Field.ELEMENT]\n\n\tvar verify_ok: bool = ActionResearchElement.verify(player, element)\n\n\tif !verify_ok:\n\t\treturn\n\n\tplayer.research_element(element)\n\n\nstatic func verify(player: Player, element: Element.enm) -> bool:\n\tvar current_level: int = player.get_element_level(element)\n\tvar element_at_max: bool = current_level == player.get_max_element_level()\n\n\tif element_at_max:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_ELEMENT_AT_MAX_LEVEL\"))\n\n\t\treturn false\n\n\tvar can_afford_research: bool = player.can_afford_research(element)\n\n\tif !can_afford_research:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_ENOUGH_TOMES_FOR_RESEARCH\"))\n\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_roll_towers.gd",
    "content": "class_name ActionRollTowers\n\n\nstatic func make() -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.ROLL_TOWERS,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(_action: Dictionary, player: Player):\n\tvar verify_ok: bool = ActionRollTowers.verify(player)\n\n\tif !verify_ok:\n\t\treturn\n\n\tplayer.roll_starting_towers()\n\n\nstatic func verify(player: Player) -> bool:\n\tvar researched_any_elements: bool = false\n\tfor element in Element.get_list():\n\t\tvar researched_element: bool = player.get_element_level(element)\n\t\tif researched_element:\n\t\t\tresearched_any_elements = true\n\t\n\tif !researched_any_elements:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_ROLL_TOWERS\"))\n\t\n\t\treturn false\n\n\tvar tower_count_for_roll: int = player.get_tower_count_for_starting_roll()\n\n\tif tower_count_for_roll <= 0:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_ROLLS_MAXED\"))\n\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_select_builder.gd",
    "content": "class_name ActionSelectBuilder\n\n\nstatic func make(builder_id_arg: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.SELECT_BUILDER,\n\t\tAction.Field.BUILDER_ID: builder_id_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar builder_id: int = action[Action.Field.BUILDER_ID]\n\n\tvar verify_ok: bool = ActionSelectBuilder.verify(player)\n\tif !verify_ok:\n\t\treturn\n\t\n\tplayer.set_builder(builder_id)\n\n\tvar is_local_player: bool = player == PlayerManager.get_local_player()\n\tif is_local_player:\n\t\tEventBus.player_selected_builder.emit()\n\n\nstatic func verify(player: Player) -> bool:\n\tvar builder_already_selected: bool = player.get_builder() != null\n\n\tif !builder_already_selected:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_ALREADY_SELECTED_BUILDER\"))\n\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_select_unit.gd",
    "content": "class_name ActionSelectUnit\n\n\nstatic func make(unit_id: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.SELECT_UNIT,\n\t\tAction.Field.UID: unit_id,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar unit_uid: int = action[Action.Field.UID]\n\tvar unit_is_null: bool = unit_uid == -1\n\n\tvar selected_unit: Unit\n\tif unit_is_null:\n\t\tselected_unit = null\n\telse:\n\t\tvar unit_node: Node = GroupManager.get_by_uid(\"units\", unit_uid)\n\t\tselected_unit = unit_node as Unit\n\n\t\tif selected_unit == null:\n\t\t\tpush_error(\"Select unit action failed\")\n\n\t\t\treturn\n\n\tplayer.set_selected_unit(selected_unit)\n"
  },
  {
    "path": "src/actions/action_select_wisdom_upgrades.gd",
    "content": "class_name ActionSelectWisdomUpgrades\n\n\n\n# NOTE: wisdom_upgrades must be a map of\n# {upgrade_id => boolean}\n# where boolean is TRUE if upgrade_id is enabled\nstatic func make(wisdom_upgrades: Dictionary) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.SELECT_WISDOM_UPGRADES,\n\t\tAction.Field.WISDOM_UPGRADES: wisdom_upgrades,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar wisdom_upgrades: Dictionary = action[Action.Field.WISDOM_UPGRADES]\n\n\tvar builder_wisdom_multiplier: float = player.get_builder_wisdom_multiplier()\n\tvar upgrades_wisdom_multiplier_bonus: float = Utils.get_wisdom_multiplier_bonus_from_upgrades(wisdom_upgrades)\n\t\n\tvar wisdom_multiplier = builder_wisdom_multiplier + upgrades_wisdom_multiplier_bonus\n\t\n\tvar wisdom_modifier: Modifier = ActionSelectWisdomUpgrades.generate_wisdom_upgrades_modifier(wisdom_upgrades, wisdom_multiplier)\n\tplayer.set_wisdom_modifier(wisdom_modifier)\n\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.ELEMENT_MASTERY]:\n\t\tvar tomes_bonus: int = floori(40 * wisdom_multiplier)\n\t\tplayer.add_tomes(tomes_bonus)\n\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.MASTERY_OF_LOGISTICS]:\n\t\tvar food_cap_bonus: int = floori(16 * wisdom_multiplier)\n\t\tplayer.modify_food_cap(food_cap_bonus)\n\t\t\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.BOND_OF_UNITY]:\n\t\tvar lives_bonus: float = 20 * wisdom_multiplier\n\t\tplayer.get_team().modify_lives(lives_bonus)\n\t\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.FOUNDATION_OF_KNOWLEDGE]:\n\t\tvar tower_bonus_exp: float = 30 * wisdom_multiplier\n\t\tplayer.set_tower_exp_bonus(tower_bonus_exp)\n\t\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.ADVANCED_OPTICS]:\n\t\tvar bonus_attack_range: float = 25 * wisdom_multiplier\n\t\tplayer.set_attack_range_bonus(bonus_attack_range)\n\n\t# Unaffected by wisdom_multiplier\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.ELEMENTAL_OVERLOAD]:\n\t\tvar max_element_level_bonus: int = 2\n\t\tplayer._max_element_level_bonus += max_element_level_bonus\n\t\n\t# Unaffected by wisdom_multiplier\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.PINNACLE_OF_POWER]:\n\t\tvar max_tower_level_bonus: int = 2\n\t\tplayer._max_tower_level_bonus += max_tower_level_bonus\n\n\nstatic func generate_wisdom_upgrades_modifier(wisdom_upgrades: Dictionary, wisdom_multiplier: float) -> Modifier:\n\tvar modifier: Modifier = Modifier.new()\n\n\tvar upgrade_to_mod_value_map: Dictionary = {\n\t\tWisdomUpgradeProperties.Id.ADVANCED_FORTUNE: {\n\t\t\tModificationType.enm.MOD_TRIGGER_CHANCES: 0.10,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.SWIFTNESS_MASTERY: {\n\t\t\tModificationType.enm.MOD_ATTACKSPEED: 0.07,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.COMBAT_MASTERY: {\n\t\t\tModificationType.enm.MOD_DAMAGE_BASE_PERC: 0.08,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.MASTERY_OF_PAIN: {\n\t\t\tModificationType.enm.MOD_ATK_CRIT_CHANCE: 0.04,\n\t\t\tModificationType.enm.MOD_SPELL_CRIT_CHANCE: 0.04,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.ADVANCED_SORCERY: {\n\t\t\tModificationType.enm.MOD_SPELL_DAMAGE_DEALT: 0.10,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.MASTERY_OF_MAGIC: {\n\t\t\tModificationType.enm.MOD_MANA_PERC: 0.20,\n\t\t\tModificationType.enm.MOD_MANA_REGEN_PERC: 0.20,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.LOOT_MASTERY: {\n\t\t\tModificationType.enm.MOD_ITEM_CHANCE_ON_KILL: 0.12,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.ADVANCED_WISDOM: {\n\t\t\tModificationType.enm.MOD_EXP_RECEIVED: 0.20,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.PILLAGE_MASTERY: {\n\t\t\tModificationType.enm.MOD_BOUNTY_RECEIVED: 0.16,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.FORTIFIED_WILL: {\n\t\t\tModificationType.enm.MOD_DEBUFF_DURATION: -0.09,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.INNER_FOCUS: {\n\t\t\tModificationType.enm.MOD_BUFF_DURATION: 0.065,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.DEADLY_STRIKES: {\n\t\t\tModificationType.enm.MOD_ATK_CRIT_DAMAGE: 0.175,\n\t\t\tModificationType.enm.MOD_SPELL_CRIT_DAMAGE: 0.175,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.FORTUNES_FAVOR: {\n\t\t\tModificationType.enm.MOD_ITEM_QUALITY_ON_KILL: 0.065,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.CHALLENGE_CONQUEROR: {\n\t\t\tModificationType.enm.MOD_DMG_TO_CHALLENGE: 0.1,\n\t\t},\n\t\tWisdomUpgradeProperties.Id.MASTER_OF_DESTRUCTION: {\n\t\t\tModificationType.enm.MOD_DMG_TOTAL_MULTIPLIER: 0.025,\n\t\t},\n\t}\n\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_upgrade_keys: Array = wisdom_upgrades.keys()\n\tsorted_upgrade_keys.sort()\n\tfor upgrade_id in sorted_upgrade_keys:\n\t\tvar upgrade_is_enabled: bool = wisdom_upgrades[upgrade_id] == true\n\n\t\tif !upgrade_is_enabled:\n\t\t\tcontinue\n\n\t\tvar mod_values: Dictionary = upgrade_to_mod_value_map.get(upgrade_id, {})\n\n#\t\tNOTE: sort mod_type keys for deterministic order\n\t\tvar sorted_mod_keys: Array = mod_values.keys()\n\t\tsorted_mod_keys.sort()\n\t\tfor mod_type in sorted_mod_keys:\n\t\t\tvar mod_value: float = mod_values[mod_type]\n\n\t\t\tmod_value *= wisdom_multiplier\n\n\t\t\tmodifier.add_modification(mod_type, mod_value, 0)\n\n\treturn modifier\n"
  },
  {
    "path": "src/actions/action_sell_tower.gd",
    "content": "class_name ActionSellTower\n\n\nstatic func make(tower_unit_id_arg: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.SELL_TOWER,\n\t\tAction.Field.UID: tower_unit_id_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, tower: Tower) -> bool:\n\tif tower == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_SELL_TOWER\"))\n\n\t\treturn false\n\n\tvar player_match: bool = tower.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\n\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player, build_space: BuildSpace):\n\tvar tower_uid: int = action[Action.Field.UID]\n\n\tvar tower_node: Node = GroupManager.get_by_uid(\"towers\", tower_uid)\n\tvar tower: Tower = tower_node as Tower\n\n\tvar verify_ok: bool = ActionSellTower.verify(player, tower)\n\tif !verify_ok:\n\t\treturn\n\n# \tReturn tower items to item stash\n\tvar item_list: Array[Item] = tower.get_items()\n\n\tfor item in item_list:\n\t\titem.drop()\n\t\titem.fly_to_stash(0.0)\n\n\tvar tower_id: int = tower.get_id()\n\tvar sell_price: int = TowerProperties.get_sell_price(tower_id)\n\tplayer.give_gold(sell_price, tower, true, true)\n\tplayer.remove_food_for_tower(tower_id)\n\n\tbuild_space.set_occupied_by_tower(tower, false)\n\n\ttower.remove_from_game()\n"
  },
  {
    "path": "src/actions/action_sort_item_stash.gd",
    "content": "class_name ActionSortItemStash\n\n\n# NOTE: this action is not confirmed to be 100% necessary\n# but better to be safe and avoid desyncs. The sort function\n# changes the order of items which can affect gameplay logic\n# and cause desyncs if done outside Action.\n\n\nstatic func make() -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.SORT_ITEM_STASH,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(_action: Dictionary, player: Player):\n\tvar item_stash: ItemContainer = player.get_item_stash()\n\titem_stash.sort_items_by_type_rarity_and_levels()\n"
  },
  {
    "path": "src/actions/action_start_next_wave.gd",
    "content": "class_name ActionStartNextWave\n\n\nstatic func make() -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.START_NEXT_WAVE,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(_action: Dictionary, player: Player):\n\tvar verify_ok: bool = ActionStartNextWave.verify(player)\n\n\tif !verify_ok:\n\t\treturn\n\n\tvar team: Team = player.get_team()\n\tteam.start_next_wave()\n\n\nstatic func verify(player: Player) -> bool:\n\tvar team: Team = player.get_team()\n\tvar team_finished_the_game: bool = team.finished_the_game()\n\tif team_finished_the_game:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_START_WAVE_GAME_OVER\"))\n\n\t\treturn false\n\n\tvar current_level: int = team.get_level()\n\tvar wave_count: int = Globals.get_wave_count()\n\tvar reached_last_wave: bool = current_level == wave_count\n\tvar game_is_neverending: bool = Globals.game_is_neverending()\n\tif reached_last_wave && !game_is_neverending:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_START_WAVE_OUT_OF_WAVES\"))\n\n\t\treturn false\n\t\n\tvar start_wave_action_is_on_cooldown: bool = team.get_start_wave_action_is_on_cooldown()\n\tvar wave_is_in_progress: bool = team.get_wave_is_in_progress()\n\tif wave_is_in_progress || start_wave_action_is_on_cooldown:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_START_WAVE_ALREADY_IN_PROGRESS\"))\n\t\t\n\t\treturn false\n\n\treturn true\n\t\n"
  },
  {
    "path": "src/actions/action_swap_items.gd",
    "content": "class_name ActionSwapItems\n\n\nstatic func make(item_uid_src: int, item_uid_dest: int, src_item_container_uid: int, dest_item_container_uid: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.SWAP_ITEMS,\n\t\tAction.Field.UID: item_uid_src,\n\t\tAction.Field.UID_2: item_uid_dest,\n\t\tAction.Field.SRC_ITEM_CONTAINER_UID: src_item_container_uid,\n\t\tAction.Field.DEST_ITEM_CONTAINER_UID: dest_item_container_uid,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar item_uid_src: int = action[Action.Field.UID]\n\tvar item_uid_dest: int = action[Action.Field.UID_2]\n\tvar src_item_container_uid: int = action[Action.Field.SRC_ITEM_CONTAINER_UID]\n\tvar dest_item_container_uid: int = action[Action.Field.DEST_ITEM_CONTAINER_UID]\n\n\tvar item_src: Item = GroupManager.get_by_uid(\"items\", item_uid_src)\n\tvar item_dest: Item = GroupManager.get_by_uid(\"items\", item_uid_dest)\n\tvar src_item_container: ItemContainer = GroupManager.get_by_uid(\"item_containers\", src_item_container_uid)\n\tvar dest_item_container: ItemContainer = GroupManager.get_by_uid(\"item_containers\", dest_item_container_uid)\n\n\tvar verify_ok: bool = ActionSwapItems.verify(player, item_src, item_dest, src_item_container, dest_item_container)\n\tif !verify_ok:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_SWAP_ITEMS\"))\n\t\t\n\t\treturn\n\n\tvar item_src_index: int = src_item_container.get_item_index(item_src)\n\tvar item_dest_index: int = dest_item_container.get_item_index(item_dest)\n\n\tvar swapping_items_in_same_container: bool = src_item_container == dest_item_container\n\tif swapping_items_in_same_container:\n#\t\tNOTE: do extra work for the case where items are\n#\t\tswapped in same container, to ensure that their\n#\t\tindexes are swapped\n# \t\tNOTE: must remove both items first to avoid errors about\n# \t\tcapacity\n\t\tsrc_item_container.remove_item(item_src)\n\t\tdest_item_container.remove_item(item_dest)\n\n#\t\tNOTE: need to take care of order, otherwise indexes\n#\t\twill get messed up\n\t\tif item_src_index <= item_dest_index:\n\t\t\tdest_item_container.add_item(item_dest, item_src_index)\n\t\t\tdest_item_container.add_item(item_src, item_dest_index)\n\t\telse:\n\t\t\tdest_item_container.add_item(item_src, item_dest_index)\n\t\t\tdest_item_container.add_item(item_dest, item_src_index)\n\telse:\n# \t\tNOTE: must remove both items first to avoid errors about\n# \t\tcapacity\n\t\tsrc_item_container.remove_item(item_src)\n\t\tdest_item_container.remove_item(item_dest)\n\t\tdest_item_container.add_item(item_src, item_dest_index)\n\t\tsrc_item_container.add_item(item_dest, item_src_index)\n\n\n# NOTE: don't need to check for capacity because swapping\n# items doesn't change the amount of items in each container\nstatic func verify(player: Player, item_src: Item, item_dest: Item, src_container: ItemContainer, dest_container: ItemContainer) -> bool:\n\tif item_src == null || item_dest == null || src_container == null || dest_container == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_SWAP_ITEMS\"))\n\t\t\n\t\treturn false\n\n\tvar player_match: bool = item_src.get_player() == player && item_dest.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_ITEM\"))\n\t\t\n\t\treturn false\n\n\tvar item_exists_in_src_container: bool = src_container.has(item_src)\n\tvar item_exists_in_dest_container: bool = dest_container.has(item_dest)\n\tif !item_exists_in_src_container || !item_exists_in_dest_container:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_SWAP_ITEMS\"))\n\n\t\treturn false\n\n\tvar src_trying_to_move_consumable_to_tower: bool = item_src.is_consumable() && dest_container is TowerItemContainer\n\tvar dest_trying_to_move_consumable_to_tower: bool = item_dest.is_consumable() && src_container is TowerItemContainer\n\n\tif src_trying_to_move_consumable_to_tower || dest_trying_to_move_consumable_to_tower:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_EQUIP_CONSUMABLES\"))\n\t\t\n\t\treturn false\n\n\treturn true\n"
  },
  {
    "path": "src/actions/action_toggle_autocast.gd",
    "content": "class_name ActionToggleAutocast\n\n\nstatic func make(autocast_uid_arg: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.TOGGLE_AUTOCAST,\n\t\tAction.Field.UID: autocast_uid_arg,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, autocast: Autocast) -> bool:\n\tif autocast == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_TOGGLE_AUTOCAST\"))\n\n\t\treturn false\n\n\tvar caster: Unit = autocast.get_caster()\n\tif caster == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_TOGGLE_AUTOCAST_RIGHT_NOW\"))\n\n\t\treturn false\n\n\tvar player_match: bool = caster.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\t\t\n\t\treturn false\n\n\tvar can_use_auto: bool = autocast.can_use_auto_mode()\n\tif !can_use_auto:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_ABILITY_NOT_AUTOMATIC\"))\n\n\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar autocast_uid: int = action[Action.Field.UID]\n\n\tvar autocast_node: Node = GroupManager.get_by_uid(\"autocasts\", autocast_uid)\n\tvar autocast: Autocast = autocast_node as Autocast\n\n\tvar verify_ok: bool = ActionToggleAutocast.verify(player, autocast)\n\n\tif !verify_ok:\n\t\treturn\n\n\tautocast.toggle_auto_mode()\n"
  },
  {
    "path": "src/actions/action_transform_tower.gd",
    "content": "class_name ActionTransformTower\n\n\nstatic func make(prev_tower_uid: int, new_tower_id: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.TRANSFORM_TOWER,\n\t\tAction.Field.UID: prev_tower_uid,\n\t\tAction.Field.TOWER_ID: new_tower_id,\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, prev_tower: Tower, new_tower_id: int) -> bool:\n\tif prev_tower == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_FAIL_UPGRADE\"))\n\n\t\treturn false\n\n\tvar player_match: bool = prev_tower.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\t\t\n\t\treturn false\n\n\tvar tower_stash: TowerStash = player.get_tower_stash()\n\tvar tower_exists_in_stash: bool = tower_stash.has_tower(new_tower_id)\n\tif !tower_exists_in_stash:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_HAVE_TOWER_IN_STASH\"))\n\n\t\treturn false\n\n\tvar prev_tower_id: int = prev_tower.get_id()\n\tvar enough_resources: bool = BuildTower.enough_resources_for_tower(new_tower_id, player, prev_tower_id)\n\tif !enough_resources:\n\t\tBuildTower.add_error_about_building_tower(new_tower_id, player, prev_tower_id)\n\n\t\treturn false\n\n\tvar game_mode_allows_transform: bool = Globals.game_mode_allows_transform()\n\tif !game_mode_allows_transform:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_TRANSFORM_IN_BUILD_MODE\"))\n\n\t\treturn false\n\n\tvar transform_is_allowed: bool = prev_tower.get_transform_is_allowed()\n\tif !transform_is_allowed:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_TRANSFORM_RIGHT_NOW\"))\n\n\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player):\n\tvar new_tower_id: int = action[Action.Field.TOWER_ID]\n\tvar prev_tower_uid: int = action[Action.Field.UID]\n\tvar prev_tower_node: Node = GroupManager.get_by_uid(\"towers\", prev_tower_uid)\n\tvar prev_tower: Tower = prev_tower_node as Tower\n\n\tvar verify_ok: bool = ActionTransformTower.verify(player, prev_tower, new_tower_id)\n\tif !verify_ok:\n\t\treturn\n\n\tplayer.remove_food_for_tower(prev_tower.get_id())\n\tplayer.add_food_for_tower(new_tower_id)\n\n# \tNOTE: order is important here. Need to set position\n# \tbefore adding to world so that correct position can be\n# \taccessed in tower's on_create().\n\tvar new_tower: Tower = Tower.make(new_tower_id, player, prev_tower)\n\tvar prev_tower_pos: Vector2 = prev_tower.get_position_wc3_2d()\n\tnew_tower.set_position_wc3_2d(prev_tower_pos)\n\tUtils.add_object_to_world(new_tower)\n\n#\tRefund build cost for previous tower\n\tvar refund_value: int = ActionTransformTower.get_transform_refund(prev_tower.get_id(), new_tower_id)\n\tprev_tower.get_player().give_gold(refund_value, prev_tower, false, true)\n\n#\tSpend build cost for new tower\n\tvar build_cost: float = TowerProperties.get_cost(new_tower_id)\n\tplayer.spend_gold(build_cost)\n\n# \tNOTE: don't modify tome count because transform is\n# \tenabled only in random modes and tome costs are 0 in\n# \trandom mode\n\n\tprev_tower.remove_from_game()\n\n\tvar tower_stash: TowerStash = player.get_tower_stash()\n\ttower_stash.spend_tower(new_tower_id)\n\n\n# This is the value refunded when a tower is transformed\n# into another tower\nstatic func get_transform_refund(prev_tower_id: int, new_tower_id: int) -> int:\n\tvar prev_cost: int = TowerProperties.get_cost(prev_tower_id)\n\tvar prev_family: int = TowerProperties.get_family(prev_tower_id)\n\tvar new_family: int = TowerProperties.get_family(new_tower_id)\n\tvar family_is_same: bool = prev_family == new_family\n\n\tvar transform_refund: int\n\n\tif family_is_same:\n\t\ttransform_refund = floori(prev_cost * 1.0)\n\telse:\n\t\ttransform_refund = floori(prev_cost * 0.75)\n\n\treturn transform_refund\n"
  },
  {
    "path": "src/actions/action_transmute.gd",
    "content": "class_name ActionTransmute\n\n\nstatic func make() -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.TRANSMUTE,\n\t\t})\n\n\treturn action\n\n\nstatic func execute(_action: Dictionary, player: Player):\n\tvar horadric_stash: ItemContainer = player.get_horadric_stash()\n\tvar item_list: Array[Item] = horadric_stash.get_item_list()\n\tvar current_recipe: HoradricCube.Recipe = HoradricCube.get_current_recipe(player, item_list)\n\tvar can_transmute: bool = current_recipe != HoradricCube.Recipe.NONE\n\t\n\tif !can_transmute:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_VALID_RECIPE\"))\n\n\t\treturn\n\n\tvar result_item_id_list: Array[int] = HoradricCube.get_result_item_for_recipe(player, current_recipe, item_list)\n\tvar generated_items: bool = !result_item_id_list.is_empty()\n\n\tif !generated_items:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_TRANSMUTE_FAILED\"))\n\t\t\n\t\treturn\n\n\tvar result_list: Array[Item] = Utils.item_id_list_to_item_list(result_item_id_list, player)\n\n\tfor item in item_list:\n\t\thoradric_stash.remove_item(item)\n\t\n\tfor item in result_list:\n\t\thoradric_stash.add_item(item)\n"
  },
  {
    "path": "src/actions/action_upgrade_tower.gd",
    "content": "class_name ActionUpgradeTower\n\n\nstatic func make(tower_uid: int) -> Action:\n\tvar action: Action = Action.new({\n\t\tAction.Field.TYPE: Action.Type.UPGRADE_TOWER,\n\t\tAction.Field.UID: tower_uid\n\t\t})\n\n\treturn action\n\n\nstatic func verify(player: Player, prev_tower: Tower) -> bool:\n\tif prev_tower == null:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_UPGRADE_FAILED\"))\n\n\t\treturn false\n\n\tvar player_match: bool = prev_tower.get_player() == player\n\tif !player_match:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\t\t\n\t\treturn false\n\n\tvar prev_tower_id: int = prev_tower.get_id()\n\tvar upgrade_id: int = TowerProperties.get_upgrade_id_for_tower(prev_tower_id)\n\tif upgrade_id == -1:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_UPGRADE_FAILED_NO_ID\"))\n\n\t\treturn false\n\n\tvar enough_resources: bool = BuildTower.enough_resources_for_tower(upgrade_id, player, prev_tower_id)\n\tif !enough_resources:\n\t\tBuildTower.add_error_about_building_tower(upgrade_id, player, prev_tower_id)\n\n\t\treturn false\n\n\tvar transform_is_allowed: bool = prev_tower.get_transform_is_allowed()\n\tif !transform_is_allowed:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_CANT_TRANSFORM_NOW\"))\n\n\t\treturn false\n\n\treturn true\n\n\nstatic func execute(action: Dictionary, player: Player, select_unit: SelectUnit):\n\tvar preceding_tower_uid: int = action[Action.Field.UID]\n\tvar preceding_tower_node: Node = GroupManager.get_by_uid(\"towers\", preceding_tower_uid)\n\tvar preceding_tower: Tower = preceding_tower_node as Tower\n\n\tvar verify_ok: bool = ActionUpgradeTower.verify(player, preceding_tower)\n\tif !verify_ok:\n\t\treturn\n\n# \tNOTE: order is important here. Need to set position\n# \tbefore adding to world so that correct position can be\n# \taccessed in tower's on_create().\n\tvar preceding_tower_id: int = preceding_tower.get_id()\n\tvar upgrade_id: int = TowerProperties.get_upgrade_id_for_tower(preceding_tower_id)\n\tvar upgrade_tower: Tower = Tower.make(upgrade_id, player, preceding_tower)\n\tvar prev_tower_pos: Vector2 = preceding_tower.get_position_wc3_2d()\n\tupgrade_tower.set_position_wc3_2d(prev_tower_pos)\n\tUtils.add_object_to_world(upgrade_tower)\n\tpreceding_tower.remove_from_game()\n\n\tif player == PlayerManager.get_local_player():\n\t\tselect_unit.set_selected_unit(upgrade_tower)\n\n\tvar refund_for_prev_tier: float = TowerProperties.get_cost(preceding_tower_id)\n\tvar upgrade_cost: float = TowerProperties.get_cost(upgrade_id)\n\tplayer.add_gold(refund_for_prev_tier)\n\tplayer.spend_gold(upgrade_cost)\n\n\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/upgrade_tower.tscn\", upgrade_tower, Unit.BodyPart.ORIGIN)\n\tEffect.set_z_index(effect, -1)\n"
  },
  {
    "path": "src/buffs/aura.gd",
    "content": "class_name Aura\nextends Node2D\n\n# Aura applies an aura effect(buff) to targets in range of\n# caster.\n\n# NOTE: it is important to use get_units_in_range() for all\n# aura range checking code. get_units_in_range() does the\n# special range extension for towers - other range/distance\n# functions don't.\n\n# NOTE: level and level_add parameters define how aura level\n# scales with tower level.\n# aura level = level + level_add * tower_level\n# - Setting level to 0 and level_add to 1 will make aura\n#   level the same as tower level.\n# - Setting level to 100 and level_add to 2 will make aura\n#   level start at 200 and incrase by 2 for each tower\n#   level.\n\nvar _aura_range: float = 10.0\nvar _target_type: TargetType = null\nvar _target_self: bool = false\nvar _level: int = 0\nvar _level_add: int = 0\nvar _aura_effect: BuffType = null\n\nvar _caster: Unit = null\nvar _target_list: Array = []\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_caster.level_changed.connect(_on_caster_level_changed)\n\ttree_exited.connect(_on_tree_exited)\n\n\n#########################\n###       Public      ###\n#########################\n\n# Triggers REFRESH event for buffs applied by this aura.\nfunc refresh():\n\tvar caster_position: Vector2 = _caster.get_position_wc3_2d()\n\tvar units_in_range: Array = Utils.get_units_in_range(_caster, _target_type, caster_position, _aura_range)\n\n\tfor unit in units_in_range:\n\t\tvar buff: Buff = unit.get_buff_of_type(_aura_effect)\n\n\t\tif buff == null:\n\t\t\tcontinue\n\n\t\tvar buff_caster: Unit = buff.get_caster()\n\t\tvar buff_was_applied_by_this_aura: bool = buff_caster == _caster\n\n\t\tif !buff_was_applied_by_this_aura:\n\t\t\tcontinue\n\t\t\n\t\tbuff._emit_refresh_event()\n\n\nfunc get_level() -> int:\n\treturn _level + _caster.get_level() * _level_add\n\n\nfunc get_range() -> float:\n\treturn _aura_range\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _remove_aura_effect_from_units(unit_list: Array):\n\t_remove_invalid_targets()\n\n\tfor target in unit_list:\n\t\tvar buff: Buff = target.get_buff_of_type(_aura_effect)\n\n\t\tif buff != null && buff.get_caster() == _caster:\n\t\t\tbuff._remove_as_aura()\n\n\nfunc _remove_invalid_targets():\n\tvar invalid_list: Array = []\n\t\n\tfor target in _target_list:\n\t\tif !is_instance_valid(target):\n\t\t\tinvalid_list.append(target)\n\n\tfor target in invalid_list:\n\t\t_target_list.erase(target)\n\n\nfunc _change_buff_level_to_this_aura_level(buff: Buff):\n\tbuff.set_level(get_level())\n\tbuff._change_giver_of_aura_effect(_caster)\n\tbuff._emit_refresh_event()\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_manual_timer_timeout():\n\t_remove_invalid_targets()\n\n\tvar caster_position: Vector2 = _caster.get_position_wc3_2d()\n\tvar units_in_range: Array = Utils.get_units_in_range(_caster, _target_type, caster_position, _aura_range)\n\n# \tRemove buff from units that have went out of range\n\tvar removed_target_list: Array = []\n\n\tfor target in _target_list:\n\t\tvar in_range = units_in_range.has(target)\n\n\t\tif !in_range:\n\t\t\tremoved_target_list.append(target)\n\n\tfor target in removed_target_list:\n\t\t_target_list.erase(target)\n\n\t_remove_aura_effect_from_units(removed_target_list)\n\n# \tApply buff to units in range\n\tfor unit in units_in_range:\n\t\tif !_target_self && unit == _caster:\n\t\t\tcontinue\n\n\t\tvar active_buff: Buff = unit.get_buff_of_type(_aura_effect)\n\n#\t\tNOTE: If there's an active buff and it's from a\n#\t\ttower of same family but lower tier - remove it.\n#\t\tThis is to always prio auras from higher tier\n#\t\ttowers. Doesn't affect buffs defined outside tower\n#\t\tscripts, in items for example.\n#\n#\t\t[ORIGINAL_GAME_DEVIATION] The mechanic of comparing\n#\t\ttower tiers didn't exist in original game. Aura\n#\t\twhich was entered first would stay on the creep,\n#\t\teven if creep entered a stronger version of same\n#\t\taura.\n# \n#\t\tNOTE: this code section needs to be duplicated from\n#\t\tBuffType._do_stacking_behavior() because for auras\n#\t\tthis logic needs to be slightly different.\n\t\tif active_buff != null:\n\t\t\tvar owned_by_tower: bool = _aura_effect.get_is_owned_by_tower()\n\t\t\tvar family_active: int = active_buff.get_tower_family()\n\t\t\tvar family_new: int = _aura_effect.get_tower_family()\n\t\t\tvar family_is_same: bool = family_active == family_new\n\t\t\tvar tier_active: int = active_buff.get_tower_tier()\n\t\t\tvar tier_new: int = _aura_effect.get_tower_tier()\n\t\t\tvar new_tier_is_greater: bool = tier_new > tier_active\n\n\t\t\tif owned_by_tower && family_is_same && new_tier_is_greater:\n\t\t\t\tactive_buff._remove_as_aura()\n\t\t\t\tactive_buff = null\n\n\t\tif active_buff == null:\n\t\t\t_aura_effect.apply_to_unit_permanent(_caster, unit, get_level())\n\t\t\t_target_list.append(unit)\n\t\telse:\n\t\t\tvar can_increase_level: bool = active_buff.get_level() < get_level()\n\t\t\tif can_increase_level:\n\t\t\t\t_change_buff_level_to_this_aura_level(active_buff)\n\n\nfunc _on_tree_exited():\n\t_remove_aura_effect_from_units(_target_list)\n\n\n# Level down the aura buffs here when tower levels down.\n# Note that level changes are handled in _on_timer_timeout().\n# \n# NOTE: the way lving down is handled is a bit imperfect\n# because if there are two towers with same aura and one of\n# them levels down, then the aura will temporarily level\n# down for 0.2s and then go back up to the level of the\n# strongest aura. It's not critical and I couldn't find a\n# better solution which doesn't break anything else.\nfunc _on_caster_level_changed(_level_increased: bool):\n\t_remove_invalid_targets()\n\t\n\tvar new_level: int = _caster.get_level()\n\n\tfor target in _target_list:\n\t\tvar active_buff: Buff = target.get_buff_of_type(_aura_effect)\n\n\t\tif active_buff == null:\n\t\t\tcontinue\n\n\t\tvar need_to_level_down: bool = active_buff.get_level() > new_level\n\n\t\tif need_to_level_down:\n\t\t\t_change_buff_level_to_this_aura_level(active_buff)\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(aura_id: int, object_with_buff_var: Object, caster: Unit) -> Aura:\n\tvar aura: Aura = Preloads.aura_scene.instantiate()\n\n\taura._aura_range = AuraProperties.get_aura_range(aura_id)\n\taura._target_type = AuraProperties.get_target_type(aura_id)\n\taura._target_self = AuraProperties.get_target_self(aura_id)\n\taura._level = AuraProperties.get_level(aura_id)\n\taura._level_add = AuraProperties.get_level_add(aura_id)\n\taura._caster = caster\n\n\tvar buff_type_string: String = AuraProperties.get_buff_type(aura_id)\n\tvar buff_type: BuffType = object_with_buff_var.get(buff_type_string)\n\tif buff_type == null:\n\t\tpush_error(\"Failed to find buff type for aura. Buff type = %s, aura id = %d\" % [buff_type_string, aura_id])\n\taura._aura_effect = buff_type\n\t\n\treturn aura\n"
  },
  {
    "path": "src/buffs/aura.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d0tscn8umgx1v\"]\n\n[ext_resource type=\"Script\" path=\"res://src/buffs/aura.gd\" id=\"1_p7wag\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_gacuv\"]\n\n[node name=\"Aura\" type=\"Node2D\"]\nscript = ExtResource(\"1_p7wag\")\n\n[node name=\"ManualTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_gacuv\")\nwait_time = 0.2\nautostart = true\n\n[connection signal=\"timeout\" from=\"ManualTimer\" to=\".\" method=\"_on_manual_timer_timeout\"]\n"
  },
  {
    "path": "src/buffs/buff.gd",
    "content": "class_name Buff\nextends Node2D\n\n\n# Buff stores buff parameters and applies them to target\n# while it is active.\n\n\nvar user_int: int = 0\nvar user_int2: int = 0\nvar user_int3: int = 0\nvar user_real: float = 0.0\nvar user_real2: float = 0.0\nvar user_real3: float = 0.0\n\nvar _caster: Unit\nvar _target: Unit\nvar _modifier: Modifier = Modifier.new()\nvar _level: int\nvar _time: float\nvar _friendly: bool\nvar _buff_type_name: String\nvar _stacking_group: String\nvar _timer: ManualTimer\n# Map of Event.Type -> list of EventHandler's\nvar event_handler_map: Dictionary = {}\nvar _original_duration: float = 0.0\nvar _tooltip_text: String\nvar _buff_icon: String\nvar _buff_icon_color: Color\nvar _is_purgable: bool = true\nvar _cleanup_done: bool = false\nvar _periodic_timer_map: Dictionary = {}\nvar _is_hidden: bool\nvar _special_effect_id: int = 0\nvar _displayed_stacks: int = 0\n# NOTE: these values are defined if the buff type was\n# created inside a TowerBehavior script.\nvar _is_owned_by_tower: bool = false\nvar _tower_family: int = -1\nvar _tower_tier: int = -1\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_timer = ManualTimer.new()\n\tadd_child(_timer)\n\t_timer.timeout.connect(_on_timer_timeout)\n\t\n\tif _time > 0.0:\n\t\tvar buff_duration_mod: float = _caster.get_prop_buff_duration()\n\t\tvar debuff_duration_mod: float = _target.get_prop_debuff_duration()\n\n\t\tvar total_time: float = _time * buff_duration_mod\n\n\t\tif !_friendly:\n\t\t\ttotal_time *= debuff_duration_mod\n\n\t\t_timer.start(total_time)\n\t\t_original_duration = total_time\n\telse:\n\t\t_original_duration = _time\n\n\t_target.death.connect(_on_target_death)\n\t_target.kill.connect(_on_target_kill)\n\t_target.level_changed.connect(_on_target_level_changed)\n\t_target.attack.connect(_on_target_attack)\n\t_target.attacked.connect(_on_target_attacked)\n\t_target.dealt_damage.connect(_on_target_dealt_damage)\n\t_target.damaged.connect(_on_target_damaged)\n\t_target.spell_casted.connect(_on_target_spell_casted)\n\t_target.spell_targeted.connect(_on_target_spell_targeted)\n\n\t_target.tree_exited.connect(_on_target_tree_exited)\n\t_caster.tree_exited.connect(_on_caster_tree_exited)\n\n\tvar create_event: Event = _make_buff_event(_target)\n\t_call_event_handler_list(Event.Type.CREATE, create_event)\n\n\tCombatLog.log_buff_apply(_caster, _target, self)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_is_owned_by_tower() -> bool:\n\treturn _is_owned_by_tower\n\n\nfunc get_tower_family() -> int:\n\treturn _tower_family\n\n\nfunc get_tower_tier() -> int:\n\treturn _tower_tier\n\n\n# NOTE: this is visual only, stack logic has to be\n# implemented separately\nfunc set_displayed_stacks(value: int):\n\t_displayed_stacks = value\n\n\nfunc get_displayed_stacks() -> int:\n\treturn _displayed_stacks\n\n\n# NOTE: do not change remaining duration if original\n# duration is negative because that means that the buff is\n# permanent. Setting the duration would cause the buff to\n# expire.\n# NOTE: buff.refreshDuration() in JASS\nfunc refresh_duration():\n\tif _original_duration < 0:\n\t\treturn\n\n\tset_remaining_duration(_original_duration)\n\n\n# NOTE: buff.removeBuff() in JASS\nfunc remove_buff():\n\tif _cleanup_done:\n\t\treturn\n\n\tvar cleanup_event: Event = _make_buff_event(_target)\n\t_call_event_handler_list(Event.Type.CLEANUP, cleanup_event)\n\n\tif _special_effect_id != 0:\n\t\tEffect.destroy_effect(_special_effect_id)\n\n\t_target._remove_buff_internal(self)\n\n\tif is_inside_tree():\n\t\t_target.remove_child(self)\n\tqueue_free()\n\n\n# NOTE: buff.purgeBuff() in JASS\nfunc purge_buff():\n\tvar purge_event: Event = _make_buff_event(null)\n\t_call_event_handler_list(Event.Type.PURGE, purge_event)\n\n\tremove_buff()\n\n\nfunc get_periodic_timers() -> Dictionary:\n\treturn _periodic_timer_map.duplicate()\n\n\n# Inherits periodic timers from a previous instance of this\n# buff. Used by items to preserve timers of items when they\n# are removed from towers.\nfunc inherit_periodic_timers(inherited_timers: Dictionary):\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_handler_keys: Array = _periodic_timer_map.keys()\n\tsorted_handler_keys.sort()\n\tfor handler in sorted_handler_keys:\n\t\tif !inherited_timers.has(handler):\n\t\t\tcontinue\n\n#\t\tRemove existing timer\n\t\tvar existing_timer: ManualTimer = _periodic_timer_map[handler]\n\t\tremove_child(existing_timer)\n\t\texisting_timer.queue_free()\n\t\texisting_timer.timeout.disconnect(_on_periodic_event_timer_timeout)\n\n#\t\tReplace with inherited timer\n\t\tvar inherited_timer: ManualTimer = inherited_timers[handler]\n\t\t_periodic_timer_map[handler] = inherited_timer\n\t\tinherited_timer.timeout.connect(_on_periodic_event_timer_timeout.bind(handler, inherited_timer))\n\t\tinherited_timer.reparent(self)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _add_event_handler(event_type: Event.Type, handler: Callable):\n\tif !event_handler_map.has(event_type):\n\t\tevent_handler_map[event_type] = []\n\n\tevent_handler_map[event_type].append(handler)\n\n\nfunc _add_periodic_event(handler: Callable, period: float):\n\tvar timer: ManualTimer = ManualTimer.new()\n\ttimer.wait_time = period\n\ttimer.one_shot = false\n\ttimer.autostart = true\n\t_periodic_timer_map[handler] = timer\n\ttimer.timeout.connect(_on_periodic_event_timer_timeout.bind(handler, timer))\n\tadd_child(timer)\n\n\nfunc _add_event_handler_unit_comes_in_range(handler: Callable, radius: float, target_type: TargetType):\n\tvar buff_range_area: BuffRangeArea = BuffRangeArea.make(radius, target_type, handler, self)\n\tadd_child(buff_range_area)\n\n\tbuff_range_area.unit_came_in_range.connect(_on_unit_came_in_range)\n\n\nfunc _call_event_handler_list(event_type: Event.Type, event: Event):\n\tif !_can_call_event_handlers():\n\t\treturn\n\n#\tNOTE: we need to set the _cleanup_done flag in this\n#\tprecise place.\n#   - It has to be set after we call\n#     _can_call_event_handlers() because\n#     _can_call_event_handlers returns false if this flag is\n#     set.\n#\t- It also has to be set before we call event handlers so\n#\t  that cleanup handler gets called once but then doesn't\n#\t  recurse into another cleanup handler. (yes, some\n#\t  cleanup handlers can trigger another cleanup event).\n\tif event_type == Event.Type.CLEANUP:\n\t\t_cleanup_done = true\n\n\tif !event_handler_map.has(event_type):\n\t\treturn\n\n\tevent._buff = self\n\n\tvar handler_list: Array = event_handler_map[event_type]\n\n\tfor handler in handler_list:\n\t\thandler.call(event)\n\n\n# Convenience function to make an event with \"_buff\" variable set to self\nfunc _make_buff_event(target_arg: Unit) -> Event:\n\tvar event: Event = Event.new(target_arg)\n\tevent._buff = self\n\n\treturn event\n\n\nfunc _refresh_by_new_buff():\n\trefresh_duration()\n\n#\tNOTE: refresh event is triggered only when refresh\n#\tis caused by an application of buff with same level.\n#\tNot triggered when refresh_duration() is called for\n#\tother reasons.\n\t_emit_refresh_event()\n\n\n\n# NOTE: aura buffs need to emit EXPIRE event when they are\n# removed from units, according to youtd engine docs. Some\n# tower scripts rely on this behavior.\nfunc _remove_as_aura():\n\tvar expire_event: Event = _make_buff_event(_target)\n\t_call_event_handler_list(Event.Type.EXPIRE, expire_event)\n\n\tremove_buff()\n\n\nfunc _emit_refresh_event():\n\tvar refresh_event: Event = _make_buff_event(_target)\n\t_call_event_handler_list(Event.Type.REFRESH, refresh_event)\n\n\nfunc _upgrade_by_new_buff(new_level: int):\n\trefresh_duration()\n\t\n\tset_level(new_level)\n\n\tvar upgrade_event: Event = _make_buff_event(_target)\n\t_call_event_handler_list(Event.Type.UPGRADE, upgrade_event)\n\n\nfunc _add_aura(aura_id: int, object_with_buff_var: Object):\n\tvar aura: Aura = Aura.make(aura_id, object_with_buff_var, get_caster())\n\tadd_child(aura)\n\n\n# NOTE: when a buff is queued for deletion it means that the\n# buff was removed from the target unit. If any other events\n# are triggered in the same frame before the buff is\n# deleted, the buff shouldn't respond to them.\nfunc _can_call_event_handlers() -> bool:\n\treturn !is_queued_for_deletion() && !_cleanup_done\n\n\nfunc _change_giver_of_aura_effect(new_caster: Unit):\n\tvar old_caster: Unit = _caster\n\n\tif old_caster == new_caster:\n\t\treturn\n\n\told_caster.tree_exited.disconnect(_on_caster_tree_exited)\n\n\t_caster = new_caster\n\t_caster.tree_exited.connect(_on_caster_tree_exited)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_unit_came_in_range(handler: Callable, unit: Unit):\n\tif !_can_call_event_handlers():\n\t\treturn\n\n\tvar range_event: Event = _make_buff_event(unit)\n\n\thandler.call(range_event)\n\n\nfunc _on_timer_timeout():\n\tif _original_duration < 0:\n\t\tpush_error(\"A permanent buff expired! This should never happen - something must be wrong. Ignoring expiry.\")\n\n\t\treturn\n\n\tvar expire_event: Event = _make_buff_event(_target)\n\t_call_event_handler_list(Event.Type.EXPIRE, expire_event)\n\n\tremove_buff()\n\n\nfunc _on_target_death(death_event: Event):\n\tdeath_event._buff = self\n\t_call_event_handler_list(Event.Type.DEATH, death_event)\n\t\n\tremove_buff()\n\n\n# Explanation of all of the cases where buff needs to be\n# removed due to a \"tree_exited\" signal:\n# \n# 1. Buff needs to be removed when buff's target exits the\n#    tree. Target is gone => buff is invalid.\n# \n# 2. Buff needs to be removed when buff's caster exits the\n#    tree. Caster is gone => event handlers are invalid =>\n#    buff is invalid.\n#\n# 3. Buff needs to be removed when buff's BuffType exits the\n#    tree. This case is necessary to correctly handle buffs\n#    created by items. BuffType is gone => item is gone =>\n#    event handlers are invalid => buff is invalid.\n\n\nfunc _on_target_tree_exited():\n\tremove_buff()\n\n\nfunc _on_caster_tree_exited():\n\tremove_buff()\n\n\nfunc _on_buff_type_tree_exited():\n\tremove_buff()\n\n\nfunc _on_target_kill(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.KILL, event)\n\n\nfunc _on_target_level_changed(level_increased: bool):\n\tvar event: Event = _make_buff_event(_target)\n\tevent._level_increased_during_event = level_increased\n\t_call_event_handler_list(Event.Type.LEVEL_CHANGED, event)\n\n\nfunc _on_target_attack(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.ATTACK, event)\n\n\nfunc _on_target_attacked(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.ATTACKED, event)\n\n\nfunc _on_target_dealt_damage(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.DAMAGE, event)\n\n\nfunc _on_target_damaged(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.DAMAGED, event)\n\n\nfunc _on_target_spell_casted(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.SPELL_CAST, event)\n\n\nfunc _on_target_spell_targeted(event: Event):\n\tevent._buff = self\n\t_call_event_handler_list(Event.Type.SPELL_TARGET, event)\n\n\nfunc _on_periodic_event_timer_timeout(handler: Callable, timer: ManualTimer):\n\tif !_can_call_event_handlers():\n\t\treturn\n\n\tvar periodic_event: Event = _make_buff_event(_target)\n\tperiodic_event._timer = timer\n\thandler.call(periodic_event)\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc is_friendly() -> bool:\n\treturn _friendly\n\n\n# NOTE: buff.setRemainingDuration() in JASS\nfunc set_remaining_duration(duration: float):\n\tif _timer != null:\n\t\t_timer.start(duration)\n\n\n# NOTE: buff.getRemainingDuration() in JASS\nfunc get_remaining_duration() -> float:\n\tvar remaining_duration: float = _timer.get_time_left()\n\n\treturn remaining_duration\n\n\nfunc get_original_duration() -> float:\n\treturn _original_duration\n\n\n# NOTE: buff.isPurgable() in JASS\nfunc is_purgable() -> bool:\n\treturn _is_purgable\n\n\nfunc set_is_purgable(value: bool):\n\t_is_purgable = value\n\n\nfunc get_buff_icon() -> String:\n\treturn _buff_icon\n\n\nfunc get_buff_icon_color() -> Color:\n\treturn _buff_icon_color\n\n\n# NOTE: if no tooltip text is defined, return type name to\n# at least make it possible to identify the buff\nfunc get_tooltip_text() -> String:\n\tif !_tooltip_text.is_empty():\n\t\treturn _tooltip_text\n\telse:\n\t\treturn _buff_type_name\n\n\nfunc get_modifier() -> Modifier:\n\treturn _modifier\n\n\n# NOTE: buff.setLevel() in JASS\nfunc set_level(level: int):\n\tvar old_level: int = _level\n\t_level = level\n\t_target.change_modifier_level(get_modifier(), old_level, level)\n\n\n# Level is used to compare this buff with another buff of\n# same type that is active on target and determine which\n# buff is stronger. Stronger buff will end up remaining\n# active on the target.\n# NOTE: buff.getLevel() in JASS\nfunc get_level() -> int:\n\treturn _level\n\n\nfunc get_buff_type_name() -> String:\n\treturn _buff_type_name\n\n\nfunc get_stacking_group() -> String:\n\treturn _stacking_group\n\n\n# NOTE: buff.getCaster() in JASS\nfunc get_caster() -> Unit:\n\treturn _caster\n\n\n# NOTE: buff.getBuffedUnit() in JASS\nfunc get_buffed_unit() -> Unit:\n\treturn _target\n\n\nfunc is_hidden() -> bool:\n\treturn _is_hidden\n"
  },
  {
    "path": "src/buffs/buff_range_area.gd",
    "content": "class_name BuffRangeArea\nextends Node2D\n\n# BuffRangeArea emits a signal when a unit that matches the\n# defined target type comes in range. Used by buffs to\n# implement the \"unit comes in range\" event.\n\nsignal unit_came_in_range(handler: Callable, unit: Unit)\n\n\nvar _target_type: TargetType\nvar _handler: Callable\nvar _radius: float\nvar _buff: Buff\nvar _prev_units_in_range: Array = []\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_manual_timer_timeout():\n\tvar buffed_unit: Unit = _buff.get_buffed_unit()\n\n\tif buffed_unit == null:\n\t\treturn\n\n\tvar caster: Unit = _buff.get_caster()\n\tvar buffed_unit_pos: Vector2 = buffed_unit.get_position_wc3_2d()\n\tvar all_units_in_range: Array = Utils.get_units_in_range(caster, _target_type, buffed_unit_pos, _radius)\n\n\tvar matching_units: Array = []\n\n\tfor unit in all_units_in_range:\n\t\tvar target_match: bool = _target_type.match(unit)\n\n\t\tif target_match:\n\t\t\tmatching_units.append(unit)\n\n\tfor unit in matching_units:\n\t\tvar unit_just_came_in_range: bool = !_prev_units_in_range.has(unit)\n\n\t\tif unit_just_came_in_range:\n\t\t\tunit_came_in_range.emit(_handler, unit)\n\n\t_prev_units_in_range = matching_units\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(radius: float, target_type: TargetType, handler: Callable, buff: Buff) -> BuffRangeArea:\n\tvar buff_range_area: BuffRangeArea = Preloads.buff_range_area_scene.instantiate()\n\tbuff_range_area._radius = radius\n\tbuff_range_area._target_type = target_type\n\tbuff_range_area._handler = handler\n\tbuff_range_area._buff = buff\n\n\treturn buff_range_area\n"
  },
  {
    "path": "src/buffs/buff_range_area.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dgajgmvgctimg\"]\n\n[ext_resource type=\"Script\" path=\"res://src/buffs/buff_range_area.gd\" id=\"1\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_4yswb\"]\n\n[node name=\"buff_range_area\" type=\"Node2D\"]\nscript = ExtResource(\"1\")\n\n[node name=\"ManualTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_4yswb\")\nwait_time = 0.2\nautostart = true\n\n[connection signal=\"timeout\" from=\"ManualTimer\" to=\".\" method=\"_on_manual_timer_timeout\"]\n"
  },
  {
    "path": "src/buffs/buff_type.gd",
    "content": "class_name BuffType\nextends Node\n\n\n# BuffType stores buff parameters and can be used to create\n# buff instances. It's possible to define a custom BuffType\n# by subclassing.\n# \n# Buffs can have event handlers. To add an event handler,\n# define a handler function in your subclass and call one of\n# the functions like add_event_on_kill(). All handler\n# functions will receive one parameter of Event type which\n# contains information about the event.\n# \n# NOTE: BuffType needs to be Node so that it can be used as\n# event handler for Buffs. Buff event handlers must be Node\n# because buff's need to connect to Node's tree_exited()\n# signal for correct \"cleanup\" event logic.\n\n\nclass SpecialEffect:\n\tvar path: String = \"\"\n\tvar z: float = 0.0\n\tvar scale: float = 1.0\n\tvar color: Color = Color.WHITE\n\tvar draw_below_unit: bool = false\n\nclass CommonHandlerData:\n\tvar handler: Callable\n\tvar event_type: Event.Type\n\nclass PeriodicHandlerData:\n\tvar handler: Callable\n\tvar period: float\n\nclass RangeHandlerData:\n\tvar handler: Callable\n\tvar radius: float\n\tvar target_type: TargetType\n\nclass AuraCreationInfo:\n\tvar aura_id: int\n\tvar object_with_buff_var: Object\n\n\nvar _unique_name: String\nvar _time_base: float\nvar _time_level_add: float\nvar _friendly: bool\nvar _modifier: Modifier = Modifier.new()\nvar _common_handler_list: Array[CommonHandlerData] = []\nvar _periodic_handler_list: Array[PeriodicHandlerData] = []\nvar _range_handler_list: Array[RangeHandlerData] = []\nvar _aura_creation_info_list: Array[AuraCreationInfo] = []\nvar _tooltip_text: String = \"\"\nvar _buff_icon: String = \"\"\nvar _buff_icon_color: Color = Color.GRAY\nvar _defined_custom_buff_icon_color: bool = false\nvar _is_hidden: bool = false\nvar _is_purgable: bool = true\nvar _stacking_behavior_is_enabled: bool = true\nvar _special_effect_data: SpecialEffect = null\n# NOTE: these values are defined if the buff type was\n# created inside a TowerBehavior script.\nvar _is_owned_by_tower: bool\nvar _tower_family: int\nvar _tower_tier: int\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# NOTE: if your script creates multiple BuffType's, then\n# each BuffType should be created with a different\n# \"variable_name\" arg. Examples: \"poison_bt\", \"curse_bt\".\nfunc _init(variable_name: String, time_base: float, time_level_add: float, friendly: bool, owner_node: Node):\n\towner_node.add_child(self)\n\n#\tNOTE: add path of owner script to ensure uniqueness\n\tvar parent_script: Script = owner_node.get_script()\n\tvar parent_script_path: String = parent_script.get_path()\n\t_unique_name = \"%s-%s\" % [parent_script_path, variable_name]\n\n\t_time_base = time_base\n\t_time_level_add = time_level_add\n\t_friendly = friendly\n\n\tif owner_node is TowerBehavior:\n\t\tvar owner_tower_behavior: TowerBehavior = owner_node as TowerBehavior\n\t\tvar owner_tower: Tower = owner_tower_behavior.get_tower()\n\t\t_is_owned_by_tower = true\n\t\t_tower_family = owner_tower.get_family()\n\t\t_tower_tier = owner_tower.get_tier()\n\telse:\n\t\t_is_owned_by_tower = false\n\t\t_tower_family = -1\n\t\t_tower_tier = -1\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: buffType.applyAdvanced() in JASS\nfunc _apply_internal(caster: Unit, target: Unit, level: int, time: float) -> Buff:\n\tif _stacking_behavior_is_enabled:\n\t\tvar higher_prio_buff: Buff = _do_stacking_behavior(target, level)\n\n\t\tif higher_prio_buff != null:\n\t\t\treturn higher_prio_buff\n\n\tvar buff: Buff = Buff.new()\n\tbuff._caster = caster\n\tbuff._level = level\n\tbuff._target = target\n\tbuff._modifier = _modifier\n\tbuff._time = time\n\tbuff._friendly = _friendly\n\tbuff._buff_type_name = _unique_name\n\tbuff._tooltip_text = _tooltip_text\n\tbuff._is_hidden = _is_hidden\n\tbuff._buff_icon = _buff_icon\n\tbuff._buff_icon_color = _buff_icon_color\n\tbuff._is_owned_by_tower = _is_owned_by_tower\n\tbuff._tower_family = _tower_family\n\tbuff._tower_tier = _tower_tier\n\tbuff._is_purgable = _is_purgable\n\n\tif _defined_custom_buff_icon_color:\n\t\tbuff._buff_icon_color = _buff_icon_color\n\telif get_parent() is TowerBehavior && caster is Tower:\n\t\tvar tower: Tower = caster as Tower\n\t\tvar element: Element.enm = tower.get_element()\n\t\tvar element_color: Color = Element.get_color(element)\n\n\t\tbuff._buff_icon_color = element_color\n\telse:\n\t\tbuff._buff_icon_color = Color.GRAY\n\n\ttree_exited.connect(buff._on_buff_type_tree_exited)\n\n\tfor handler in _common_handler_list:\n\t\tbuff._add_event_handler(handler.event_type, handler.handler)\n\n\tfor handler in _periodic_handler_list:\n\t\tbuff._add_periodic_event(handler.handler, handler.period)\n\n\tfor handler in _range_handler_list:\n\t\tbuff._add_event_handler_unit_comes_in_range(handler.handler, handler.radius, handler.target_type)\n\n\tfor aura_creation_info in _aura_creation_info_list:\n\t\tvar aura_id: int = aura_creation_info.aura_id\n\t\tvar object_with_buff_var: Object = aura_creation_info.object_with_buff_var\n\t\tbuff._add_aura(aura_id, object_with_buff_var)\n\n#\tNOTE: need to handle edge cases where buff should not be\n#\tapplied:\n# \t1. If buffs are applied to a unit which is in the\n# \t   process of getting deleted. In such cases, still\n# \t   create the buff to be able to return it and avoid\n# \t   null errors but don't add the buff to the unit.\n# \t   Adding buff to unit while unit is getting removed\n# \t   from tree causes Godot \"parent is busy\" error.\n#\t2. If time is 0. Note that time can be \"-1\" in case of\n#\t   permanent buffs.\n#\tIn such cases, free the buff immediately.\n\tvar target_is_active: bool = target.is_inside_tree() && !target.is_queued_for_deletion()\n\tvar time_is_valid: bool = time == -1 || time > 0\n\tvar buff_should_be_applied: bool = target_is_active && time_is_valid\n\tif buff_should_be_applied:\n\t\ttarget._add_buff_internal(buff)\n\t\ttarget.add_child(buff)\n\n\t\tif _special_effect_data != null:\n\t\t\tvar special_effect_id: int = Effect.create_simple_at_unit_attached(_special_effect_data.path, target, Unit.BodyPart.ORIGIN, _special_effect_data.z)\n\t\t\tEffect.set_auto_destroy_enabled(special_effect_id, false)\n\t\t\tEffect.set_scale(special_effect_id, _special_effect_data.scale)\n\t\t\tEffect.set_color(special_effect_id, _special_effect_data.color)\n\t\t\tif _special_effect_data.draw_below_unit:\n\t\t\t\tEffect.set_z_index(special_effect_id, -1)\n\t\t\tbuff._special_effect_id = special_effect_id\n\telse:\n#\t\tNOTE: set _cleanup_done to true because no cleanup\n#\t\tis needed. Buff was never added to tree, so _ready()\n#\t\twasn't called, so buff's CREATE event wasn't\n#\t\ttriggered.\n\t\tbuff._cleanup_done = true\n\t\tbuff.queue_free()\n\n\treturn buff\n\n\n# Base apply function. Overrides time parameters from init().\n# \n# NOTE: buffType.applyCustomTimed() in JASS\nfunc apply_custom_timed(caster: Unit, target: Unit, level: int, time: float) -> Buff:\n\tvar buff: Buff = _apply_internal(caster, target, level, time)\n\n\treturn buff\n\n\n# Basic apply function. Uses time parameters that were\n# passed to BuffType.new(). Returns the new buff that was\n# applied or currently active buff if it has higher priority\n# due to stacking behavior.\n#\n# NOTE: buffs must be applied after the unit has been added\n# to scene tree, after add_child() was called.\n# \n# NOTE: buffType.apply() in JASS\nfunc apply(caster: Unit, target: Unit, level: int) -> Buff:\n\tvar time: float = _time_base + _time_level_add * level\n\n\tvar buff: Buff = apply_custom_timed(caster, target, level, time)\n\n\treturn buff\n\n\n# Apply overriding time parameters from init() and without\n# specifying level. This is a convenience function\n# \n# NOTE: buffType.applyOnlyTimed() in JASS\nfunc apply_only_timed(caster: Unit, target: Unit, time: float) -> Buff:\n\tvar buff: Buff = apply_custom_timed(caster, target, 0, time)\n\t\n\treturn buff\n\n# NOTE: buffType.applyToUnitPermanent() in JASS\nfunc apply_to_unit_permanent(caster: Unit, target: Unit, level: int) -> Buff:\n\tvar buff: Buff = apply_custom_timed(caster, target, level, -1.0)\n\tbuff.set_is_purgable(false)\n\n\treturn buff\n\n\n# Generic function. You should use one of the specialized\n# versions to set handlers for specific events.\nfunc add_event_handler(event_type: Event.Type, handler: Callable):\n\tvar data: CommonHandlerData = CommonHandlerData.new()\n\tdata.handler = handler\n\tdata.event_type = event_type\n\n\t_common_handler_list.append(data)\n\n\n# This event is fired periodically.\n# NOTE: buffType.addPeriodicEvent() in JASS\nfunc add_periodic_event(handler: Callable, period: float):\n\tvar data: PeriodicHandlerData = PeriodicHandlerData.new()\n\tdata.handler = handler\n\tdata.period = period\n\n\t_periodic_handler_list.append(data)\n\n\n# This event is fired whenever a unit comes in range of the\n# buffed unit. If the same unit leaves range and then comes\n# back, this event will fire again. TargetType argument can\n# be used to filter units which will trigger this event.\n# NOTE: buffType.addEventOnUnitComesInRange() in JASS\nfunc add_event_on_unit_comes_in_range(handler: Callable, radius: float, target_type: TargetType):\n\tvar data: RangeHandlerData = RangeHandlerData.new()\n\tdata.handler = handler\n\tdata.radius = radius\n\tdata.target_type = target_type\n\n\t_range_handler_list.append(data)\n\n\n# This event is fired when the buff is removed or\n# the buffed unit dies.\n# NOTE: buffType.addEventOnCleanup() in JASS\nfunc add_event_on_cleanup(handler: Callable):\n\tadd_event_handler(Event.Type.CLEANUP, handler)\n\n\n# This event is fired whenever the buff is created (applied\n# on a unit which doesn't have the buff yet).\n# NOTE: buffType.addEventOnCreate() in JASS\nfunc add_event_on_create(handler: Callable):\n\tadd_event_handler(Event.Type.CREATE, handler)\n\n\n# This event is fired whenever the buff is upgraded (applied\n# on a unit which already has same buff but with lower\n# level, this is possible if there multiples of same tower\n# at different levels).\n# NOTE: buffType.addEventOnUpgrade() in JASS\nfunc add_event_on_upgrade(handler: Callable):\n\tadd_event_handler(Event.Type.UPGRADE, handler)\n\n\n# This event is fired whenever the buff is refreshed (applied\n# on a unit which already has same buff with same level).\n# NOTE: buffType.addEventOnRefresh() in JASS\nfunc add_event_on_refresh(handler: Callable):\n\tadd_event_handler(Event.Type.REFRESH, handler)\n\n\n# This event is fired whenever the buffed unit dies.\n# NOTE: buffType.addEventOnDeath() in JASS\nfunc add_event_on_death(handler: Callable):\n\tadd_event_handler(Event.Type.DEATH, handler)\n\n\n# This event is fired whenever the buffed unit kills another\n# unit.\n# NOTE: buffType.addEventOnKill() in JASS\nfunc add_event_on_kill(handler: Callable):\n\tadd_event_handler(Event.Type.KILL, handler)\n\n\n# This event is fired whenever the level of the buffed unit\n# changes. Both level ups and level downs are included. Note\n# that unit levels can change by more than 1 at one time. In\n# such cases, this event will be triggered multiple times.\n# NOTE: buffType.addEventOnLevelUp() in JASS\nfunc add_event_on_level_changed(handler: Callable):\n\tadd_event_handler(Event.Type.LEVEL_CHANGED, handler)\n\n\n# This event is fired whenever the buffed unit attacks.\n# Caveats:\n# - Event is fired before tower launches the attack\n#   projectile at the target.\n# - For multishot attacks, attack event will be fired only\n#   once per attack, for the first target.\n# NOTE: buffType.addEventOnAttack() in JASS\nfunc add_event_on_attack(handler: Callable):\n\tadd_event_handler(Event.Type.ATTACK, handler)\n\n\n# This event is fired whenever the buffed unit is attacked.\n# NOTE: buffType.addEventOnAttacked() in JASS\nfunc add_event_on_attacked(handler: Callable):\n\tadd_event_handler(Event.Type.ATTACKED, handler)\n\n\n# This event is fired whenever the buffed unit deals ATTACK\n# damage.\n# \n# Caveats:\n# - Event is fired only for attack damage caused by normal\n#   tower attacks.\n# - Event is NOT fired for attack damage caused by tower\n#   abilities.\n# - For tower bounce/multishot/splash attacks, event is\n#   fired individually for each hit creep. 5 creeps were hit\n#   means that there will be 5 \"damage\" events.\n# - This event can't recurse. If your handler deals attack\n#   damage, that will not trigger another DAMAGE event.\n# NOTE: buffType.addEventOnDamage() in JASS\nfunc add_event_on_damage(handler: Callable):\n\tadd_event_handler(Event.Type.DAMAGE, handler)\n\n\n# This event is fired whenever the buffed unit receives\n# ATTACK/SPELL damage.\n# \n# Caveats:\n# - Unlike the \"deal damage\" event, this \"receive damage\"\n#   event has much less restrictions. It is fired for almost\n#   all kinds of damage.\n# - This event is NOT fired for rare cases where creep\n#   damages another creep (some weird tower abilities do\n#   that).\n# NOTE: buffType.addEventOnDamaged() in JASS\nfunc add_event_on_damaged(handler: Callable):\n\tadd_event_handler(Event.Type.DAMAGED, handler)\n\n\n# This event is fired when the buff is removed due to having\n# used up its duration.\n# NOTE: buffType.setEventOnExpire() in JASS\nfunc add_event_on_expire(handler: Callable):\n\tadd_event_handler(Event.Type.EXPIRE, handler)\n\n\n# This event is fired whenever the buffed unit casts a spell\n# (Autocast object).\n# NOTE: buffType.addEventOnSpellCasted() in JASS\nfunc add_event_on_spell_casted(handler: Callable):\n\tadd_event_handler(Event.Type.SPELL_CAST, handler)\n\n\n# This event is fired whenever the buffed unit is targeted\n# by a spell (Autocast object).\n# NOTE: buffType.addEventOnSpellTargeted() in JASS\nfunc add_event_on_spell_targeted(handler: Callable):\n\tadd_event_handler(Event.Type.SPELL_TARGET, handler)\n\n\n# This event is fired when the buff is purged.\n# NOTE: buffType.addEventOnPurge() in JASS\nfunc add_event_on_purge(handler: Callable):\n\tadd_event_handler(Event.Type.PURGE, handler)\n\n\n# NOTE: when aura is added to buff type, we only store the\n# creation info. The actual aura instance is created later\n# when buff is applied on a unit.\nfunc add_aura(aura_id: int, object_with_buff_var: Object):\n\tvar aura_creation_info: AuraCreationInfo = AuraCreationInfo.new()\n\taura_creation_info.aura_id = aura_id\n\taura_creation_info.object_with_buff_var = object_with_buff_var\n\t\n\t_aura_creation_info_list.append(aura_creation_info)\n\n\n# NOTE: this is useful in rare cases like trigger buffs and\n# aura carrier buffs\nfunc disable_stacking_behavior():\n\t_stacking_behavior_is_enabled = false\n\n\n#########################\n###      Private      ###\n#########################\n\n# This function handles situations where a buff is applied\n# while another buff of same type is already active.\n# \n# This f-n will return null if new buff can be applied. It\n# returns an active buff if new buff cannot be applied due\n# to stacking behavior. In addition, this f-n modifies the\n# active buff in certain cases.\n#\n# NOTE: there's a special case for two buffs from same\n# bufftype buf different tower tiers (same family). In such\n# cases, we can't compare by level because different tier\n# towers define completely different bonuses for buffs. If\n# old tier is lower, old buff gets discarded. If old tier is\n# higher, new buff gets discarded. The level difference gets\n# ignored.\n# \n# NOTE: the stacking logic has to be in the exact way as\n# defined here. Changing this logic will break tower and\n# item scripts.\n# \n# [ORIGINAL_GAME_DEVIATION] The comparison of tower tiers\n# didn't exist in original game. If lower tier tower applied\n# a buff and a higher tier tower tried to overwrite it, the\n# buff from higher tier tower would get rejected.\nfunc _do_stacking_behavior(target: Unit, new_level: int):\n\tvar active_buff: Buff = target.get_buff_of_type(self)\n\n#\tNOTE: no active buff, so ok to create new buff\n\tif active_buff == null:\n\t\treturn null\n\n\tvar owned_by_tower: bool = get_is_owned_by_tower()\n\tvar family_active: int = active_buff.get_tower_family()\n\tvar family_new: int = self.get_tower_family()\n\tvar family_is_same: bool = family_active == family_new\n\tvar tier_active: int = active_buff.get_tower_tier()\n\tvar tier_new: int = self.get_tower_tier()\n\tvar tier_is_same: bool = tier_active == tier_new\n\n\tif owned_by_tower && family_is_same && !tier_is_same:\n\t\tif tier_active > tier_new:\n#\t\t\tNOTE: active buff is always prio if it comes\n#\t\t\tfrom higher tier same family tower\n\t\t\treturn active_buff\n\t\telif tier_active < tier_new:\n#\t\t\tNOTE: active buff gets removed (not upgraded) if\n#\t\t\tit comes from lower tier same family tower.\n\t\t\tactive_buff.remove_buff()\n\n\t\t\treturn null\n\n\tvar active_level: int = active_buff.get_level()\n\n\tif new_level > active_level:\n#\t\tNOTE: upgrade active buff, no new buff\n\t\tactive_buff._upgrade_by_new_buff(new_level)\n\n\t\treturn active_buff\n\telif new_level == active_level:\n#\t\tNOTE: refresh active buff, no new buff\n\t\tactive_buff._refresh_by_new_buff()\n\n\t\treturn active_buff\n\telse :\n#\t\t(new_level < active_level)\n#\t\tNOTE: keep active buff, no new buff\n\t\treturn active_buff\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc get_is_owned_by_tower() -> bool:\n\treturn _is_owned_by_tower\n\n\nfunc get_tower_family() -> int:\n\treturn _tower_family\n\n\nfunc get_tower_tier() -> int:\n\treturn _tower_tier\n\n\nfunc get_unique_name() -> String:\n\treturn _unique_name\n\n\n# Defines a modifier which will be applied to target unit.\n# Note that unlike modifiers applied via Unit.add_modifier()\n# function, buff modifiers will not react to unit level ups.\n# The strength of buff modifiers depends on buff level.\n# NOTE: buffType.setBuffModifier() in JASS\nfunc set_buff_modifier(modifier: Modifier):\n\t_modifier = modifier\n\n\n# This tooltip will be displayed when the buff is applied to\n# a unit and player hovers the mouse over the buff icon.\n# Note that this should be plain text, rich text format not\n# supported.\nfunc set_buff_tooltip(tooltip: String):\n\t_tooltip_text = tooltip\n\n\n# NOTE: buffType.setBuffIcon() in JASS\nfunc set_buff_icon(buff_icon: String):\n\t_buff_icon = buff_icon\n\n\n# NOTE: if you don't define a color and bufftype belongs to\n# tower, then buff will use the color of the tower element.\nfunc set_buff_icon_color(color: Color):\n\t_defined_custom_buff_icon_color = true\n\t_buff_icon_color = color\n\n\n# NOTE: this f-n is not implemented. With the way tower\n# scripts are done in youtd2, it's not possible to implement\n# stacking groups in the same way as in original youtd.\n# Instead, there's a workaround where buffs are always\n# prio'd by caster \"tier\".\n# \n# NOTE: buffType.setStackingGroup() in JASS\n# func set_stacking_group(_stacking_group: String):\n# \tpass\n\n\n# NOTE: effects created by this functions will not follow a\n# unit. Try to use this only for buffs applied to towers.\n# NOTE: buffType.setSpecialEffect() in JASS\nfunc set_special_effect(effect_path: String, z: float, scale: float, color: Color = Color.WHITE, draw_below_unit: bool = false):\n\t_special_effect_data = SpecialEffect.new()\n\t_special_effect_data.path = effect_path\n\t_special_effect_data.z = z\n\t_special_effect_data.scale = scale\n\t_special_effect_data.color = color\n\t_special_effect_data.draw_below_unit = draw_below_unit\n\n\n# NOTE: if a buff is hidden, it will not be displayed in the\n# unit menu. Note that for development purposes, you can\n# force hidden buffs to be shown via config.\nfunc set_hidden():\n\t_is_hidden = true\n\n\nfunc set_is_purgable(value: bool):\n\t_is_purgable = value\n\n\n#########################\n###       Static      ###\n#########################\n\n# NOTE: BuffType.createAuraEffectType() in JASS\nstatic func create_aura_effect_type(type: String, friendly: bool, parent: Node) -> BuffType:\n\tvar buff_type: BuffType = BuffType.new(type, 0.0, 0.0, friendly, parent)\n\tbuff_type.set_is_purgable(false)\n\n\treturn buff_type\n"
  },
  {
    "path": "src/buffs/instances/cb_silence.gd",
    "content": "class_name CbSilence\nextends BuffType\n\n# NOTE: globally available cb_silence in JASS\n\n\n# NOTE: BuffType.createDuplicate(cb_silence...) in JASS\nfunc _init(type: String, time_base: float, time_level_add: float,friendly: bool, parent: Node):\n\tsuper(type, time_base, time_level_add, friendly, parent)\n\tadd_event_on_create(on_create)\n\tadd_event_on_cleanup(_on_cleanup)\n\n\tset_buff_icon(\"res://resources/icons/generic_icons/beard.tres\")\n\tset_buff_tooltip(tr(\"TCH4\"))\n\n\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target = buff.get_buffed_unit()\n\n\ttarget.add_silence()\n\n\nfunc _on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target = buff.get_buffed_unit()\n\n\ttarget.remove_silence()\n"
  },
  {
    "path": "src/buffs/instances/cb_stun.gd",
    "content": "class_name CbStun\nextends BuffType\n\n# NOTE: analog of globally available cb_stun in JASS\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] In original game, stuns\n# cannot stack. If you have two towers try to apply two\n# different variations of stuns, then one will cancel\n# another. In original game, total duration of stun will be\n# time before cancel + duration of cancelling buff. In\n# youtd2, both stuns will be applied and total duration will\n# be equal to the max of durations of two stuns.\n\n\n# These values calibrate diminishing returns for stuns on\n# creeps. Stuns will start to randomly cancel after the\n# \"min\" value (in seconds). The chance to cancel stun\n# reaches 100% at \"max\" value. Note that even at 100%\n# chance, stuns will still apply and last for a short\n# time(~0.3s) until periodic callback is called.\nconst DIMINISHING_RETURNS_MIN: float = 15.0\nconst DIMINISHING_RETURNS_MAX: float = 30.0\n\n\n# NOTE: BuffType.createDuplicate(cb_stun...) in JASS\nfunc _init(type: String, time_base: float, time_level_add: float,friendly: bool, parent: Node):\n\tsuper(type, time_base, time_level_add, friendly, parent)\n\tadd_event_on_create(on_create)\n\tadd_periodic_event(periodic, 0.3)\n\tadd_event_on_cleanup(_on_cleanup)\n\n#\tNOTE: this is the default tooltip for stun buff. It may\n#\tbe overriden in buffs that extend this buff.\n\tset_buff_tooltip(tr(\"FROV\"))\n\tset_buff_icon(\"res://resources/icons/generic_icons/knocked_out_stars.tres\")\n\tset_buff_icon_color(Color.WHITE)\n\n\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target = buff.get_buffed_unit()\n\n\ttarget.add_stun()\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Implemented Diminishing\n# Returns. Original game didn't have explicit Diminishing\n# Returns for stuns but it may have inherited some hidden\n# functionality from wc3 engine.\nfunc periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target = buff.get_buffed_unit()\n\n\tif !target is Creep:\n\t\treturn\n\n\tvar total_stun_duration: float = target.get_total_stun_duration()\n\n\tvar chance_to_cancel_stun: float = (total_stun_duration - DIMINISHING_RETURNS_MIN) / (DIMINISHING_RETURNS_MAX - DIMINISHING_RETURNS_MIN)\n\tchance_to_cancel_stun = clampf(chance_to_cancel_stun, 0.0, 1.0)\n\n\tif Utils.rand_chance(Globals.synced_rng, chance_to_cancel_stun):\n\t\tbuff.remove_buff()\n\n\nfunc _on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target = buff.get_buffed_unit()\n\n\ttarget.remove_stun()\n"
  },
  {
    "path": "src/buffs/modification.gd",
    "content": "class_name Modification\n\n\nvar type: ModificationType.enm\nvar value_base: float\nvar level_add: float\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(type_arg: ModificationType.enm, value_base_arg: float, level_add_arg: float):\n\ttype = type_arg\n\tvalue_base = value_base_arg\n\tlevel_add = level_add_arg\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_tooltip_text() -> String:\n\tvar base_is_zero = abs(value_base) < 0.0001\n\tvar add_is_zero = abs(level_add) < 0.0001\n\n\tvar type_name: String = ModificationType.get_display_string(type)\n\n\tvar text: String\n\t\n\tif !base_is_zero && !add_is_zero:\n\t\ttext = \"%s %s (%s/lvl)\\n\" % [_format_percentage(value_base), type_name, _format_percentage(level_add)]\n\telif !base_is_zero && add_is_zero:\n\t\ttext = \"%s %s\\n\" % [_format_percentage(value_base), type_name]\n\telif base_is_zero && !add_is_zero:\n\t\ttext = \"%s %s/lvl\\n\" % [_format_percentage(level_add), type_name]\n\telse:\n\t\ttext = \"\"\n\n\treturn text\n\n\n#########################\n###      Private      ###\n#########################\n\n# Formats percentage values for use in tooltip text\n# 0.1 = +10%\n# -0.1 = -10%\n# 0.001 = +0.1%\nfunc _format_percentage(value: float) -> String:\n\tvar sign_string: String\n\tif value > 0.0:\n\t\tsign_string = \"+\"\n\telse:\n\t\tsign_string = \"\"\n\n\tvar value_is_percentage: bool = ModificationType.get_is_percentage(type)\n\n\tvar value_string: String\n\tif value_is_percentage:\n\t\tvalue_string = String.num(value * 100, 2)\n\telse:\n\t\tvalue_string = String.num(value, 2)\n\n\tvar percent_string: String\n\tif value_is_percentage:\n\t\tpercent_string = \"%\"\n\telse:\n\t\tpercent_string = \"\"\n\n\tvar base_string: String = \"%s%s%s\" % [sign_string, value_string, percent_string]\n\n\treturn base_string\n\n\nstatic func convert_to_string(modification: Modification) -> String:\n\tvar modification_type_string: String = ModificationType.convert_to_string(modification.type)\n\tvar value_base_string: String = str(modification.value_base)\n\tvar level_add_string: String = str(modification.level_add)\n\tvar modification_string: String = \"%s,%s,%s\" % [modification_type_string, value_base_string, level_add_string]\n\n\treturn modification_string\n\n\nstatic func from_string(modification_string: String) -> Modification:\n\tvar mod_params: PackedStringArray = modification_string.split(\",\")\n\n\tif mod_params.size() != 3:\n\t\treturn Modification.new(ModificationType.enm.MOD_DMG_TO_MASS, 0, 0)\n\n\tvar mod_type_string: String = mod_params[0]\n\tvar mod_type: ModificationType.enm = ModificationType.from_string(mod_type_string)\n\tvar mod_value_base: float = mod_params[1].to_float()\n\tvar mod_level_add: float = mod_params[2].to_float()\n\n\tvar modification: Modification = Modification.new(mod_type, mod_value_base, mod_level_add)\n\n\treturn modification\n"
  },
  {
    "path": "src/buffs/modifier.gd",
    "content": "class_name Modifier\n\n# Modifier stores a list of modifications. Can apply and\n# undo apply of such modifications on a unit.\n\n\nvar _modification_list: Array = []\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: modifier.addModification() in JASS\nfunc add_modification(modification_type: int, value_base: float, level_add: float):\n\tvar modification: Modification = Modification.new(modification_type, value_base, level_add)\n\t_modification_list.append(modification)\n\n\nfunc add_modification_instance(modification: Modification):\n\t_modification_list.append(modification)\n\n\nfunc get_modification_list() -> Array:\n\treturn _modification_list.duplicate(true)\n\n\nfunc get_tooltip_text() -> String:\n\tvar text: String = \"\"\n\n\tfor modification in _modification_list:\n\t\tvar modification_text: String = modification.get_tooltip_text()\n\t\ttext += modification_text\n\n\treturn text\n\n\nstatic func convert_to_string(modifier: Modifier) -> String:\n\tvar modification_string_list: Array[String] = []\n\n\tfor modification in modifier._modification_list:\n\t\tvar modification_string: String = Modification.convert_to_string(modification)\n\t\tmodification_string_list.append(modification_string)\n\n\tvar modifier_string: String = \"|\".join(modification_string_list)\n\n\treturn modifier_string\n\n\nstatic func convert_from_string(modifier_string: String) -> Modifier:\n\tvar modifier: Modifier = Modifier.new()\n\t\n\tvar mod_string_list: Array = modifier_string.split(\"|\")\n\n\tfor mod_string in mod_string_list:\n\t\tvar modification: Modification = Modification.from_string(mod_string)\n\t\tmodifier.add_modification_instance(modification)\n\n\treturn modifier\n"
  },
  {
    "path": "src/buffs/target_type.gd",
    "content": "class_name TargetType\n\n# Filters units by various properties. Create a TargetType\n# like this:\n# \n# TargetType.new(TargetType.CREEPS + TargetType.RACE_UNDEAD)\n\nconst CREEPS: int \t\t\t= 0x1\nconst TOWERS: int \t\t\t= 0x2\nconst PLAYER_TOWERS: int \t= 0x4\nconst CORPSES: int \t\t\t= 0x8\n\nconst RACE_UNDEAD: int \t\t= 0x10\nconst RACE_MAGIC: int \t\t= 0x20\nconst RACE_NATURE: int \t\t= 0x40\nconst RACE_ORC: int \t\t= 0x80\nconst RACE_HUMANOID: int \t= 0x100\nconst RACE_CHALLENGE: int \t= 0x200\nconst RACE_ALL: int \t\t= RACE_UNDEAD | RACE_MAGIC | RACE_NATURE | RACE_ORC | RACE_HUMANOID | RACE_CHALLENGE\n\nconst SIZE_MASS: int \t\t= 0x400\nconst SIZE_NORMAL: int \t\t= 0x800\nconst SIZE_CHAMPION: int \t= 0x1000\nconst SIZE_BOSS: int \t\t= 0x2000\nconst SIZE_AIR: int \t\t= 0x4000\nconst SIZE_ALL: int \t\t= SIZE_MASS | SIZE_NORMAL | SIZE_CHAMPION | SIZE_BOSS | SIZE_AIR\n\nconst ELEMENT_ASTRAL: int \t= 0x8000\nconst ELEMENT_DARKNESS: int = 0x10000\nconst ELEMENT_NATURE: int \t= 0x20000\nconst ELEMENT_FIRE: int \t= 0x40000\nconst ELEMENT_ICE: int \t\t= 0x80000\nconst ELEMENT_STORM: int \t= 0x100000\nconst ELEMENT_IRON: int \t= 0x200000\nconst ELEMENT_ALL: int \t\t= ELEMENT_ASTRAL | ELEMENT_DARKNESS | ELEMENT_NATURE | ELEMENT_FIRE | ELEMENT_ICE | ELEMENT_STORM | ELEMENT_IRON\n\nconst RARITY_COMMON: int \t= 0x400000\nconst RARITY_UNCOMMON: int \t= 0x800000\nconst RARITY_RARE: int \t\t= 0x1000000\nconst RARITY_UNIQUE: int \t= 0x2000000\nconst RARITY_ALL: int \t\t= RARITY_COMMON | RARITY_UNCOMMON | RARITY_RARE | RARITY_UNIQUE\n\nconst string_to_bit_map: Dictionary = {\n\t\"CREEPS\": CREEPS,\n\t\"TOWERS\": TOWERS,\n\t\"PLAYER_TOWERS\": PLAYER_TOWERS,\n\t\"CORPSES\": CORPSES,\n\n\t\"RACE_UNDEAD\": RACE_UNDEAD,\n\t\"RACE_MAGIC\": RACE_MAGIC,\n\t\"RACE_NATURE\": RACE_NATURE,\n\t\"RACE_ORC\": RACE_ORC,\n\t\"RACE_HUMANOID\": RACE_HUMANOID,\n\t\"RACE_CHALLENGE\": RACE_CHALLENGE,\n\n\t\"SIZE_MASS\": SIZE_MASS,\n\t\"SIZE_NORMAL\": SIZE_NORMAL,\n\t\"SIZE_CHAMPION\": SIZE_CHAMPION,\n\t\"SIZE_BOSS\": SIZE_BOSS,\n\t\"SIZE_AIR\": SIZE_AIR,\n\n\t\"ELEMENT_ASTRAL\": ELEMENT_ASTRAL,\n\t\"ELEMENT_DARKNESS\": ELEMENT_DARKNESS,\n\t\"ELEMENT_NATURE\": ELEMENT_NATURE,\n\t\"ELEMENT_FIRE\": ELEMENT_FIRE,\n\t\"ELEMENT_ICE\": ELEMENT_ICE,\n\t\"ELEMENT_STORM\": ELEMENT_STORM,\n\t\"ELEMENT_IRON\": ELEMENT_IRON,\n\n\t\"RARITY_COMMON\": RARITY_COMMON,\n\t\"RARITY_UNCOMMON\": RARITY_UNCOMMON,\n\t\"RARITY_RARE\": RARITY_RARE,\n\t\"RARITY_UNIQUE\": RARITY_UNIQUE,\n}\n\nconst bit_to_string_map: Dictionary = {\n\tCREEPS: \"CREEPS\",\n\tTOWERS: \"TOWERS\",\n\tPLAYER_TOWERS: \"PLAYER_TOWERS\",\n\tCORPSES: \"CORPSES\",\n\n\tRACE_UNDEAD: \"RACE_UNDEAD\",\n\tRACE_MAGIC: \"RACE_MAGIC\",\n\tRACE_NATURE: \"RACE_NATURE\",\n\tRACE_ORC: \"RACE_ORC\",\n\tRACE_HUMANOID: \"RACE_HUMANOID\",\n\tRACE_CHALLENGE: \"RACE_CHALLENGE\",\n\n\tSIZE_MASS: \"SIZE_MASS\",\n\tSIZE_NORMAL: \"SIZE_NORMAL\",\n\tSIZE_CHAMPION: \"SIZE_CHAMPION\",\n\tSIZE_BOSS: \"SIZE_BOSS\",\n\tSIZE_AIR: \"SIZE_AIR\",\n\n\tELEMENT_ASTRAL: \"ELEMENT_ASTRAL\",\n\tELEMENT_DARKNESS: \"ELEMENT_DARKNESS\",\n\tELEMENT_NATURE: \"ELEMENT_NATURE\",\n\tELEMENT_FIRE: \"ELEMENT_FIRE\",\n\tELEMENT_ICE: \"ELEMENT_ICE\",\n\tELEMENT_STORM: \"ELEMENT_STORM\",\n\tELEMENT_IRON: \"ELEMENT_IRON\",\n\n\tRARITY_COMMON: \"RARITY_COMMON\",\n\tRARITY_UNCOMMON: \"RARITY_UNCOMMON\",\n\tRARITY_RARE: \"RARITY_RARE\",\n\tRARITY_UNIQUE: \"RARITY_UNIQUE\",\n}\n\nstatic var _tower_element_to_bit: Dictionary = {\n\tElement.enm.ASTRAL: TargetType.ELEMENT_ASTRAL,\n\tElement.enm.DARKNESS: TargetType.ELEMENT_DARKNESS,\n\tElement.enm.NATURE: TargetType.ELEMENT_NATURE,\n\tElement.enm.FIRE: TargetType.ELEMENT_FIRE,\n\tElement.enm.ICE: TargetType.ELEMENT_ICE,\n\tElement.enm.STORM: TargetType.ELEMENT_STORM,\n\tElement.enm.IRON: TargetType.ELEMENT_IRON,\n}\n\nstatic var _creep_category_to_bit: Dictionary = {\n\tCreepCategory.enm.UNDEAD: RACE_UNDEAD,\n\tCreepCategory.enm.MAGIC: RACE_MAGIC,\n\tCreepCategory.enm.NATURE: RACE_NATURE,\n\tCreepCategory.enm.ORC: RACE_ORC,\n\tCreepCategory.enm.HUMANOID: RACE_HUMANOID,\n\tCreepCategory.enm.CHALLENGE: RACE_CHALLENGE,\n}\n\nstatic var _creep_size_to_bit: Dictionary = {\n\tCreepSize.enm.MASS: SIZE_MASS,\n\tCreepSize.enm.NORMAL: SIZE_NORMAL,\n\tCreepSize.enm.CHAMPION: SIZE_CHAMPION,\n\tCreepSize.enm.BOSS: SIZE_BOSS,\n\tCreepSize.enm.AIR: SIZE_AIR,\n\tCreepSize.enm.CHALLENGE_BOSS: SIZE_BOSS,\n\tCreepSize.enm.CHALLENGE_MASS: SIZE_MASS,\n}\n\nstatic var _tower_rarity_to_bit: Dictionary = {\n\tRarity.enm.COMMON: TargetType.RARITY_COMMON,\n\tRarity.enm.UNCOMMON: TargetType.RARITY_UNCOMMON,\n\tRarity.enm.RARE: TargetType.RARITY_RARE,\n\tRarity.enm.UNIQUE: TargetType.RARITY_UNIQUE,\n}\n\nenum UnitType {\n\tTOWERS,\n\tCREEPS,\n\tCORPSES\n}\n\nvar _unit_type: UnitType\nvar _original_bitmask: int = 0\nvar _bitmask: int = 0\nvar _player_towers_is_set: bool\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(bitmask: int):\n\t_original_bitmask = bitmask\n\t_bitmask = bitmask\n\t_unit_type = TargetType._get_unit_type(bitmask)\n\n\tvar group_bitmask_list: Array[int] = [\n\t\tELEMENT_ALL,\n\t\tRACE_ALL,\n\t\tSIZE_ALL,\n\t\tRARITY_ALL,\n\t]\n\t\n#\tNOTE: if target type was created with no bit specified\n#\tfor group (element, race or size) then it is assumed\n#\tthat we should accept all variations for that group.\n#\tTherefore we set all bits from those group bitmasks.\n\tfor all_bitmask in group_bitmask_list:\n\t\tvar no_filter_for_section: bool = _bitmask & all_bitmask == 0\n\t\tif no_filter_for_section:\n\t\t\t_bitmask |= all_bitmask\n\n\t_player_towers_is_set = _bitmask & PLAYER_TOWERS == PLAYER_TOWERS\n\n#\tNOTE: treat PLAYER_TOWERS as TOWERS and vice versa. The\n#\tactual filtering for PLAYER_TOWERS cannot be implemented\n#\tin TargetType itself because caster's player is not\n#\taccessible here. This filtering is implemented in\n#\tUtils.get_units_in_range().\n\tif _bitmask & PLAYER_TOWERS == PLAYER_TOWERS:\n\t\t_bitmask |= TOWERS\n\tif _bitmask & TOWERS == TOWERS:\n\t\t_bitmask |= PLAYER_TOWERS\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc equals_to(target_type: TargetType) -> bool:\n\tvar result: bool = _bitmask == target_type._bitmask\n\n\treturn result\n\n\n# NOTE: need to use bitmask to get optimal performance.\n# TargetType.match() will get called very frequently via\n# Utils.get_units_in_range().\nfunc match(unit: Unit) -> bool:\n\tvar is_match: bool = _bitmask & unit.get_target_bitmask() == unit.get_target_bitmask()\n\n\treturn is_match\n\n\nfunc get_unit_type() -> TargetType.UnitType:\n\treturn _unit_type\n\n\nfunc player_towers_is_set() -> bool:\n\treturn _player_towers_is_set\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func _get_unit_type(bitmask: int) -> UnitType:\n\tvar creeps_set: bool = UtilsStatic.bit_is_set(bitmask, CREEPS)\n\tvar towers_set: bool = UtilsStatic.bit_is_set(bitmask, TOWERS)\n\tvar player_towers_set: bool = UtilsStatic.bit_is_set(bitmask, PLAYER_TOWERS)\n\tvar corpses_set: bool = UtilsStatic.bit_is_set(bitmask, CORPSES)\n\n\tif creeps_set:\n\t\treturn UnitType.CREEPS\n\telif towers_set:\n\t\treturn UnitType.TOWERS\n\telif player_towers_set:\n\t\treturn UnitType.TOWERS\n\telif corpses_set:\n\t\treturn UnitType.CORPSES\n\telse:\n\t\treturn UnitType.CREEPS\n\n\nstatic func make_unit_bitmask(unit: Unit) -> int:\n\tvar bitmask: int = 0\n\n\tif unit is Tower:\n\t\tvar tower: Tower = unit as Tower\n\n\t\tvar element: Element.enm = tower.get_element()\n\t\tvar element_bit: int = _tower_element_to_bit[element]\n\t\tvar rarity: Rarity.enm = tower.get_rarity()\n\t\tvar rarity_bit: int = _tower_rarity_to_bit[rarity]\n\t\t\n#\t\tNOTE: need to set both TOWERS and PLAYER_TOWERS so\n#\t\tthat both type of bitmasks match with this unit\n\t\tbitmask |= TargetType.TOWERS\n\t\tbitmask |= TargetType.PLAYER_TOWERS\n\t\tbitmask |= element_bit\n\t\tbitmask |= rarity_bit\n\telif unit is Creep:\n\t\tvar creep: Creep = unit as Creep\n\n\t\tvar category: CreepCategory.enm = creep.get_category()\n\t\tvar category_bit: int = _creep_category_to_bit[category]\n\t\tvar size: CreepSize.enm = creep.get_size()\n\t\tvar size_bit: int = _creep_size_to_bit[size]\n\n\t\tbitmask |= TargetType.CREEPS\n\t\tbitmask |= category_bit\n\t\tbitmask |= size_bit\n\telif unit is CreepCorpse:\n\t\tbitmask |= TargetType.CORPSES\n\n\treturn bitmask\n\n\nstatic func convert_from_string(string: String) -> TargetType:\n\tvar set_bit_string_list: Array = string.split(\",\")\n\tset_bit_string_list.erase(\"\")\n\tvar set_bit_list: Array[int] = []\n\n\tfor set_bit_string in set_bit_string_list:\n\t\tvar set_bit: int = string_to_bit_map[set_bit_string]\n\n\t\tset_bit_list.append(set_bit)\n\n\tvar bitmask: int = 0\n\tfor set_bit in set_bit_list:\n\t\tbitmask += set_bit\n\n\tvar target_type: TargetType\n\tif bitmask != 0:\n\t\ttarget_type = TargetType.new(bitmask)\n\telse:\n\t\ttarget_type = null\n\n\treturn target_type\n\n\nstatic func convert_to_string(target_type: TargetType) -> String:\n\tif target_type == null:\n\t\treturn \"\"\n\n\tvar bit_list: Array = bit_to_string_map.keys()\n\tbit_list.sort()\n\n#\tNOTE: using original bitmask because the full \"bitmask\"\n#\tcontains redundant bits\n\tvar bitmask: int = target_type._original_bitmask\n\n\tvar set_bit_list: Array[int] = []\n\tfor bit in bit_list:\n\t\tvar bit_is_set: int = UtilsStatic.bit_is_set(bitmask, bit)\n\n\t\tif bit_is_set:\n\t\t\tset_bit_list.append(bit)\n\n\tvar set_bit_string_list: Array = []\n\n\tfor bit in set_bit_list:\n\t\tvar set_bit_string: String = bit_to_string_map[bit]\n\n\t\tset_bit_string_list.append(set_bit_string)\n\n\tvar result: String = \",\".join(set_bit_string_list)\n\n\treturn result\n"
  },
  {
    "path": "src/builders/builder.gd",
    "content": "class_name Builder extends Node\n\n\n# Base class for builder instances. Defines functions which\n# should be overriden in subclasses. Some of these functions\n# will be called once after builder is selected. Other\n# functions will be called multiple times during gameplay,\n# as callbacks.\n\n\nvar _id: int\nvar _tower_buff: BuffType\nvar _creep_buff: BuffType\nvar _tower_modifier: Modifier\nvar _creep_modifier: Modifier\n\nvar _allow_adjacent_towers: bool = true\nvar _tower_lvl_bonus: int = 0\nvar _range_bonus: float = 0.0\nvar _item_slots_bonus: int = 0\nvar _adds_extra_recipes: bool = false\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_tower_buff = _get_tower_buff()\n\t_creep_buff = _get_creep_buff()\n\t_tower_modifier = _get_tower_modifier()\n\t_creep_modifier = _get_creep_modifier()\n\t\n\tvar builder_name: String = BuilderProperties.get_display_name(_id)\n\n\tif _tower_buff != null:\n\t\t_tower_buff.set_buff_tooltip(\"DEBUG Buff from builder %s\" % builder_name)\n\t\t_tower_buff.set_hidden()\n\t\n\tif _creep_buff != null:\n\t\t_creep_buff.set_buff_tooltip(\"DEBUG Buff from builder %s\" % builder_name)\n\t\t_creep_buff.set_hidden()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id() -> int:\n\treturn _id\n\n\nfunc get_display_name() -> String:\n\tvar display_name: String = BuilderProperties.get_display_name(_id)\n\n\treturn display_name\n\n\nfunc get_allow_adjacent_towers() -> bool:\n\treturn _allow_adjacent_towers\n\n\nfunc get_tower_lvl_bonus() -> int:\n\treturn _tower_lvl_bonus\n\n\nfunc get_range_bonus() -> float:\n\treturn _range_bonus\n\n\nfunc get_item_slots_bonus() -> int:\n\treturn _item_slots_bonus\n\n\nfunc get_adds_extra_recipes() -> bool:\n\treturn _adds_extra_recipes\n\n\nfunc apply_effects(unit: Unit):\n\tvar buff: BuffType\n\tvar modifier: Modifier\n\n\tif unit is Tower:\n\t\tbuff = _tower_buff\n\t\tmodifier = _tower_modifier\n\telif unit is Creep:\n\t\tbuff = _creep_buff\n\t\tmodifier = _creep_modifier\n\telse:\n\t\tbuff = null\n\t\tmodifier = null\n\n\tif buff != null:\n\t\tbuff.apply_to_unit_permanent(unit, unit, unit.get_level())\n\n\tif modifier != null:\n\t\tunit.add_modifier(modifier)\n\n\n#########################\n###  Override methods ###\n#########################\n\nfunc apply_to_player(_player: Player):\n\tpass\n\n\nfunc apply_wave_finished_effect(_player: Player):\n\tpass\n\n\nfunc _get_tower_buff() -> BuffType:\n\treturn null\n\n\nfunc _get_creep_buff() -> BuffType:\n\treturn null\n\n\n# NOTE: if your builder needs to modify unit stats, use\n# modifiers instead of buffs. This way, modifiers will be\n# affected by unit leveling up. Modifiers applied via buffs\n# will NOT be affected by level ups.\nfunc _get_tower_modifier() -> Modifier:\n\treturn null\n\n\nfunc _get_creep_modifier() -> Modifier:\n\treturn null\n\n\n#########################\n###       Static      ###\n#########################\n\n\nstatic func create_instance(id: int) -> Builder:\n\tvar script_path: String = BuilderProperties.get_script_path(id)\n\tvar builder_script = load(script_path)\n\tvar builder_instance: Builder = builder_script.new()\n\tbuilder_instance._id = id\n\n\treturn builder_instance\n"
  },
  {
    "path": "src/builders/instances/builder_adventurer.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.15, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.20, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_antagonizer.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.10, 0.04)\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.10, 0.005)\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.25, 0.0)\n\n\tmod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, -0.60, -0.016)\n\tmod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, -0.16, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_arch_sorceress.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.50, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, 0.20, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, 0.50, 0.02)\n    mod.add_modification(ModificationType.enm.MOD_DMG_TO_MAGIC, 0.0, 0.01)\n\n    mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, -0.10, -0.012)\n\n    return mod\n"
  },
  {
    "path": "src/builders/instances/builder_backpacker.gd",
    "content": "extends Builder\n\n\nfunc _init():\n    _item_slots_bonus = 2\n    _adds_extra_recipes = true\n\n\nfunc _get_tower_modifier() -> Modifier:\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.40, 0.0)\n\n    return mod\n\n\nfunc _get_tower_buff() -> BuffType:\n    var backpacker_bt: BuffType = BuffType.new(\"backpacker_bt\", 0, 0, false, self)\n    backpacker_bt.add_periodic_event(backpacker_bt_periodic, 1.0)\n\n    return backpacker_bt\n\n\nfunc backpacker_bt_periodic(event: Event):\n    var buff: Buff = event.get_buff()\n    var tower: Tower = buff.get_buffed_unit()\n    var item_list: Array[Item] = tower.get_items()\n\n    var tower_rarity: Rarity.enm = TowerProperties.get_rarity(tower.get_id())\n\n    var dropped_items: bool = false\n\n    for item in item_list:\n        var item_rarity: Rarity.enm = item.get_rarity()\n        var can_wield_item: bool = item_rarity == tower_rarity || item_rarity == Rarity.enm.UNIQUE\n        \n        if !can_wield_item:\n            item.drop()\n            item.fly_to_stash(0.0)\n            dropped_items = true\n    \n    if dropped_items:\n        tower.get_player().display_floating_text(tr(\"BUILDER_BACKPACKER_ERROR_TEXT\"), tower, Color.RED)\n"
  },
  {
    "path": "src/builders/instances/builder_barbarian_warlord.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.10, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.35, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.0, 0.004)\n    mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.0, 0.02)\n    mod.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 2.0, 0.0)\n\n    mod.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, -3.0, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -1.0, 0.0)\n\n    return mod\n"
  },
  {
    "path": "src/builders/instances/builder_benevolent_witch.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MANA, 10, 0)\n\tmod.add_modification(ModificationType.enm.MOD_MANA_PERC, 1.0, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, 0.50, 0.02)\n\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -0.25, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_blademaster.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.08, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.40, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 1.0, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_elementalist.gd",
    "content": "extends Builder\n\n\nfunc apply_to_player(player: Player):\n\tplayer.add_tomes(65)\n\tplayer.modify_food_cap(20)\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_ORC, 0.25, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_UNDEAD, 0.20, 0.0)\n\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_NATURE, -0.20, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_HUMANOID, -0.05, 0.0)\n\n\treturn mod\n\n\nfunc apply_wave_finished_effect(player: Player):\n\tplayer.add_tomes(2)\n"
  },
  {
    "path": "src/builders/instances/builder_farseer.gd",
    "content": "extends Builder\n\n\n# NOTE: commented out sections relevant to invisibility\n# because invisible waves are currently disabled.\n\n\nfunc _init():\n\t_range_bonus = 75\n\n\n# func _get_tower_buff() -> BuffType:\n# \tvar farseer_bt: BuffType = MagicalSightBuff.new(\"farseer_bt\", 700, self)\n\n# \treturn farseer_bt\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.10, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_feeble_fender.gd",
    "content": "extends Builder\n\n\nfunc apply_to_player(player: Player):\n\tplayer.modify_income_rate(-0.20)\n\tplayer.add_tomes(-45)\n\tplayer.set_builder_wisdom_multiplier(1.25)\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_UNDEAD, 0.50, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_ORC, 0.30, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_MASS, 0.50, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_MAGIC, -0.30, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_goblin_alchemist.gd",
    "content": "extends Builder\n\n\nfunc apply_to_player(player: Player):\n\tplayer.modify_income_rate(0.15)\n\tplayer.modify_interest_rate(0.02)\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_BOUNTY_RECEIVED, 0.20, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.35, 0.02)\n\n\tmod.add_modification(ModificationType.enm.MOD_BUFF_DURATION, -0.35, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, 0.25, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.15, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_iron_maiden.gd",
    "content": "extends Builder\n\n\nfunc apply_to_player(player: Player):\n\tplayer.get_team().modify_lives(50)\n\n\nfunc apply_wave_finished_effect(player: Player):\n\tvar portal_lives: float = player.get_team().get_lives_percent()\n\n# \tNOTE: the tooltip says 50% and 10%, but that is in\n# \tabsolute terms without considering +50% to base lives\n# \tfrom Iron Maiden. 50% means 50, not 0.5 * 150 = 75. This\n# \tis how it works in original game.\n\tvar regen_amount: float\n\tif portal_lives < 10:\n\t\tregen_amount = 2\n\telif portal_lives < 50:\n\t\tregen_amount = 1\n\telse:\n\t\tregen_amount = 0\n\n\tplayer.get_team().modify_lives(regen_amount)\n\n# \tNOTE: original game doesn't have this message but I\n# \tthought that it would be useful to add it.\n\tif regen_amount != 0:\n\t\tvar regen_amount_string: String = Utils.format_percent(regen_amount / 100, 1)\n\t\tMessages.add_normal(player, tr(\"MESSAGE_IRON_MAIDEN\").format({REGENED_LIVES = regen_amount_string}))\n"
  },
  {
    "path": "src/builders/instances/builder_master_of_encyclopedic_wisdom.gd",
    "content": "extends Builder\n\n\nfunc _init():\n\t_tower_lvl_bonus = 5\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, 0.60, 0.01)\n\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, -0.15, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_maverick.gd",
    "content": "extends Builder\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] the following builder\n# effect from original game is not implemented: \"Unable to\n# share build areas with allies\"\n\n\nfunc _init():\n\t_allow_adjacent_towers = false\n\n\nfunc apply_to_player(player: Player):\n\tplayer.modify_food_cap(-20)\n\tplayer.set_builder_wisdom_multiplier(0.625)\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_BOSS, 0.50, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_CHAMPION, 0.25, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.30, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.0, 0.01)\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.0, 0.03)\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.0, 0.03)\n\n\tmod.add_modification(ModificationType.enm.MOD_BUFF_DURATION, -0.50, 0.03)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_naga_time_twister.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.40, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.30, 0.0)\n\n    mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, -0.25, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -0.25, 0.0)\n\n    return mod\n"
  },
  {
    "path": "src/builders/instances/builder_none.gd",
    "content": "extends Builder\n\n# If \"none\" builder was selected, nothing needs to be done,\n# so don't override anything from base class.\n"
  },
  {
    "path": "src/builders/instances/builder_panda_monk.gd",
    "content": "extends Builder\n\n# NOTE: this builder was named \"Pandaren Monk\" in original\n# youtd\n\nfunc _get_tower_modifier() -> Modifier:\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.25, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.15, 0.014)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.20, 0.012)\n    mod.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.0, 0.012)\n\n    mod.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, -0.60, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -0.10, 0.0)\n\n    return mod\n"
  },
  {
    "path": "src/builders/instances/builder_queen.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.10, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_AIR, 0.30, 0.02)\n\n\treturn mod\n\n\nfunc _get_creep_buff() -> BuffType:\n\tvar queen_bt: BuffType = BuffType.new(\"queen_bt\", 0, 0, false, self)\n\tqueen_bt.add_event_on_create(_creep_bt_on_create)\n\n\treturn queen_bt\n\n\nfunc _creep_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar creep: Creep = buffed_unit as Creep\n\n\tif creep == null:\n\t\treturn\n\n\tvar creep_size: CreepSize.enm = creep.get_size()\n\n\tif creep_size == CreepSize.enm.AIR:\n\t\tcreep.modify_property(ModificationType.enm.MOD_MOVESPEED_ABSOLUTE, -60)\n"
  },
  {
    "path": "src/builders/instances/builder_realist.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.15, 0.015)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.15, 0.015)\n    mod.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, 1.50, 0.0)\n\n    mod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, -0.50, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, -0.20, 0.0)\n    mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -0.20, 0.0)\n\n    return mod\n"
  },
  {
    "path": "src/builders/instances/builder_royal_assassin.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_BOSS, 0.15, 0.01)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_CHAMPION, 0.25, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.0, 0.02)\n\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_NORMAL, -0.08, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_MASS, -0.12, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_spirit_warden.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.30, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_BUFF_DURATION, 0.80, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_MASS, 0.10, 0.0)\n\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_BOSS, -0.10, 0.0)\n\n\treturn mod\n"
  },
  {
    "path": "src/builders/instances/builder_veteran_pilot.gd",
    "content": "extends Builder\n\n\nfunc _get_tower_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.20, 0.02)\n\n\treturn mod\n\n\nfunc _get_creep_modifier() -> Modifier:\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED_ABSOLUTE, 50, 0)\n\n\treturn mod\n"
  },
  {
    "path": "src/creeps/creep.gd",
    "content": "class_name Creep\nextends Unit\n\n\nsignal moved(delta)\n\n\nconst HEIGHT_TWEEN_FAST_FORWARD_DELTA: float = 100.0\n\n# NOTE: need to limit size of selection visual so that creep\n# selection visual doesn't clip into floor2 tiles.\nconst MAX_SELECTION_VISUAL_SIZE: float = 120.0\n\nconst slow_run_animations: Array[String] = [\"slow_run_E\", \"slow_run_S\", \"slow_run_W\", \"slow_run_N\"]\nconst fly_animations: Array[String] = [\"fly_E\", \"fly_SE\", \"fly_S\", \"fly_SW\", \"fly_W\", \"fly_NW\", \"fly_N\", \"fly_NE\"]\nconst death_animations: Array[String] = [\"death_E\", \"death_S\", \"death_W\", \"death_N\"]\n\n\nvar _path: Path2D\nvar _size: CreepSize.enm\nvar _category: CreepCategory.enm\nvar _armor_type: ArmorType.enm\nvar _current_path_index: int = 0\nvar _facing_angle: float = 0.0\nvar _spawn_level: int\nvar _special_list: Array[int] = []\nvar _target_height: float = 0.0\nvar _height_change_speed: float = 0.0\nvar _portal_damage_multiplier: float = 1.0\n\n\n# NOTE: need to use @onready for these variables instead of\n# @export because export vars cause null errors in HTML5\n# build, for some reason.\n@onready var _visual = $Visual\n@onready var _sprite: AnimatedSprite2D = $Visual/SpriteParent/Sprite\n@onready var _health_bar = $Visual/HealthBar\n@onready var _selection_area: Area2D = $Visual/SelectionArea\n@onready var _sprite_parent: Node2D = $Visual/SpriteParent\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tsuper()\n\n\tGroupManager.add(\"creeps\", self, get_uid())\n\t\n\tvar max_health = get_overall_health()\n\t_health_bar.set_max(max_health)\n\t_health_bar.set_min(0.0)\n\t_health_bar.set_value(max_health)\n\thealth_changed.connect(_on_health_changed)\n\n\tif _size == CreepSize.enm.AIR:\n\t\tvar air_creep_z: float = 2 * Constants.TILE_SIZE_WC3\n\t\tset_z(air_creep_z)\n\t\t_target_height = air_creep_z\n\t\n\t_setup_selection_signals(_selection_area)\n\t\n\t_set_visual_node(_visual)\n\tvar outline_thickness: float = _get_outline_thickness()\n\t_setup_unit_sprite(_sprite, _sprite_parent, outline_thickness)\n\n\tvar animation_for_dimensions: String\n\tif _size == CreepSize.enm.AIR:\n\t\tanimation_for_dimensions = fly_animations[0]\n\telse:\n\t\tanimation_for_dimensions = slow_run_animations[0]\n\n\tvar sprite_dimensions: Vector2 = Utils.get_animated_sprite_dimensions(_sprite, animation_for_dimensions)\n\t_set_unit_dimensions(sprite_dimensions)\n\n\tvar selection_size: float = min(sprite_dimensions.x, MAX_SELECTION_VISUAL_SIZE)\n\t_set_selection_size(selection_size)\n\n\tdeath.connect(_on_death)\n\n\nfunc update(delta: float):\n\tsuper.update(delta)\n\t\n\tif !is_stunned():\n\t\t_move(delta)\n\n#\tNOTE: need to also play animation for outline, so it\n#\tmatches sprite\n\tvar creep_animation: String = _get_creep_animation()\n\t_sprite.play(creep_animation)\n\tvar selection_outline: Node2D = get_selection_outline()\n\tselection_outline.play(creep_animation)\n\n\tvar creep_move_speed: float = get_current_movespeed()\n\tvar move_speed_ratio: float = creep_move_speed / Constants.DEFAULT_MOVE_SPEED\n\t_sprite.set_speed_scale(move_speed_ratio)\n\tselection_outline.set_speed_scale(move_speed_ratio)\n\n\tvar current_z: float = get_z()\n\n\tif current_z != _target_height:\n\t\tvar height_change: float = _height_change_speed * delta\n\n\t\tvar new_z: float\n\t\tif current_z < _target_height:\n\t\t\tnew_z = max(_target_height, current_z + height_change)\n\t\telse:\n\t\t\tnew_z = min(_target_height, current_z - height_change)\n\n\t\tset_z(new_z)\n\n\tz_index = _calculate_current_z_index()\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: should be called once when creating the creep\nfunc set_properties(path: Path2D, player: Player, size: CreepSize.enm, armor_type: ArmorType.enm, race, health: float, armor: float, level: int):\n\tset_player(player)\n\t_path = path\n\t_size = size\n\t_armor_type = armor_type\n\t_category = race\n\tset_base_health(health)\n\tset_health(health)\n\tset_base_armor(armor)\n\t_spawn_level = level\n\n\nfunc set_portal_damage_multiplier(value: float):\n\t_portal_damage_multiplier = value\n\n\n# Returns score which will be granted by Creep.\n# Note that this value depends on creep health.\n# NOTE: this function is *mostly* correct. Some multipliers\n# may still be missing.\nfunc get_score(difficulty: Difficulty.enm, game_length: int, game_mode: GameMode.enm) -> float:\n\tconst difficulty_multiplier_map: Dictionary = {\n\t\tDifficulty.enm.BEGINNER: 1.0,\n\t\tDifficulty.enm.EASY: 2.0,\n\t\tDifficulty.enm.MEDIUM: 3.0,\n\t\tDifficulty.enm.HARD: 4.0,\n\t\tDifficulty.enm.EXTREME: 5.0,\n\t}\n\tvar difficulty_multiplier: float = difficulty_multiplier_map[difficulty]\n\n\tconst length_multiplier_map: Dictionary = {\n\t\tConstants.WAVE_COUNT_TRIAL: 1.0,\n\t\tConstants.WAVE_COUNT_FULL: 1.0,\n\t\tConstants.WAVE_COUNT_NEVERENDING: 0.9,\n\t}\n\tvar length_multiplier: float = length_multiplier_map[game_length]\n\n\tconst game_mode_multiplier_map: Dictionary = {\n\t\tGameMode.enm.BUILD: 0.9,\n\t\tGameMode.enm.RANDOM_WITH_UPGRADES: 1.0,\n\t\tGameMode.enm.TOTALLY_RANDOM: 1.35,\n\t}\n\tvar game_mode_multiplier: float = game_mode_multiplier_map[game_mode]\n\n\tvar settings_multiplier: float = difficulty_multiplier * length_multiplier * game_mode_multiplier\n\n\tvar damage_done: float = get_damage_done()\n\tvar size_multiplier: float = CreepSize.get_score_multiplier(_size)\n\tvar score: float = damage_done * (_spawn_level / 8 + 1) * settings_multiplier * size_multiplier\n\t\n\treturn score\n\n\nfunc get_damage_to_portal() -> float:\n#\tNOTE: final wave boss deals full damage to portal\n\tvar wave_count: int = Globals.get_wave_count()\n\tvar is_final_wave: bool = _spawn_level == wave_count\n\n\tif is_final_wave:\n\t\treturn 100.0\n\n\tvar size_is_challenge: bool = CreepSize.is_challenge(_size)\n\n\tif size_is_challenge:\n\t\treturn 0\n\n\tvar damage_done: float = get_damage_done()\n\n\tvar type_multiplier: float = CreepSize.get_portal_damage_multiplier(_size)\n\n\tvar damage_done_power: float\n\tif _size == CreepSize.enm.BOSS:\n\t\tdamage_done_power = 4\n\telse:\n\t\tdamage_done_power = 5\n\n\tvar damage_reduction_from_hp_ratio: float = (1 - pow(damage_done, damage_done_power))\n\tvar damage_to_portal: float = 2.5 * type_multiplier * damage_reduction_from_hp_ratio * _portal_damage_multiplier\n\n\tvar player: Player = get_player()\n\tvar team: Team = player.get_team()\n\tvar team_size: int = team.get_players().size()\n\n\tdamage_to_portal = Utils.divide_safe(damage_to_portal, team_size, damage_to_portal)\n\n\treturn damage_to_portal\n\n\n# Creep moves to a point on path, which is closest to given\n# point.\nfunc move_to_point(point: Vector2):\n\tvar curve: Curve2D = _path.curve\n\n\tvar min_distance: float = 10000.0\n\tvar min_index: int = -1\n\tvar min_position: Vector2 = Vector2.ZERO\n\tvar prev: Vector2 = Utils.get_path_point_wc3(_path, 0)\n\n\tfor i in range(1, curve.point_count):\n\t\tvar curr: Vector2 = Utils.get_path_point_wc3(_path, i)\n\t\tvar closest_point: Vector2 = Geometry2D.get_closest_point_to_segment(point, prev, curr)\n\t\tvar distance: float = closest_point.distance_to(point)\n\n\t\tif distance < min_distance:\n\t\t\tmin_distance = distance\n\t\t\tmin_index = i\n\t\t\tmin_position = closest_point\n\n\t\tprev = curr\n\n\tif min_index == -1:\n\t\treturn\n\t\n\tset_position_wc3_2d(min_position)\n\t_current_path_index = min_index\n\n\n# NOTE: creep.adjustHeight() in JASS\n# NOTE: can't use tween here because it causes desync.\nfunc adjust_height(height: float, speed: float):\n#\tNOTE: can't create tween's while node is outside tree.\n#\tIf creep is outside tree then it's okay to do nothing\n#\tbecause creep is about to get deleted anyway.\n\tif !is_inside_tree():\n\t\treturn\n\n\tvar creep_is_air: bool = get_size() == CreepSize.enm.AIR\n\n#\tNOTE: shouldn't change height of air creeps - it would\n#\tlook weird\n\tif creep_is_air:\n\t\treturn\n\t\n\t_target_height += height\n\t_height_change_speed = speed\n\n\n# NOTE: creep.dropItem() in JASS\n\nfunc drop_item(caster: Tower, use_creep_player: bool):\n\tvar random_item: int = ItemDropCalc.get_random_item(caster, self)\n\n\tif random_item == 0:\n\t\treturn\n\n\tdrop_item_by_id(caster, use_creep_player, random_item)\n\n\tEventBus.item_dropped.emit()\n\n\nfunc drop_item_by_id(caster: Tower, use_creep_player: bool, item_id: int):\n\tvar player_for_item: Player\n\tif use_creep_player:\n\t\tplayer_for_item = get_player()\n\telse:\n\t\tplayer_for_item = caster.get_player()\n\n\tvar item_position: Vector3 = get_position_wc3()\n\tvar item: Item = Item.create(player_for_item, item_id, item_position)\n\n\tvar item_name: String = ItemProperties.get_display_name(item_id)\n\tvar item_rarity: Rarity.enm = ItemProperties.get_rarity(item_id)\n\tvar rarity_color: Color = Rarity.get_color(item_rarity)\n\n\tplayer_for_item.display_floating_text(item_name, self, rarity_color)\n\n\tvar autooil_tower: Tower = player_for_item.get_autooil_tower(item_id)\n\tvar autooil_exists_for_this_item: bool = autooil_tower != null\n\tif autooil_exists_for_this_item:\n\t\titem.pickup(autooil_tower)\n\t\t\n\t\tvar oil_name: String = item.get_display_name()\n\t\tvar tower_name: String = autooil_tower.get_display_name()\n\t\tMessages.add_normal(player_for_item, tr(\"MESSAGE_AUTOOIL_APPLY\").format({OIL_NAME = oil_name, TOWER_NAME = tower_name}))\n\n\t\treturn\n\telse:\n\t\titem.fly_to_stash(0.0)\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: see explanation of z_index setup in map.gd\nfunc _calculate_current_z_index() -> int:\n\tif get_z() > 1.5 * Constants.TILE_SIZE_WC3:\n\t\tif get_size() == CreepSize.enm.AIR:\n\t\t\treturn 21\n\t\telse:\n\t\t\treturn 20\n\telse:\n\t\treturn 10\n\n\nfunc _move(delta):\n\tvar path_is_over: bool = _current_path_index >= _path.get_curve().get_point_count()\n\tif path_is_over:\n\t\t_deal_damage_to_portal()\n\t\tremove_from_game()\n\n\t\treturn\n\n\tvar path_point_wc3: Vector2 = Utils.get_path_point_wc3(_path, _current_path_index)\n\tvar move_delta: float = get_current_movespeed() * delta\n\tvar old_position_2d: Vector2 = get_position_wc3_2d()\n\tvar new_position_2d: Vector2 = old_position_2d.move_toward(path_point_wc3, move_delta)\n\tset_position_wc3_2d(new_position_2d)\n\n\tmoved.emit(delta)\n\t\n\tvar reached_path_point: bool = (new_position_2d == path_point_wc3)\n\t\n\tif reached_path_point:\n\t\t_current_path_index += 1\n\n\tvar new_facing_angle: float = _get_current_movement_angle()\n\tset_unit_facing(new_facing_angle)\n\n\nfunc _deal_damage_to_portal():\n\tvar damage_to_portal = get_damage_to_portal()\n\tvar damage_to_portal_string: String = Utils.format_percent(damage_to_portal / 100, 1)\n\tvar damage_done: float = get_damage_done()\n\tvar damage_done_string: String = Utils.format_percent(damage_done, 2)\n\tvar creep_size: CreepSize.enm = get_size_including_challenge_sizes()\n\tvar creep_size_string: String = CreepSize.get_display_string(creep_size)\n\tvar creep_score: float = get_score(Globals.get_difficulty(), Globals.get_wave_count(), Globals.get_game_mode())\n\n\tvar player: Player = get_player()\n\t\n\tif creep_size == CreepSize.enm.BOSS:\n\t\tMessages.add_normal(player, tr(\"MESSAGE_DAMAGE_TO_BOSS\").format({DAMAGE = damage_done_string}))\n\telse:\n\t\tMessages.add_normal(player, tr(\"MESSAGE_FAILED_TO_KILL\").format({CREEP_SIZE = creep_size_string.to_upper()}))\n\n\tif damage_to_portal > 0:\n\t\tMessages.add_normal(player, tr(\"MESSAGE_LOSE_LIVES\").format({LOST_LIVES = damage_to_portal_string}))\n\n#\tNOTE: creeps still give partial score if they are not\n#\tkilled. Ratio depends on creep health.\n\tif creep_score > 0:\n\t\tplayer.add_score(creep_score)\n\n\tvar team: Team = player.get_team()\n\n\tteam.modify_lives(-damage_to_portal)\n\tteam.play_portal_damage_sfx()\n\n\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/silence_area.tscn\", self)\n\tEffect.set_color(effect, Color8(90, 180, 250))\n\tEffect.set_scale(effect, 1.5)\n\n\tEventBus.portal_received_damage.emit()\n\n\n# Returns current movement angle, top down and in degrees\nfunc _get_current_movement_angle() -> float:\n\tvar path_curve: Curve2D = _path.get_curve()\n\n\tif _current_path_index >= path_curve.point_count:\n\t\treturn _facing_angle\n\n\tvar next_point: Vector2 = Utils.get_path_point_wc3(_path, _current_path_index)\n\tvar facing_vector: Vector2 = next_point - get_position_wc3_2d()\n\tvar facing_angle_radians: float = facing_vector.angle()\n\tvar facing_angle_degrees: float = rad_to_deg(facing_angle_radians)\n\n\treturn facing_angle_degrees\n\n\nfunc _get_creep_animation() -> String:\n\tvar animation_list: Array[String]\n\t\n\tif get_size() == CreepSize.enm.AIR:\n\t\tanimation_list = fly_animations\n\telse:\n\t\tanimation_list = slow_run_animations\n\n\tvar animation: String = _get_animation_based_on_facing_angle(animation_list)\n\n\treturn animation\n\n\nfunc _get_death_animation() -> String:\n\tvar animation: String = _get_animation_based_on_facing_angle(death_animations)\n\n\treturn animation\n\n\nfunc _get_animation_based_on_facing_angle(animation_order: Array[String]) -> String:\n# \tNOTE: convert facing angle to animation index by\n# \tbreaking down the 360 degree space into sections. 4 for\n# \tground units and 8 for air units. Then we figure out\n# \twhich section does the facing angle belong to. The index\n# \tof that section will be equal to the animation index.\n\tvar facing_angle_top_down: float = _facing_angle\n\tvar facing_angle_isometric: float = facing_angle_top_down - 45\n\tvar section_count: int = animation_order.size()\n\tvar section_angle: float = 360.0 / section_count\n\tvar animation_index: int = roundi(facing_angle_isometric / section_angle)\n\n\tif animation_index >= animation_order.size():\n\t\tprint_debug(\"animation_index out of bounds = \", animation_index)\n\t\tanimation_index = 0\n\n\tvar animation: String = animation_order[animation_index]\n\n\treturn animation\n\n\n# NOTE: different thickness is used for different sizes to\n# account for differences in sprite scale.\nfunc _get_outline_thickness() -> float:\n\tmatch get_size():\n\t\tCreepSize.enm.MASS: return 4.5\n\t\tCreepSize.enm.NORMAL: return 3.8\n\t\tCreepSize.enm.AIR: return 3.0\n\t\tCreepSize.enm.CHAMPION: return 2.8\n\t\tCreepSize.enm.BOSS: return 2.0\n\t\tCreepSize.enm.CHALLENGE_MASS: return 4.5\n\t\tCreepSize.enm.CHALLENGE_BOSS: return 2.0\n\n\treturn 10.0\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_health_changed():\n\tvar health_ratio: float = get_health_ratio()\n\t_health_bar.ratio = health_ratio\n\n\nfunc _on_death(_event: Event):\n\tvar creep_score: float = get_score(Globals.get_difficulty(), Globals.get_wave_count(), Globals.get_game_mode())\n\n\tif creep_score > 0:\n\t\tvar player: Player = get_player()\n\t\tplayer.add_score(creep_score)\n\n# \tDeath visual\n\tvar effect_id: int = Effect.create_simple_at_unit(\"res://src/effects/death_explode.tscn\", self)\n\tvar effect_scale: float = max(_sprite_dimensions.x, _sprite_dimensions.y) / Constants.DEATH_EXPLODE_EFFECT_SIZE\n\tEffect.set_scale(effect_id, effect_scale)\n\n# \tAdd corpse object\n\tif _size != CreepSize.enm.AIR:\n\t\tvar death_animation: String = _get_death_animation()\n\t\tvar corpse: CreepCorpse = CreepCorpse.make(self, _sprite, death_animation)\n\t\tvar corpse_pos: Vector3 = Vector3(get_x(), get_y(), 0)\n\t\tcorpse.set_position_wc3(corpse_pos)\n\t\tUtils.add_object_to_world(corpse)\n\n\t\tvar blood_pool: Node2D = Preloads.blood_pool_scene.instantiate()\n\t\tblood_pool.position = position\n\t\tUtils.add_object_to_world(blood_pool)\n\n\n#########################\n### Setters / Getters ###\n#########################\n\n# NOTE: creep.getBaseBountyValue() in JASS\nfunc get_base_bounty_value() -> float:\n\tvar creep_size: CreepSize.enm = get_size_including_challenge_sizes()\n\tvar gold_multiplier: float = CreepSize.get_gold_multiplier(creep_size)\n\tvar spawn_level: int = get_spawn_level()\n\tvar bounty: float = gold_multiplier * (spawn_level / 8 + 1)\n\n\treturn bounty\n\n\nfunc get_log_name() -> String:\n\tvar size_name: String = CreepSize.get_display_string(_size)\n\tvar log_name: String = \"%s-%d\" % [size_name, get_uid()]\n\n\treturn log_name\n\n\n# NOTE: creeps are always considered to be in combat for the\n# purposes of their autocasts.\nfunc is_in_combat() -> bool:\n\treturn true\n\n\nfunc get_current_movespeed() -> float:\n\tvar base: float = get_base_movespeed()\n\tvar mod: float = get_prop_move_speed()\n\tvar mod_absolute: float = get_prop_move_speed_absolute()\n\tvar unclamped: float = (base + mod_absolute) * mod\n\tvar move_speed: float = clampf(unclamped, Constants.MOVE_SPEED_MIN, Constants.MOVE_SPEED_MAX)\n\n\treturn move_speed\n\n\n# Sets unit facing to an angle with respect to the positive\n# X axis, in degrees.\n# NOTE: angle is top down\n# \n# NOTE: SetUnitFacing() in JASS\nfunc set_unit_facing(angle: float):\n# \tNOTE: limit facing angle to (0, 360) range\n\t_facing_angle = int(angle + 360) % 360\n\n\tvar animation: String = _get_creep_animation()\n\tif animation != \"\":\n\t\t_sprite.play(animation)\n\t\tvar selection_outline: Node2D = get_selection_outline()\n\t\tselection_outline.play(animation)\n\n\n# NOTE: angle is top down\n# NOTE: GetUnitFacing() in JASS\nfunc get_unit_facing() -> float:\n\treturn _facing_angle\n\n# NOTE: this special function forces CHALLENGE_MASS and\n# CHALLENGE_BOSS to be treated as MASS and BOSS creeps. Use\n# get_size_including_challenge_sizes() to get the \"real\"\n# creep size.\nfunc get_size() -> CreepSize.enm:\n\tif _size == CreepSize.enm.CHALLENGE_MASS:\n\t\treturn CreepSize.enm.MASS\n\telif _size == CreepSize.enm.CHALLENGE_BOSS:\n\t\treturn CreepSize.enm.BOSS\n\telse:\n\t\treturn _size\n\nfunc get_size_including_challenge_sizes() -> CreepSize.enm:\n\treturn _size\n\n# NOTE: unit.getCategory() in JASS\nfunc get_category() -> CreepCategory.enm:\n\treturn _category\n\nfunc get_armor_type() -> ArmorType.enm:\n\treturn _armor_type\n\nfunc get_display_name() -> String:\n\treturn tr(\"CREEP_GENERIC_NAME\")\n\n\nfunc get_move_path() -> Path2D:\n\treturn _path\n\n\nfunc get_spawn_level() -> int:\n\treturn _spawn_level\n\n\nfunc get_special_list() -> Array[int]:\n\treturn _special_list\n\n\nfunc set_special_list(special_list: Array[int]):\n\t_special_list = special_list\n\n\nfunc get_ability_button_data_list() -> Array[AbilityButton.Data]:\n\tvar list: Array[AbilityButton.Data] = []\n\n\tvar armor_type: ArmorType.enm = get_armor_type()\n\tvar armor_type_name: String = ArmorType.get_display_string(armor_type)\n\tvar armor_type_name_colored: String = ArmorType.convert_to_colored_string(armor_type)\n\tvar armor_type_damage_taken: String = ArmorType.get_rich_text_for_damage_taken(armor_type)\n\tvar armor_type_description: String = tr(\"CREEP_ARMOR_ABILITY_DESCRIPTION\").format({ARMOR_TYPE = armor_type_name_colored, DAMAGE_FROM_TEXT = armor_type_damage_taken})\n\tvar armor_type_ability: AbilityButton.Data = AbilityButton.Data.new()\n\tarmor_type_ability.ability_name = tr(\"CREEP_ARMOR_ABILITY_TITLE\").format({ARMOR_TYPE = armor_type_name})\n\tarmor_type_ability.icon = \"res://resources/icons/shields/shield_green.tres\"\n\tarmor_type_ability.description_long = armor_type_description\n\tlist.append(armor_type_ability)\n\n\tfor special in _special_list:\n\t\tvar special_name: String = WaveSpecialProperties.get_special_name(special)\n\t\tvar special_description: String = WaveSpecialProperties.get_description(special)\n\t\tvar special_icon: String = WaveSpecialProperties.get_icon_path(special)\n\n\t\tvar ability: AbilityButton.Data = AbilityButton.Data.new()\n\t\tability.ability_name = special_name\n\t\tability.icon = special_icon\n\t\tability.description_long = special_description\n\t\tlist.append(ability)\n\n\treturn list\n"
  },
  {
    "path": "src/creeps/creep_blood_pool.gd",
    "content": "extends Node2D\n\n\n# Corpse visual created after creep dies. Fades away slowly\n# then disappears. Note that this is not the corpse.\n\n\nconst DURATION: float = 60\n\n@export var _sprite: Sprite2D\n\n\nfunc _ready():\n#\tStart out transparent\n\t_sprite.modulate.a = 0\n\n#\tNOTE: draw blood pool between floor tile and creep\n#\tcorpse\n\t_sprite.z_index = -1\n\n\n#\tRandomize properties of blood pool to make them look\n#\tvaried\n\tvar random_offset: Vector2 = Vector2(Globals.synced_rng.randf_range(-10, 10), Globals.synced_rng.randf_range(-10, 10))\n\t_sprite.position += random_offset\n\n\tvar random_scale: Vector2 = Vector2(Globals.synced_rng.randf_range(0.95, 1.05), Globals.synced_rng.randf_range(0.95, 1.05)) * Globals.synced_rng.randf_range(0.7, 1.0)\n\t_sprite.scale = random_scale\n\n\t_sprite.flip_h = Utils.rand_chance(Globals.synced_rng, 0.5)\n\t_sprite.flip_v = Utils.rand_chance(Globals.synced_rng, 0.5)\n\n\tvar transparency_max: float = Globals.synced_rng.randf_range(0.4, 0.6)\n\n# \tBlood pool fades in shortly after creep death animation\n# \tfalls to the ground.\n# \tThen it slowly fades away.\n\tvar game_speed: int = Globals.get_update_ticks_per_physics_tick()\n\tvar modulate_tween = create_tween()\n\tmodulate_tween.set_speed_scale(game_speed)\n\tmodulate_tween.tween_property(_sprite, \"modulate\",\n\t\tColor(_sprite.modulate.r, _sprite.modulate.g, _sprite.modulate.b, transparency_max), 1.0).set_delay(1.0)\n\tmodulate_tween.tween_property(_sprite, \"modulate\",\n\t\tColor(_sprite.modulate.r, _sprite.modulate.g, _sprite.modulate.b, 0),\n\t\t0.6 * DURATION).set_delay(0.4 * DURATION).set_trans(Tween.TRANS_LINEAR)\n\tmodulate_tween.finished.connect(_on_fade_finished)\n\n\nfunc _on_fade_finished():\n\tqueue_free()\n"
  },
  {
    "path": "src/creeps/creep_blood_pool.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://w47xmru10osr\"]\n\n[ext_resource type=\"Script\" path=\"res://src/creeps/creep_blood_pool.gd\" id=\"1_5iqax\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bqfroocbty8l3\" path=\"res://assets/misc/creep_blood_pool.png\" id=\"1_u8fa2\"]\n\n\n[node name=\"CreepBloodPool\" type=\"Node2D\" node_paths=PackedStringArray(\"_sprite\")]\nscript = ExtResource(\"1_5iqax\")\n_sprite = NodePath(\"Sprite2D\")\n\n[node name=\"Sprite2D\" type=\"Sprite2D\" parent=\".\"]\nmodulate = Color(0.65098, 0.196078, 0.196078, 0.588235)\ntexture = ExtResource(\"1_u8fa2\")\n"
  },
  {
    "path": "src/creeps/creep_corpse.gd",
    "content": "class_name CreepCorpse extends Unit\n\n\n# Corpse visual created after creep dies. Fades away slowly\n# then disappears.\n# \n# NOTE: this code is very easy to change in such a way that\n# it creates a new desync source. It looks like it's visuals\n# only but it's not - it affects game logic sometimes.\n# Corpses are used by Undistrubed Crypt tower to deal AoE\n# damage centered on corpse positions. Therefore, corpse\n# properties like position and duration MUST be synced with\n# the game client and game speed. That is why a ManualTimer\n# is used for expiry instead of a tween.\n# \n# Note that for the position and modulate of the sprite (not\n# root node), it's ok to use tweens because these properties\n# won't have any effect on game logic. But these tweens do\n# need to be synced to game speed - otherwise it looks weird\n# on fast game speeds.\n\n\nconst DURATION: float = 10\nconst RANDOM_OFFSET: float = 5\n\nvar _creep_uid: int = 0\nvar _creep_unit_scale: float = 1.0\n\n@export var _sprite: AnimatedSprite2D\n@export var _visual: Node2D\n@export var _expire_timer: ManualTimer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tsuper()\n\n\tadd_to_group(\"corpses\")\n\n\t_set_visual_node(_visual)\n\t\n#\tNOTE: see explanation of z_index setup in map.gd\n\tz_index = 10\n\n#\tNOTE: need to inherit creep unit scale in case creep's\n#\tscale is altered\n\t_visual.scale = Vector2.ONE * _creep_unit_scale\n\t\n\t_expire_timer.start(DURATION)\n\n\tvar game_speed: int = Globals.get_update_ticks_per_physics_tick()\n\n#\tMove corpse to a random small offset during death\n#\tanimation. Otherwise corpses line up perfectly and it\n#\tlooks weird.\n\tvar position_tween = create_tween()\n\tposition_tween.set_speed_scale(game_speed)\n\tvar random_offset_top_down: Vector2 = Vector2(\n\t\tRANDOM_OFFSET * Globals.local_rng.randf_range(-1, 1),\n\t\tRANDOM_OFFSET * Globals.local_rng.randf_range(-1, -1))\n\tvar random_offset_canvas: Vector2 = VectorUtils.top_down_to_canvas(random_offset_top_down)\n\tvar final_pos: Vector2 = _sprite.position + random_offset_canvas\n\tposition_tween.tween_property(_sprite, \"position\",\n\t\tfinal_pos,\n\t\t0.2 * DURATION).set_trans(Tween.TRANS_LINEAR)\n\n\tvar fade_tween = create_tween()\n\tfade_tween.set_speed_scale(game_speed)\n\tfade_tween.tween_property(_sprite, \"modulate\",\n\t\tColor(_sprite.modulate.r, _sprite.modulate.g, _sprite.modulate.b, 0),\n\t\t0.2 * DURATION).set_delay(0.8 * DURATION).set_trans(Tween.TRANS_LINEAR)\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: this uid is invalid because creep is removed from\n# game before corpse is created\nfunc get_creep_uid() -> int:\n\treturn _creep_uid\n\n\n#########################\n###      Private      ###\n#########################\n\n# Copies sprite from creep and starts the death animation.\n# NOTE: need to copy original sprite's position and scale to\n# correctly display the same thing.\nfunc _setup_sprite(creep_sprite: CreepSprite, death_animation: String):\n\t_sprite.sprite_frames = creep_sprite.sprite_frames.duplicate()\n\t_sprite.scale = creep_sprite.scale\n#\tNOTE: need to copy position of sprite because creep\n#\tsprites are centered via position\n\t_sprite.position = creep_sprite.position\n\t_sprite.sprite_frames.set_animation_loop(death_animation, false)\n#\tNOTE: play death animation with random speed to make\n#\tthem look more diverse\n\t_sprite.set_speed_scale(Globals.synced_rng.randf_range(1.0, 1.6))\n\tvar animation_offset: Vector2 = creep_sprite.get_offset_for_animation(death_animation)\n\t_sprite.set_offset(animation_offset)\n\t_sprite.play(death_animation)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_expire_timer_timeout():\n\tremove_from_game()\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(creep: Creep, sprite: AnimatedSprite2D, death_animation: String) -> CreepCorpse:\n\tvar corpse: Node2D = Preloads.corpse_scene.instantiate()\n\tvar player: Player = creep.get_player()\n\tcorpse.set_player(player)\n\tcorpse._setup_sprite(sprite, death_animation)\n\tcorpse._creep_uid = creep.get_uid()\n\tcorpse._creep_unit_scale = creep.get_unit_scale()\n\n\treturn corpse\n"
  },
  {
    "path": "src/creeps/creep_corpse.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dsfo2v7m21tqm\"]\n\n[ext_resource type=\"Script\" path=\"res://src/creeps/creep_corpse.gd\" id=\"1_mvyph\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_7a4st\"]\n\n[node name=\"CreepCorpse\" type=\"Node2D\" node_paths=PackedStringArray(\"_sprite\", \"_visual\", \"_expire_timer\")]\nscript = ExtResource(\"1_mvyph\")\n_sprite = NodePath(\"Visual/Sprite2D\")\n_visual = NodePath(\"Visual\")\n_expire_timer = NodePath(\"ExpireTimer\")\n\n[node name=\"Visual\" type=\"Node2D\" parent=\".\"]\n\n[node name=\"Sprite2D\" type=\"AnimatedSprite2D\" parent=\"Visual\"]\n\n[node name=\"ExpireTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_7a4st\")\none_shot = true\n\n[connection signal=\"timeout\" from=\"ExpireTimer\" to=\".\" method=\"_on_expire_timer_timeout\"]\n"
  },
  {
    "path": "src/creeps/creep_spawner.gd",
    "content": "class_name CreepSpawner extends Node\n\n\n# Spawns creeps for creep waves.\n\n\nsignal all_creeps_spawned\n\n\n# NOTE: the values for champion and boss are unused because\n# waves with champions use delay of the main creep size\n# while bosses are alone in their waves and have no creeps\n# after them. This is intended behavior.\nconst _creep_delay_map: Dictionary = {\n\tCreepSize.enm.MASS: [0.15, 0.4],\n\tCreepSize.enm.NORMAL: [0.4, 2.2],\n\tCreepSize.enm.AIR: [1.0, 3.0],\n\tCreepSize.enm.CHAMPION: [0.7, 4.4],\n\tCreepSize.enm.BOSS: [1.5, 9.0],\n\tCreepSize.enm.CHALLENGE_MASS: [0.15, 0.4],\n\tCreepSize.enm.CHALLENGE_BOSS: [1.5, 9.0],\n}\n\n\nvar _player: Player = null\nvar _ground_path: WavePath = null\nvar _air_path: WavePath = null\nvar _current_wave: Wave\nvar _creep_index: int = 0\n\n@export var _timer_between_creeps: ManualTimer\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_player(player: Player):\n\t_player = player\n\n\t_player.game_lose.connect(_on_game_lose)\n\n\t_ground_path = Utils.find_creep_path(player, false)\n\t_air_path = Utils.find_creep_path(player, true)\n\n\tif _air_path == null || _ground_path == null:\n\t\tpush_error(\"Failed to find paths for player %d, player index %d\" % [player.get_id(), player.get_index()])\n\n\n# NOTE: this f-n assumes that previous wave has finished\n# spawning.\nfunc start_spawning_wave(wave: Wave):\n\t_timer_between_creeps.stop()\n\t_current_wave = wave\n\t_creep_index = 0\n\t_spawn_next_creep()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _spawn_next_creep():\n\tvar creep_combination: Array[CreepSize.enm] = _current_wave.get_creep_combination()\n\tvar creep_size: CreepSize.enm = creep_combination[_creep_index]\n\tvar creep_race: CreepCategory.enm = _current_wave.get_creep_race()\n\tvar creep_armor: float = _current_wave.get_base_armor()\n\tvar creep_armor_type: ArmorType.enm = _current_wave.get_armor_type()\n\tvar creep_level: int = _current_wave.get_level()\n\tvar creep_health: float = CreepSpawner.get_creep_health(_current_wave, creep_size)\n\tvar creep_specials: Array[int] = _current_wave.get_specials()\n\tvar creep_path: WavePath = _get_creep_path(creep_size)\n\tvar creep_scene_name: String = Wave.get_scene_name_for_creep_type(creep_size, creep_race)\n\t\n\tif !Preloads.creep_scenes.has(creep_scene_name):\n\t\tpush_error(\"Could not find a scene for creep size [%s] and race [%].\" % [creep_size, creep_race])\n\n\t\treturn\n\n\tvar creep_scene: PackedScene = Preloads.creep_scenes[creep_scene_name]\n\tvar creep: Creep = creep_scene.instantiate()\n\tcreep.set_properties(creep_path, _player, creep_size, creep_armor_type, creep_race, creep_health, creep_armor, creep_level)\n\n\tvar first_path_point: Vector2 = Utils.get_path_point_wc3(creep_path, 0)\n\tcreep.set_position_wc3_2d(first_path_point)\n\n\t_current_wave.add_alive_creep(creep)\n\n\tUtils.add_object_to_world(creep)\n\tprint_verbose(\"Spawned creep [%s].\" % creep)\n\n#\tNOTE: buffs must be applied after creep has been added\n#\tto world\n\tWaveSpecial.apply_to_creep(creep_specials, creep)\n\t\n\t_creep_index += 1\n\t\n\tvar creep_count: int = _current_wave.get_creep_count()\n\tvar spawned_all_creeps: bool = _creep_index >= creep_count\n\t\n\tif spawned_all_creeps:\n\t\tprint_verbose(\"Finished spawning creeps for current wave.\")\n\t\t\n\t\tall_creeps_spawned.emit()\n\telse:\n#\t\tNOTE: need to calculate delay based on the main\n#\t\tcreep size of the way, NOT the creep size of the\n#\t\tcurrent creep. This is important for mass+champ or\n#\t\tnormal+champ waves having appropriate spacing.\n\t\tvar wave_main_creep_size: CreepSize.enm = _current_wave.get_creep_size()\n\t\tvar delay_before_next_creep: float = CreepSpawner.get_creep_delay(wave_main_creep_size)\n\t\t_timer_between_creeps.start(delay_before_next_creep)\n\t\tprint_verbose(\"Started creep spawn timer with delay [%f].\" % delay_before_next_creep)\n\n\nfunc _get_creep_path(creep_size: CreepSize.enm) -> Path2D:\n\tif creep_size == CreepSize.enm.AIR:\n\t\treturn _air_path\n\telse:\n\t\treturn _ground_path\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_spawn_timer_timeout():\n\t_spawn_next_creep()\n\n\nfunc _on_game_lose():\n\t_timer_between_creeps.stop()\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func get_creep_health(wave: Wave, creep_size: CreepSize.enm) -> float:\n\tvar size_multiplier: float = CreepSize.health_multiplier_map[creep_size]\n\tvar creep_health: float = wave.get_base_hp() * size_multiplier\n\n\treturn creep_health\n\n\nstatic func get_creep_delay(wave_main_creep_size: CreepSize.enm) -> float:\n\tvar delay_range: Array = _creep_delay_map[wave_main_creep_size]\n\tvar delay_min: float = delay_range[0]\n\tvar delay_max: float = delay_range[1]\n\tvar creep_delay: float = Globals.synced_rng.randf_range(delay_min, delay_max)\n\t\n\treturn creep_delay\n"
  },
  {
    "path": "src/creeps/creep_spawner.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b80b85lbixydk\"]\n\n[ext_resource type=\"Script\" path=\"res://src/creeps/creep_spawner.gd\" id=\"1\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_wbil6\"]\n\n[node name=\"CreepSpawner\" type=\"Node\" node_paths=PackedStringArray(\"_timer_between_creeps\")]\nscript = ExtResource(\"1\")\n_timer_between_creeps = NodePath(\"SpawnTimer\")\n\n[node name=\"SpawnTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_wbil6\")\none_shot = true\n\n[connection signal=\"timeout\" from=\"SpawnTimer\" to=\".\" method=\"_on_spawn_timer_timeout\"]\n"
  },
  {
    "path": "src/creeps/creep_sprite.gd",
    "content": "@tool\nclass_name CreepSprite extends AnimatedSprite2D\n\n\n@export var sprite_sheets_dir: String\n@export var _animation_offset_map: Dictionary = {}\n\nconst ACTIONS = [\"slow_run\", \"death\", \"fly\"]\nconst DIRECTIONS = [\"E\", \"SW\", \"W\", \"NE\", \"S\", \"SE\", \"N\", \"NW\"]\nconst ANIMATION_FPS = 15.0\n\n\nfunc _ready():\n\t# The code below is used to generate SpriteFrames in the editor.\n\t# It's not necessary to call this logic in runtime.\n\tif not Engine.is_editor_hint() or sprite_sheets_dir == \"\":\n\t\treturn\n\n\t_animation_offset_map.clear()\n\t\n\tvar start_time = Time.get_ticks_msec()\n\t\n\tsprite_frames = SpriteFrames.new()\n\n\tfor action in ACTIONS:\n\t\tfor direction in DIRECTIONS:\n\t\t\tvar animation_name = \"%s_%s\" % [action, direction]\n\t\t\tvar sprite_sheet_path = _get_sprite_sheet_path(animation_name)\n\n\t\t\t_create_animation(animation_name, sprite_sheet_path)\n\t\n#\tNOTE: remove default animation because it's empty\n\tsprite_frames.remove_animation(\"default\")\n\n#\tSwitch to some valid animation to display it in godot editor\n\tvar animation_list: Array = sprite_frames.get_animation_names()\n\tif !animation_list.is_empty():\n\t\tvar first_animation: String = animation_list[0]\n\t\tset_animation(first_animation)\n\n\tvar end_time = Time.get_ticks_msec()\n\tprint_verbose(\"Generated animation frames in [%s] seconds.\" % [(end_time - start_time) / 1000.0])\n\n\n# NOTE: this will fix the offset both in game and in editor\n# because this is a tool script\nfunc _process(_delta: float):\n\tif sprite_sheets_dir == \"\":\n\t\treturn\n\n\t_update_offset()\n\n# NOTE: each animation has a different offset which is\n# created during the packing process. To display the\n# animation at correct position, this offset needs to be\n# applied to sprite.\n# NOTE: if animatedsprited2d is scaled, then offset will\n# be scaled also, so we need to account for that and\n# divide offset by scale\nfunc get_offset_for_animation(animation_name: String):\n\tvar packed_offset: Vector2 = _animation_offset_map.get(animation_name, Vector2.ZERO) as Vector2\n\tvar scaled_offset: Vector2 = packed_offset / scale\n\n\treturn scaled_offset\n\n\nfunc _create_animation(animation_name: String, sprite_sheet_path: String):\n\tif sprite_frames.has_animation(animation_name):\n\t\tsprite_frames.clear(animation_name)\n\n#\tNOTE: currently quietly skipping non-existing animations\n#\tbecause some creeps don't use animations for NW, SW,\n#\tetc.\n\tif !ResourceLoader.exists(sprite_sheet_path):\n\t\treturn\n\n\tvar sprite_sheet_atlas = load(sprite_sheet_path)\n\tprint_verbose(\"sprite_sheet_path=\", sprite_sheet_path)\n\n\tprint_verbose(\"sprite_sheet_atlas.get_width() = \", sprite_sheet_atlas.get_width())\n\t\n\tvar metadata: PackedMetadata = PackedMetadata.get_metadata_for_sheet(sprite_sheet_path)\n\n\tvar packed_offset: Vector2 = metadata.get_offset() * sprite_sheet_atlas.get_size()\n\t_animation_offset_map[animation_name] = packed_offset\n\n\tvar rows: int = metadata.get_row_count()\n\tvar cols: int = metadata.get_col_count()\n\tvar cell_size: Vector2 = Vector2(sprite_sheet_atlas.get_width() / cols, sprite_sheet_atlas.get_height() / rows)\n\n#\tNOTE: sprite count used to be not needed when we could\n#\tuse get_used_rect() to detect whether a frame is empty\n#\tor not. Compression was turned on for creep atlases and\n#\tnow we can't use get_used_rect() anymore.\n\tvar sprite_count: int = metadata.get_sprite_count()\n\n\tif sprite_frames.has_animation(animation_name):\n\t\tsprite_frames.clear(animation_name)\n\n\tsprite_frames.add_animation(animation_name)\n\tsprite_frames.set_animation_speed(animation_name, ANIMATION_FPS)\n\n\tfor row in range(0, rows):\n\t\tfor col in range(0, cols):\n\t\t\tvar added_all_frames: bool = sprite_frames.get_frame_count(animation_name) == sprite_count\n\t\t\tif added_all_frames:\n\t\t\t\tbreak\n\n\t\t\t_create_animation_frame(animation_name, row, col, sprite_sheet_atlas, cell_size)\n\n\nfunc _create_animation_frame(anim, row, col, sprite_sheet, cell_size: Vector2):\n\tvar texture = AtlasTexture.new()\n\ttexture.atlas = sprite_sheet\n\ttexture.region = Rect2(col * cell_size.x, row * cell_size.y, cell_size.x, cell_size.y)\n\n\t# print_verbose(\"texture.region=\", texture.region)\n\tsprite_frames.add_frame(anim, texture)\n\n\nfunc _update_offset():\n\tvar animation_name: String = get_animation()\n\tvar current_offset: Vector2 = get_offset_for_animation(animation_name)\n\tset_offset(current_offset)\n\n\nfunc _get_sprite_sheet_path(animation_name: String) -> String:\n\tvar animation_path = \"%s/%s.png\" % [sprite_sheets_dir, animation_name]\n\n\treturn animation_path\n"
  },
  {
    "path": "src/creeps/health_bar.gd",
    "content": "@tool\nextends ProgressBar\n\n\n# The health bar changes colors based on current health.\n# Green at full health, orange at middle, red when close to\n# 0%.\n\n@export var color3: Color\n@export var color2: Color\n@export var color1: Color\n\n\n# NOTE: load color for initial value here\nfunc _ready():\n\t_on_value_changed(value)\n\n\nfunc _on_value_changed(new_value: float):\n\tvar health_ratio: float = Utils.divide_safe(new_value, max_value)\n\n\tvar current_color: Color\n\tif health_ratio > 0.75:\n\t\tcurrent_color = color3\n\telif health_ratio > 0.5:\n\t\tcurrent_color = lerp(color2, color3, (health_ratio - 0.5) * 4)\n\telif health_ratio > 0.25:\n\t\tcurrent_color = lerp(color1, color2, (health_ratio - 0.25) * 4)\n\telse:\n\t\tcurrent_color = color1\n\n\tmodulate = current_color\n"
  },
  {
    "path": "src/creeps/instances/challenge/challenge_boss_creep.tscn",
    "content": "[gd_scene load_steps=171 format=3 uid=\"uid://ctyu4c3cvngrh\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_bwcxi\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b1s341ilp1g0f\" path=\"res://assets/creeps/orc/boss/death_E.png\" id=\"2_vc8dd\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://kyq50l132wm1\" path=\"res://assets/creeps/orc/boss/death_N.png\" id=\"3_fvspa\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cmytlwkuq6i8q\" path=\"res://assets/creeps/orc/boss/death_S.png\" id=\"4_2ys2h\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://pulp58p3vflw\" path=\"res://assets/creeps/orc/boss/death_W.png\" id=\"5_iesaf\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c4mbacosga5se\" path=\"res://assets/creeps/orc/boss/slow_run_E.png\" id=\"6_rt1hh\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dcrmib66n1i1k\" path=\"res://assets/creeps/orc/boss/slow_run_N.png\" id=\"7_y76jy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://be8at5qd2xtfm\" path=\"res://assets/creeps/orc/boss/slow_run_S.png\" id=\"8_27r43\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bf8mfmg7jkmv7\" path=\"res://assets/creeps/orc/boss/slow_run_W.png\" id=\"9_x5i10\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hedlm\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6jxtm\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g7r5k\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p8yuc\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mi88t\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7ek2a\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l2hbx\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nlcav\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_phpwg\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jfpbe\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bhhbg\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kott4\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oj712\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v46lm\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_plejr\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tbctm\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_540v1\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wonqo\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tm7fr\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k0dsn\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tsbvw\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vneuh\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8n57k\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7mipi\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t55je\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(0, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m65ld\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(204, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s5tfy\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(408, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6o2aq\"]\natlas = ExtResource(\"2_vc8dd\")\nregion = Rect2(612, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ncl2h\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lg41y\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hd8ut\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vr1bo\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_khq0k\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bdqan\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_feh2w\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nayrp\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3pr7f\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p112h\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_02tn1\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8hxnq\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_52ktr\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0ie7\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nxx38\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1rse2\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5gly0\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6olnl\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_knbkg\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gghtx\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6c62a\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ruvjn\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jstbd\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u1vjn\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_385vu\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(0, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jrkw6\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(182, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p3l5h\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(364, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gd7gh\"]\natlas = ExtResource(\"3_fvspa\")\nregion = Rect2(546, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gbo7i\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4pvde\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vr8ox\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3cve7\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f2uwa\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lhejp\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fvk7g\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4p4ea\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mv17l\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_twoah\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uh4px\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ooq2e\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wm1y3\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u4pfy\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vw45o\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6enin\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p8bww\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7dnac\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dbptv\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n7kc2\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_28ymr\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_itv0d\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r5men\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kjqcc\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hcr45\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(0, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_di2jh\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(182, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4ppwf\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(364, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7jomb\"]\natlas = ExtResource(\"4_2ys2h\")\nregion = Rect2(546, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1gifj\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hblkg\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jjpwe\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xdcm3\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wc1rf\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0l163\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3kg32\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e72vf\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_77adm\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3uju6\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s32wf\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jgvmr\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_67vap\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iqbas\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dp3m1\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pymcb\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xn4ew\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4vnwg\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xs0dl\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h3fhp\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p64qr\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cdjp0\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u78w8\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4wmla\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4v8l4\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(0, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cte74\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(204, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gn215\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(408, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2vu74\"]\natlas = ExtResource(\"5_iesaf\")\nregion = Rect2(612, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kl5fb\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(0, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ytbdf\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(121, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bc05m\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(242, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_piduw\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(363, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p6i5j\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(0, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eu2ks\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(121, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uatwi\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(242, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ggxua\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(363, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n4jky\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(0, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ephre\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(121, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jo7de\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(242, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p5833\"]\natlas = ExtResource(\"6_rt1hh\")\nregion = Rect2(363, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xjkfx\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(0, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2f5fs\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(118, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i0ecs\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(236, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6fqj8\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(354, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6s0km\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(0, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l8xwy\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(118, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lp78l\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(236, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nt3rt\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(354, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p8crd\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(0, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kuhhn\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(118, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nodkk\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(236, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wtfej\"]\natlas = ExtResource(\"7_y76jy\")\nregion = Rect2(354, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r88e0\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(0, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g4u6f\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(118, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rg0jl\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(236, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o5vxp\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(354, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3gkx4\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(0, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5vldl\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(118, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ij36i\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(236, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pcfgk\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(354, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jbl6l\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(0, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jikgb\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(118, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lucsg\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(236, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rvb1f\"]\natlas = ExtResource(\"8_27r43\")\nregion = Rect2(354, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kxk7r\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(0, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_582bm\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(121, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v33mk\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(242, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_273vs\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(363, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yh5bq\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(0, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_inhj0\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(121, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8qfnb\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(242, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bv1jo\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(363, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eeote\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(0, 270, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t365e\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(121, 270, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tsiti\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(242, 270, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5a56e\"]\natlas = ExtResource(\"9_x5i10\")\nregion = Rect2(363, 270, 121, 135)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_6ucux\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hedlm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6jxtm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g7r5k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p8yuc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mi88t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7ek2a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l2hbx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nlcav\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_phpwg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jfpbe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bhhbg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kott4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oj712\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v46lm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_plejr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tbctm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_540v1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wonqo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tm7fr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k0dsn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tsbvw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vneuh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8n57k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7mipi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t55je\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m65ld\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s5tfy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6o2aq\")\n}],\n\"loop\": true,\n\"name\": &\"death_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ncl2h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lg41y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hd8ut\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vr1bo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_khq0k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bdqan\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_feh2w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nayrp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3pr7f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p112h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_02tn1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8hxnq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_52ktr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d0ie7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nxx38\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1rse2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5gly0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6olnl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_knbkg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gghtx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6c62a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ruvjn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jstbd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u1vjn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_385vu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jrkw6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p3l5h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gd7gh\")\n}],\n\"loop\": true,\n\"name\": &\"death_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gbo7i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4pvde\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vr8ox\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3cve7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f2uwa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lhejp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fvk7g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4p4ea\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mv17l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_twoah\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uh4px\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ooq2e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wm1y3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u4pfy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vw45o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6enin\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p8bww\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7dnac\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dbptv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n7kc2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_28ymr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_itv0d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r5men\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kjqcc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hcr45\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_di2jh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4ppwf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7jomb\")\n}],\n\"loop\": true,\n\"name\": &\"death_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1gifj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hblkg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jjpwe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xdcm3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wc1rf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0l163\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3kg32\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e72vf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_77adm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3uju6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s32wf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jgvmr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_67vap\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iqbas\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dp3m1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pymcb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xn4ew\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4vnwg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xs0dl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h3fhp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p64qr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cdjp0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u78w8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4wmla\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4v8l4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cte74\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gn215\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2vu74\")\n}],\n\"loop\": true,\n\"name\": &\"death_W\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kl5fb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ytbdf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bc05m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_piduw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p6i5j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eu2ks\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uatwi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ggxua\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n4jky\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ephre\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jo7de\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p5833\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xjkfx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2f5fs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i0ecs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6fqj8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6s0km\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l8xwy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lp78l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nt3rt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p8crd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kuhhn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nodkk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wtfej\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r88e0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g4u6f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rg0jl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o5vxp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3gkx4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5vldl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ij36i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pcfgk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jbl6l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jikgb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lucsg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rvb1f\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kxk7r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_582bm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v33mk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_273vs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yh5bq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_inhj0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8qfnb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bv1jo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eeote\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t365e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tsiti\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5a56e\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"challenge_boss_creep\" instance=ExtResource(\"1_bwcxi\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -120)\nscale = Vector2(2.5, 2.5)\nsprite_frames = SubResource(\"SpriteFrames_6ucux\")\nanimation = &\"death_E\"\noffset = Vector2(0.8, 12.8)\nsprite_sheets_dir = \"res://assets/creeps/orc/boss\"\n_animation_offset_map = {\n\"death_E\": Vector2(2, 32),\n\"death_N\": Vector2(27, 16),\n\"death_S\": Vector2(-27, 31),\n\"death_W\": Vector2(-2, 7),\n\"slow_run_E\": Vector2(10, 14),\n\"slow_run_N\": Vector2(25, 16),\n\"slow_run_S\": Vector2(-25, 15),\n\"slow_run_W\": Vector2(-11, 8)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -250.0\noffset_bottom = -241.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-114, -263, 112, -280, 129, 18, -121, 1)\n"
  },
  {
    "path": "src/creeps/instances/challenge/challenge_mass_creep.tscn",
    "content": "[gd_scene load_steps=183 format=3 uid=\"uid://djhtap2tscqe7\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_56x63\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c031gwyl83vsh\" path=\"res://assets/creeps/orc/mass/death_E.png\" id=\"2_17xdl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://byqwfls7534ta\" path=\"res://assets/creeps/orc/mass/death_N.png\" id=\"3_dl80u\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dc3ghqhhglmqi\" path=\"res://assets/creeps/orc/mass/death_S.png\" id=\"4_vh1bw\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://e7syh2jbikvl\" path=\"res://assets/creeps/orc/mass/death_W.png\" id=\"5_yl67w\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bd5vg4oke4m70\" path=\"res://assets/creeps/orc/mass/slow_run_E.png\" id=\"6_qfodw\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://jmweiopkc2gm\" path=\"res://assets/creeps/orc/mass/slow_run_N.png\" id=\"7_qf677\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://beanme0cwvawx\" path=\"res://assets/creeps/orc/mass/slow_run_S.png\" id=\"8_gnexk\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c2kjqefq762mo\" path=\"res://assets/creeps/orc/mass/slow_run_W.png\" id=\"9_csqvt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m73in\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gneoq\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3fmbo\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kyjt4\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3dslg\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xvwo8\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xa3pn\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_opumd\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_psy3l\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b8g4a\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d6qec\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8nbw3\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mhw5g\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e5q1h\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r0p7x\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qtjm7\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1v4wh\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ljt3e\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j2ua0\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v0sdy\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y0yix\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w1jvb\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m1cgq\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w76w4\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gv88g\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(0, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3pkt1\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(154, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_twj2x\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(308, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7mau0\"]\natlas = ExtResource(\"2_17xdl\")\nregion = Rect2(462, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fij06\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c1xf6\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4yiiq\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q4pdr\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_avv2d\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7ess3\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8a1yf\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wgo8l\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c2drx\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ekrv\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0vm0o\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0jyex\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_63xv8\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vjgp3\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dfh72\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oieku\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7lvsx\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k46es\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7lfea\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_11qod\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_axff5\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dkpjp\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_igd68\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_txiuo\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u8oku\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(0, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ck8yb\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(142, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rsekj\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(284, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fhitf\"]\natlas = ExtResource(\"3_dl80u\")\nregion = Rect2(426, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wxq51\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q3by6\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pqqkr\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qls6g\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ungx6\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8bayl\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_78ajt\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a3gt8\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f7p1m\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s8jar\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v455i\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aufc1\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_458ti\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hfhy2\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tev5s\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pdmh8\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_awhrx\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_um6vt\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3bv1h\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mt7us\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jjh85\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4uggt\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1rvo2\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lqx4d\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dehxc\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(0, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m1qik\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(143, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vdgaj\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(286, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sqre6\"]\natlas = ExtResource(\"4_vh1bw\")\nregion = Rect2(429, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eq3bs\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rm6y7\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2qyum\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6h0wk\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fnq6n\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7y2se\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pcgg5\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_smpvd\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5iwio\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cvi0m\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xgs8j\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0rha0\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6havg\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yl3wp\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0fvm6\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6gens\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mjyme\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_70liy\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k15nd\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rgoa8\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bxv7b\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o80y6\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w52sr\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c5sd3\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eleac\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(0, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m66gl\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(154, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hikx4\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(308, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k31v5\"]\natlas = ExtResource(\"5_yl67w\")\nregion = Rect2(462, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gitp4\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(0, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q300x\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(105, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dw8wg\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(210, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lbawc\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(315, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jceeu\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(0, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r6it0\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(105, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d82kk\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(210, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vnebx\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(315, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k0nc0\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(0, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fqc3e\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(105, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gdry2\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(210, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t0bty\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(315, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6jgbd\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(0, 279, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_37pjo\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(105, 279, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e0xat\"]\natlas = ExtResource(\"6_qfodw\")\nregion = Rect2(210, 279, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3lme3\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(0, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_msdyp\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(100, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v2210\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(200, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xe5m6\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(300, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ufa5q\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(0, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kj5ta\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(100, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ibh6g\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(200, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rbu0h\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(300, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1yylu\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(0, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8ncnh\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(100, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4cr85\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(200, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wo3ov\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(300, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_craqg\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(0, 303, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8qi45\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(100, 303, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xoxws\"]\natlas = ExtResource(\"7_qf677\")\nregion = Rect2(200, 303, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_36wdt\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(0, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fuau1\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(100, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f77gq\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(200, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wo8mn\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(300, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fodbq\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(0, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_24qrn\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(100, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6haxa\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(200, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bjc8y\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(300, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w7ovi\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(0, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wuvip\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(100, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m17pk\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(200, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rgs4r\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(300, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g0vs3\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(0, 258, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dvyk3\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(100, 258, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bkxis\"]\natlas = ExtResource(\"8_gnexk\")\nregion = Rect2(200, 258, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5jy06\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(0, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h35sv\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(105, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ady3s\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(210, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4hoxm\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(315, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_su8bh\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(0, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x2f0c\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(105, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aiywa\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(210, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1hdtc\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(315, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mn63p\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(0, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vbe7w\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(105, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_npp1b\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(210, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mxbgi\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(315, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bhq43\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(0, 312, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y7f7e\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(105, 312, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1ml05\"]\natlas = ExtResource(\"9_csqvt\")\nregion = Rect2(210, 312, 105, 104)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_4w8re\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m73in\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gneoq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3fmbo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kyjt4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3dslg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xvwo8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xa3pn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_opumd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_psy3l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b8g4a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d6qec\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8nbw3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mhw5g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e5q1h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r0p7x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qtjm7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1v4wh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ljt3e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j2ua0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v0sdy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y0yix\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w1jvb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m1cgq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w76w4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gv88g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3pkt1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_twj2x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7mau0\")\n}],\n\"loop\": true,\n\"name\": &\"death_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fij06\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c1xf6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4yiiq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q4pdr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_avv2d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7ess3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8a1yf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wgo8l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c2drx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ekrv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0vm0o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0jyex\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_63xv8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vjgp3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dfh72\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oieku\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7lvsx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k46es\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7lfea\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_11qod\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_axff5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dkpjp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_igd68\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_txiuo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u8oku\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ck8yb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rsekj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fhitf\")\n}],\n\"loop\": true,\n\"name\": &\"death_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wxq51\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q3by6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pqqkr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qls6g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ungx6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8bayl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_78ajt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a3gt8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f7p1m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s8jar\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v455i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aufc1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_458ti\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hfhy2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tev5s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pdmh8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_awhrx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_um6vt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3bv1h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mt7us\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jjh85\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4uggt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1rvo2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lqx4d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dehxc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m1qik\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vdgaj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sqre6\")\n}],\n\"loop\": true,\n\"name\": &\"death_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eq3bs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rm6y7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2qyum\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6h0wk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fnq6n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7y2se\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pcgg5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_smpvd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5iwio\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cvi0m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xgs8j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0rha0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6havg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yl3wp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0fvm6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6gens\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mjyme\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_70liy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k15nd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rgoa8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bxv7b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o80y6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w52sr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c5sd3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eleac\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m66gl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hikx4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k31v5\")\n}],\n\"loop\": true,\n\"name\": &\"death_W\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gitp4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q300x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dw8wg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lbawc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jceeu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r6it0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d82kk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vnebx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k0nc0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fqc3e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gdry2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t0bty\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6jgbd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_37pjo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e0xat\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3lme3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_msdyp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v2210\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xe5m6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ufa5q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kj5ta\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ibh6g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rbu0h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1yylu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8ncnh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4cr85\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wo3ov\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_craqg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8qi45\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xoxws\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_36wdt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fuau1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f77gq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wo8mn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fodbq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_24qrn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6haxa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bjc8y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w7ovi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wuvip\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m17pk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rgs4r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g0vs3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dvyk3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bkxis\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5jy06\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h35sv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ady3s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4hoxm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_su8bh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x2f0c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aiywa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1hdtc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mn63p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vbe7w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_npp1b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mxbgi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bhq43\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y7f7e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1ml05\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"challenge_mass_creep\" instance=ExtResource(\"1_56x63\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -60)\nsprite_frames = SubResource(\"SpriteFrames_4w8re\")\nanimation = &\"death_E\"\noffset = Vector2(5, 40)\nsprite_sheets_dir = \"res://assets/creeps/orc/mass\"\n_animation_offset_map = {\n\"death_E\": Vector2(5, 40),\n\"death_N\": Vector2(27, 26),\n\"death_S\": Vector2(-27, 36),\n\"death_W\": Vector2(-5, 22),\n\"slow_run_E\": Vector2(-8, 37),\n\"slow_run_N\": Vector2(9, 27),\n\"slow_run_S\": Vector2(-9, 30),\n\"slow_run_W\": Vector2(7, 24)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -100.0\noffset_bottom = -91.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-44, -114, 43, -111, 49, 15, -48, 13)\n"
  },
  {
    "path": "src/creeps/instances/creep.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://cmcahg14hpv5j\"]\n\n[ext_resource type=\"Script\" path=\"res://src/creeps/creep.gd\" id=\"1_pofyw\"]\n[ext_resource type=\"Script\" path=\"res://src/creeps/creep_sprite.gd\" id=\"2_412am\"]\n[ext_resource type=\"Script\" path=\"res://src/creeps/health_bar.gd\" id=\"3_bsm61\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://b5iupqqmqci6d\" path=\"res://resources/theme/health_bar_background.tres\" id=\"3_inlld\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://b3ycwn0t4rl5u\" path=\"res://resources/theme/health_bar_fill.tres\" id=\"4_csbf1\"]\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_xfndm\"]\n\n[node name=\"Creep\" type=\"Node2D\"]\nscript = ExtResource(\"1_pofyw\")\n\n[node name=\"Visual\" type=\"Node2D\" parent=\".\"]\n\n[node name=\"SpriteParent\" type=\"Node2D\" parent=\"Visual\"]\n\n[node name=\"Sprite\" type=\"AnimatedSprite2D\" parent=\"Visual/SpriteParent\"]\nsprite_frames = SubResource(\"SpriteFrames_xfndm\")\nscript = ExtResource(\"2_412am\")\n\n[node name=\"HealthBar\" type=\"ProgressBar\" parent=\"Visual\"]\noffset_left = -50.0\noffset_right = 50.0\noffset_bottom = 9.0\nmouse_filter = 2\ntheme_override_styles/background = ExtResource(\"3_inlld\")\ntheme_override_styles/fill = ExtResource(\"4_csbf1\")\nvalue = 100.0\nshow_percentage = false\nscript = ExtResource(\"3_bsm61\")\ncolor3 = Color(0.176471, 0.960784, 0, 1)\ncolor2 = Color(1, 0.635294, 0.0745098, 1)\ncolor1 = Color(0.698039, 0, 0, 1)\n\n[node name=\"SelectionArea\" type=\"Area2D\" parent=\"Visual\"]\nmonitoring = false\nmonitorable = false\n\n[node name=\"CollisionPolygon2D\" type=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\"]\npolygon = PackedVector2Array(-30, -40, 30, -40, 30, 40, -30, 40)\n\n[connection signal=\"value_changed\" from=\"Visual/HealthBar\" to=\"Visual/HealthBar\" method=\"_on_value_changed\"]\n"
  },
  {
    "path": "src/creeps/instances/orc/orc_air_creep.tscn",
    "content": "[gd_scene load_steps=211 format=3 uid=\"uid://bh1nj3pfum28e\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_7h8wd\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b5se2dom7rt6d\" path=\"res://assets/creeps/orc/air/fly_E.png\" id=\"2_6td5n\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dg22ncv2bbgpl\" path=\"res://assets/creeps/orc/air/fly_N.png\" id=\"3_iooky\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://lhbh8ncpikea\" path=\"res://assets/creeps/orc/air/fly_NE.png\" id=\"4_5ysir\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://m74fw3s6vh5h\" path=\"res://assets/creeps/orc/air/fly_NW.png\" id=\"5_jugra\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ctrob5r1weymb\" path=\"res://assets/creeps/orc/air/fly_S.png\" id=\"6_8y4ke\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dejolx201xt4l\" path=\"res://assets/creeps/orc/air/fly_SE.png\" id=\"7_ix84g\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://beysr35mknwqu\" path=\"res://assets/creeps/orc/air/fly_SW.png\" id=\"8_4ei4t\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ddhb3w0ho041v\" path=\"res://assets/creeps/orc/air/fly_W.png\" id=\"9_mhphx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3lo1d\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 0, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vtk2d\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(104, 0, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oherj\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(208, 0, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c04xl\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(312, 0, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gd73c\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 70, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gckbt\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(104, 70, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j5ak8\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(208, 70, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qqmoe\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(312, 70, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0xjor\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 140, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yoauw\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(104, 140, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wuuwe\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(208, 140, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_huf7b\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(312, 140, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lx62w\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 210, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qr5sy\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(104, 210, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h7pm7\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(208, 210, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1hicj\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(312, 210, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7pr2u\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 280, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wp6dl\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(104, 280, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5tupu\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(208, 280, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yabon\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(312, 280, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hfidh\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 350, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hcqlt\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(104, 350, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1goox\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(208, 350, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uc7n7\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(312, 350, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f44e5\"]\natlas = ExtResource(\"2_6td5n\")\nregion = Rect2(0, 420, 104, 70)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xucvs\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 0, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b7fsp\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(99, 0, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4s4jl\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(198, 0, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aoldw\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(297, 0, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pw8ol\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 87, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8mpam\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(99, 87, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_80g60\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(198, 87, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qrgov\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(297, 87, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r6ukk\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 174, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xhdms\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(99, 174, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3odjo\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(198, 174, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_baf2t\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(297, 174, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_706br\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 261, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k8tdc\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(99, 261, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gd4qf\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(198, 261, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uckwd\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(297, 261, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uy0wr\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 348, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cpltm\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(99, 348, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ur12b\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(198, 348, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rk7ws\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(297, 348, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_le45a\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 435, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dk5v0\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(99, 435, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ij61c\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(198, 435, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ybc83\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(297, 435, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wdb5y\"]\natlas = ExtResource(\"3_iooky\")\nregion = Rect2(0, 522, 99, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6u7te\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 0, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1keu0\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(114, 0, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fcmqp\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(228, 0, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3g0fr\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(342, 0, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ky1ve\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 62, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ggy2w\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(114, 62, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_icvsl\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(228, 62, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jpo38\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(342, 62, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_42pre\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 124, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x6rjn\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(114, 124, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_35f7p\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(228, 124, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7uu6s\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(342, 124, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ifpjg\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 186, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vp1uq\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(114, 186, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ry7nk\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(228, 186, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7lq3p\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(342, 186, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xkmu1\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 248, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t53lv\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(114, 248, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8kbhp\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(228, 248, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sg8ax\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(342, 248, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tqonp\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 310, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qcq43\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(114, 310, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_usajs\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(228, 310, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gaab3\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(342, 310, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bkens\"]\natlas = ExtResource(\"4_5ysir\")\nregion = Rect2(0, 372, 114, 62)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_htpbj\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 0, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d8y2v\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(85, 0, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_np1lp\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(170, 0, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tctrg\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(255, 0, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f7244\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 97, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_60515\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(85, 97, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i3jaf\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(170, 97, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vjxpj\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(255, 97, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f58t1\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 194, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_72btr\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(85, 194, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mnxvp\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(170, 194, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tdaw1\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(255, 194, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_20wg1\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 291, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rm3rv\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(85, 291, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4lfu3\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(170, 291, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1u8ri\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(255, 291, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_juygm\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 388, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f71xu\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(85, 388, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q77wg\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(170, 388, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mdsvh\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(255, 388, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jskdh\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 485, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rq7i6\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(85, 485, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k3po0\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(170, 485, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7ohb3\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(255, 485, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ht43v\"]\natlas = ExtResource(\"5_jugra\")\nregion = Rect2(0, 582, 85, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eo7am\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 0, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sql3o\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(99, 0, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q3772\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(198, 0, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2mpp3\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(297, 0, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gq7hs\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 79, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sw8tu\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(99, 79, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fg428\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(198, 79, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e2lii\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(297, 79, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3agqq\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 158, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rnqp6\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(99, 158, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qf6mn\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(198, 158, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v0bau\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(297, 158, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vwbhw\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 237, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yqab3\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(99, 237, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ib6v2\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(198, 237, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uhtoj\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(297, 237, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y8h0p\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 316, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_05pue\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(99, 316, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pgisp\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(198, 316, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8von1\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(297, 316, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i72yd\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 395, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mc0x1\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(99, 395, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e8usb\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(198, 395, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_csvtm\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(297, 395, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4wtu5\"]\natlas = ExtResource(\"6_8y4ke\")\nregion = Rect2(0, 474, 99, 79)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ab3hf\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 0, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jy8ev\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(85, 0, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u4yre\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(170, 0, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rb02e\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(255, 0, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_noyxo\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 85, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c6x2k\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(85, 85, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ph8gf\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(170, 85, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s5ivg\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(255, 85, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_po03d\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 170, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uhec6\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(85, 170, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g6eh2\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(170, 170, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dhhsu\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(255, 170, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v3jy8\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 255, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4nbtl\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(85, 255, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o50jj\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(170, 255, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_07eq2\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(255, 255, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hl7l4\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 340, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mxu6c\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(85, 340, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hi6lk\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(170, 340, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v1v8q\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(255, 340, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_61l86\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 425, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5wkbo\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(85, 425, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wn2s3\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(170, 425, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fdhwr\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(255, 425, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ulptl\"]\natlas = ExtResource(\"7_ix84g\")\nregion = Rect2(0, 510, 85, 85)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nvwp5\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 0, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f3g1i\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(114, 0, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xe5fl\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(228, 0, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i651i\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(342, 0, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yqlki\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 66, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gbsot\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(114, 66, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2dhxm\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(228, 66, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wwgyx\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(342, 66, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8kfbv\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 132, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kt4py\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(114, 132, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8mksm\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(228, 132, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e1ttb\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(342, 132, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yak7k\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 198, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pirr5\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(114, 198, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t4o3o\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(228, 198, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r6hnw\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(342, 198, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xir08\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 264, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pv3qo\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(114, 264, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hbee7\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(228, 264, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_etdp8\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(342, 264, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x3xdr\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 330, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jh4mh\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(114, 330, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bbvhq\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(228, 330, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ipxe7\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(342, 330, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_igdm0\"]\natlas = ExtResource(\"8_4ei4t\")\nregion = Rect2(0, 396, 114, 66)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1mk4t\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 0, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ini8u\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(104, 0, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_454tu\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(208, 0, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4en8j\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(312, 0, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i844e\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 87, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hyc6p\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(104, 87, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w0bo7\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(208, 87, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4dpuk\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(312, 87, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_txe0r\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 174, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8td7s\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(104, 174, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w2a5h\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(208, 174, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hkbiw\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(312, 174, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tccrp\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 261, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m7o78\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(104, 261, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8qjeu\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(208, 261, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4rapw\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(312, 261, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rnk55\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 348, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7gl1y\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(104, 348, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h303i\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(208, 348, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2q0ev\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(312, 348, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ut2kh\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 435, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6t4hv\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(104, 435, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bpcf3\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(208, 435, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kvn8d\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(312, 435, 104, 87)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2taid\"]\natlas = ExtResource(\"9_mhphx\")\nregion = Rect2(0, 522, 104, 87)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ldbg0\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3lo1d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vtk2d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oherj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c04xl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gd73c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gckbt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j5ak8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qqmoe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0xjor\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yoauw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wuuwe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_huf7b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lx62w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qr5sy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h7pm7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1hicj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7pr2u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wp6dl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5tupu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yabon\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hfidh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hcqlt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1goox\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uc7n7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f44e5\")\n}],\n\"loop\": true,\n\"name\": &\"fly_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xucvs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b7fsp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4s4jl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aoldw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pw8ol\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8mpam\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_80g60\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qrgov\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r6ukk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xhdms\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3odjo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_baf2t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_706br\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k8tdc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gd4qf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uckwd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uy0wr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cpltm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ur12b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rk7ws\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_le45a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dk5v0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ij61c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ybc83\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wdb5y\")\n}],\n\"loop\": true,\n\"name\": &\"fly_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6u7te\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1keu0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fcmqp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3g0fr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ky1ve\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ggy2w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_icvsl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jpo38\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_42pre\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x6rjn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_35f7p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7uu6s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ifpjg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vp1uq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ry7nk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7lq3p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xkmu1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t53lv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8kbhp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sg8ax\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tqonp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qcq43\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_usajs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gaab3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bkens\")\n}],\n\"loop\": true,\n\"name\": &\"fly_NE\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_htpbj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d8y2v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_np1lp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tctrg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f7244\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_60515\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i3jaf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vjxpj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f58t1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_72btr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mnxvp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tdaw1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_20wg1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rm3rv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4lfu3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1u8ri\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_juygm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f71xu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q77wg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mdsvh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jskdh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rq7i6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k3po0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7ohb3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ht43v\")\n}],\n\"loop\": true,\n\"name\": &\"fly_NW\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eo7am\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sql3o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q3772\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2mpp3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gq7hs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sw8tu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fg428\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e2lii\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3agqq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rnqp6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qf6mn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v0bau\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vwbhw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yqab3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ib6v2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uhtoj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y8h0p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_05pue\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pgisp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8von1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i72yd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mc0x1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e8usb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_csvtm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4wtu5\")\n}],\n\"loop\": true,\n\"name\": &\"fly_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ab3hf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jy8ev\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u4yre\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rb02e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_noyxo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c6x2k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ph8gf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s5ivg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_po03d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uhec6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g6eh2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dhhsu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v3jy8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4nbtl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o50jj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_07eq2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hl7l4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mxu6c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hi6lk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v1v8q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_61l86\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5wkbo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wn2s3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fdhwr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ulptl\")\n}],\n\"loop\": true,\n\"name\": &\"fly_SE\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nvwp5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f3g1i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xe5fl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i651i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yqlki\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gbsot\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2dhxm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wwgyx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8kfbv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kt4py\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8mksm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e1ttb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yak7k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pirr5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t4o3o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r6hnw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xir08\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pv3qo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hbee7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_etdp8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x3xdr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jh4mh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bbvhq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ipxe7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_igdm0\")\n}],\n\"loop\": true,\n\"name\": &\"fly_SW\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1mk4t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ini8u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_454tu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4en8j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i844e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hyc6p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w0bo7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4dpuk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_txe0r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8td7s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w2a5h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hkbiw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tccrp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m7o78\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8qjeu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4rapw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rnk55\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7gl1y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h303i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2q0ev\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ut2kh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6t4hv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bpcf3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kvn8d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2taid\")\n}],\n\"loop\": true,\n\"name\": &\"fly_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"orc_air_creep\" instance=ExtResource(\"1_7h8wd\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -20)\nscale = Vector2(1.6, 1.6)\nsprite_frames = SubResource(\"SpriteFrames_ldbg0\")\nanimation = &\"fly_E\"\noffset = Vector2(3.125, 16.25)\nsprite_sheets_dir = \"res://assets/creeps/orc/air\"\n_animation_offset_map = {\n\"fly_E\": Vector2(5, 26),\n\"fly_N\": Vector2(4, 25),\n\"fly_NE\": Vector2(14, 28),\n\"fly_NW\": Vector2(-2, 23),\n\"fly_S\": Vector2(-5, 31),\n\"fly_SE\": Vector2(1, 32),\n\"fly_SW\": Vector2(-14, 30),\n\"fly_W\": Vector2(-5, 25)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -50.0\noffset_bottom = -41.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-99, -62, 109, -51, 108, 69, -103, 65)\n"
  },
  {
    "path": "src/creeps/instances/orc/orc_boss_creep.tscn",
    "content": "[gd_scene load_steps=171 format=3 uid=\"uid://cyu23qhnt2nk1\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_pwrh8\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b1s341ilp1g0f\" path=\"res://assets/creeps/orc/boss/death_E.png\" id=\"2_y0g0k\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://kyq50l132wm1\" path=\"res://assets/creeps/orc/boss/death_N.png\" id=\"3_g0pwo\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cmytlwkuq6i8q\" path=\"res://assets/creeps/orc/boss/death_S.png\" id=\"4_yprvm\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://pulp58p3vflw\" path=\"res://assets/creeps/orc/boss/death_W.png\" id=\"5_hsre7\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c4mbacosga5se\" path=\"res://assets/creeps/orc/boss/slow_run_E.png\" id=\"6_ovvoh\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dcrmib66n1i1k\" path=\"res://assets/creeps/orc/boss/slow_run_N.png\" id=\"7_4atdi\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://be8at5qd2xtfm\" path=\"res://assets/creeps/orc/boss/slow_run_S.png\" id=\"8_jxc3g\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bf8mfmg7jkmv7\" path=\"res://assets/creeps/orc/boss/slow_run_W.png\" id=\"9_3d7uj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cskc0\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wupi4\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6hoqb\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5h8cs\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 0, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0rnlm\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_trvwj\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k2ocs\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xww76\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 185, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_erp68\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yg73x\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_537vc\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5u23m\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 370, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nvqd0\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xy67m\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5kd0a\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bq7py\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 555, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1fdk8\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vglqm\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4pgmg\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_48a3t\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 740, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1nt6y\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rrwqe\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ynrwv\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_76c8w\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 925, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cfwdj\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(0, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_og2ga\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(204, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_48anh\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(408, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lg5ep\"]\natlas = ExtResource(\"2_y0g0k\")\nregion = Rect2(612, 1110, 204, 185)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fwvq1\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i57fi\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_udx3v\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ckjno\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 0, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fd413\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dm1f7\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_myg07\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pv3eu\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 137, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jo8el\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xueq5\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qays3\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bk4yn\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 274, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ljout\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0v7ku\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tmnst\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y5iw1\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 411, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0hio5\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0q1f0\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8jm3p\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aw17h\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 548, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1nfs3\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_66rrh\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r6ucn\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_21rgx\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 685, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hl6xt\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(0, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ew5yf\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(182, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrlgo\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(364, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_inqqf\"]\natlas = ExtResource(\"3_g0pwo\")\nregion = Rect2(546, 822, 182, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5nod8\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_28a41\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iv6th\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3nune\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 0, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qchcr\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3dqvj\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ch6iw\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4avtw\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 165, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ybyeu\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yg2h0\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hxuok\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tqxfu\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 330, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yxuh3\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fx4mr\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0p62u\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2lhgf\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 495, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_32xnn\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q6ev8\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1kajw\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pgxr4\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 660, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fm6mi\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nsqqw\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xdn4n\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k6yld\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 825, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dx1yl\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(0, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o8d6m\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(182, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o537e\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(364, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ypco2\"]\natlas = ExtResource(\"4_yprvm\")\nregion = Rect2(546, 990, 182, 165)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a8aee\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_breii\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_flupp\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eii84\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 0, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m5m1i\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yka0w\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7a78r\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ynht\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 125, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rkb42\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_25yxw\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g4dyb\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hae5n\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 250, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jvck6\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a0fjs\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8l2cq\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bhwia\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 375, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d26fu\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5jk7h\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_smkxw\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qhvxq\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 500, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q0x1q\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qpxa8\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3a7af\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ara2e\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 625, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uvw6f\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(0, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rqakt\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(204, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0jy1g\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(408, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nw3aa\"]\natlas = ExtResource(\"5_hsre7\")\nregion = Rect2(612, 750, 204, 125)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r0bom\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(0, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2gj0a\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(121, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ixh6s\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(242, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bbci1\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(363, 0, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5jayy\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(0, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i01k2\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(121, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a6pnf\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(242, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cfmf6\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(363, 126, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3e8na\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(0, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hn43e\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(121, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vkret\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(242, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mev3t\"]\natlas = ExtResource(\"6_ovvoh\")\nregion = Rect2(363, 252, 121, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ubiw\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(0, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_blk4r\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(118, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ys8sv\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(236, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yr3ir\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(354, 0, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8dfvn\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(0, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n477h\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(118, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mp35f\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(236, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6fsyd\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(354, 137, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p1rvi\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(0, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pw77b\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(118, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e2fk7\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(236, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gqf3i\"]\natlas = ExtResource(\"7_4atdi\")\nregion = Rect2(354, 274, 118, 137)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gerqi\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(0, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k022c\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(118, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vn7om\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(236, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s83f5\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(354, 0, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sg6fr\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(0, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x5ksp\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(118, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bw41t\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(236, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k7j1y\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(354, 121, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kp5hs\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(0, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vojvc\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(118, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_swipi\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(236, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_epoep\"]\natlas = ExtResource(\"8_jxc3g\")\nregion = Rect2(354, 242, 118, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2fqtl\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(0, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ap2v\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(121, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mosy0\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(242, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ju5gl\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(363, 0, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_httxr\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(0, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sf71p\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(121, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ephlx\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(242, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ckwwi\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(363, 135, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w7fso\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(0, 270, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_japji\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(121, 270, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f36qu\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(242, 270, 121, 135)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m0tei\"]\natlas = ExtResource(\"9_3d7uj\")\nregion = Rect2(363, 270, 121, 135)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_h3g4d\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cskc0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wupi4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6hoqb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5h8cs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0rnlm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_trvwj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k2ocs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xww76\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_erp68\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yg73x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_537vc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5u23m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nvqd0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xy67m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5kd0a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bq7py\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1fdk8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vglqm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4pgmg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_48a3t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1nt6y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rrwqe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ynrwv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_76c8w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cfwdj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_og2ga\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_48anh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lg5ep\")\n}],\n\"loop\": true,\n\"name\": &\"death_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fwvq1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i57fi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_udx3v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ckjno\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fd413\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dm1f7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_myg07\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pv3eu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jo8el\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xueq5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qays3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bk4yn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ljout\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0v7ku\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tmnst\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y5iw1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0hio5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0q1f0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8jm3p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aw17h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1nfs3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_66rrh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r6ucn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_21rgx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hl6xt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ew5yf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lrlgo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_inqqf\")\n}],\n\"loop\": true,\n\"name\": &\"death_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5nod8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_28a41\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iv6th\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3nune\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qchcr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3dqvj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ch6iw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4avtw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ybyeu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yg2h0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hxuok\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tqxfu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yxuh3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fx4mr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0p62u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2lhgf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_32xnn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q6ev8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1kajw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pgxr4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fm6mi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nsqqw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xdn4n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k6yld\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dx1yl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o8d6m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o537e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ypco2\")\n}],\n\"loop\": true,\n\"name\": &\"death_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a8aee\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_breii\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_flupp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eii84\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m5m1i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yka0w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7a78r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ynht\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rkb42\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_25yxw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g4dyb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hae5n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jvck6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a0fjs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8l2cq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bhwia\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d26fu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5jk7h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_smkxw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qhvxq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q0x1q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qpxa8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3a7af\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ara2e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uvw6f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rqakt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0jy1g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nw3aa\")\n}],\n\"loop\": true,\n\"name\": &\"death_W\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r0bom\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2gj0a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ixh6s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bbci1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5jayy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i01k2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a6pnf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cfmf6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3e8na\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hn43e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vkret\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mev3t\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ubiw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_blk4r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ys8sv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yr3ir\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8dfvn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n477h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mp35f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6fsyd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p1rvi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pw77b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e2fk7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gqf3i\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gerqi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k022c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vn7om\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s83f5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sg6fr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x5ksp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bw41t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k7j1y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kp5hs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vojvc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_swipi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_epoep\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2fqtl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3ap2v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mosy0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ju5gl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_httxr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sf71p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ephlx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ckwwi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w7fso\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_japji\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f36qu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m0tei\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"orc_boss_creep\" instance=ExtResource(\"1_pwrh8\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -120)\nscale = Vector2(2.5, 2.5)\nsprite_frames = SubResource(\"SpriteFrames_h3g4d\")\nanimation = &\"death_E\"\noffset = Vector2(0.8, 12.8)\nsprite_sheets_dir = \"res://assets/creeps/orc/boss\"\n_animation_offset_map = {\n\"death_E\": Vector2(2, 32),\n\"death_N\": Vector2(27, 16),\n\"death_S\": Vector2(-27, 31),\n\"death_W\": Vector2(-2, 7),\n\"slow_run_E\": Vector2(10, 14),\n\"slow_run_N\": Vector2(25, 16),\n\"slow_run_S\": Vector2(-25, 15),\n\"slow_run_W\": Vector2(-11, 8)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -250.0\noffset_bottom = -241.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-111, -230, 111, -230, 71, 25, -78, 19)\n"
  },
  {
    "path": "src/creeps/instances/orc/orc_champion_creep.tscn",
    "content": "[gd_scene load_steps=167 format=3 uid=\"uid://brrlcocd22tsp\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_e7002\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://hdtvoqf7jppc\" path=\"res://assets/creeps/orc/champion/death_E.png\" id=\"2_2eoq8\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bt0fnps8to5c5\" path=\"res://assets/creeps/orc/champion/death_N.png\" id=\"3_ve1vs\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bn3cfvfeop2ni\" path=\"res://assets/creeps/orc/champion/death_S.png\" id=\"4_0iyvj\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dvwut2d2wdqo3\" path=\"res://assets/creeps/orc/champion/death_W.png\" id=\"5_oeni5\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ch7gt4062eyrj\" path=\"res://assets/creeps/orc/champion/slow_run_E.png\" id=\"6_gox7a\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dxvx01jjvjcye\" path=\"res://assets/creeps/orc/champion/slow_run_N.png\" id=\"7_550yc\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://d4cer5fkla46y\" path=\"res://assets/creeps/orc/champion/slow_run_S.png\" id=\"8_7okpo\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bvaegexu3foek\" path=\"res://assets/creeps/orc/champion/slow_run_W.png\" id=\"9_oid0y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gne3q\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 0, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ljvcx\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 0, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u70o3\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 0, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q2208\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 0, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eoiuo\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 174, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ttpcf\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 174, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t8tyh\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 174, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3u460\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 174, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tkyux\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 348, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a1wr5\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 348, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_324el\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 348, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rqyo6\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 348, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6sasb\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 522, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fyy8g\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 522, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sy0y1\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 522, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lj7an\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 522, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_faun0\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 696, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0ytbl\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 696, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gtkfk\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 696, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1ygfn\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 696, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_obcq4\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 870, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_76iij\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 870, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ogbca\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 870, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tuxvg\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 870, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ci77i\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(0, 1044, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2be0s\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(178, 1044, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lqyy2\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(356, 1044, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fvfvs\"]\natlas = ExtResource(\"2_2eoq8\")\nregion = Rect2(534, 1044, 178, 174)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gia6k\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 0, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vi1ma\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 0, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rwl1f\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 0, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eg2o2\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 0, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8l6vi\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 130, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o0iiy\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 130, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mtmvn\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 130, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qck7v\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 130, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e08eb\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 260, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_58e3p\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 260, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5vcqh\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 260, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r46ac\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 260, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8s00o\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 390, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7gm51\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 390, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wudct\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 390, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1im0y\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 390, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7udwp\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 520, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jijhu\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 520, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xyjgy\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 520, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bm8ep\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 520, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7q1ay\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 650, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qxkpt\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 650, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_okpc0\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 650, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0vjhe\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 650, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ivofi\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(0, 780, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vefrk\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(182, 780, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3x7lv\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(364, 780, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7da05\"]\natlas = ExtResource(\"3_ve1vs\")\nregion = Rect2(546, 780, 182, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rofmt\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 0, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7k2wa\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 0, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_up74v\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 0, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b4yrt\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 0, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g5cs5\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 184, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xs3ks\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 184, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_evclp\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 184, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jm71u\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 184, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_63ted\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 368, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vhif0\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 368, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2f105\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 368, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6biln\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 368, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ce12\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 552, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aqx6p\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 552, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rxy6y\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 552, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k64j6\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 552, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j0ib1\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 736, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6hmlq\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 736, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_phdjt\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 736, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oe2bp\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 736, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bvmg8\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 920, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6fcj1\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 920, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h03hc\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 920, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_73yuo\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 920, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kyonr\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(0, 1104, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q8oo4\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(182, 1104, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cenox\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(364, 1104, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vqxc2\"]\natlas = ExtResource(\"4_0iyvj\")\nregion = Rect2(546, 1104, 182, 184)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dr4um\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 0, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ttaj2\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 0, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fkk0u\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 0, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6auud\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 0, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cglm1\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 113, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1tcat\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 113, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_44var\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 113, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_86y8d\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 113, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voi0h\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 226, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dygok\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 226, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_opj51\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 226, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sw78q\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 226, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_56ath\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 339, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ltc2y\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 339, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fi47w\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 339, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2c3c2\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 339, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_unjat\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 452, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kt6xk\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 452, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wy4xj\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 452, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ybw75\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 452, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xojon\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 565, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vpqqm\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 565, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fhhik\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 565, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3h74o\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 565, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dus3x\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(0, 678, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7s7dg\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(179, 678, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7vp2t\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(358, 678, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7fhbr\"]\natlas = ExtResource(\"5_oeni5\")\nregion = Rect2(537, 678, 179, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rnnbx\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(0, 0, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x7mi6\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(78, 0, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xms8h\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(156, 0, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xnmrv\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(234, 0, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_733cm\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(0, 97, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pjcmt\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(78, 97, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3apgs\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(156, 97, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2gu1x\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(234, 97, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vx73k\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(0, 194, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i17l8\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(78, 194, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nvbh1\"]\natlas = ExtResource(\"6_gox7a\")\nregion = Rect2(156, 194, 78, 97)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_axsn1\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(0, 0, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_33qun\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(113, 0, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nkm1v\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(226, 0, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hkhpm\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(339, 0, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_asg7g\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(0, 113, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8gfjb\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(113, 113, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fw466\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(226, 113, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qki8c\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(339, 113, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sbsu6\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(0, 226, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ibh1d\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(113, 226, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5e7lj\"]\natlas = ExtResource(\"7_550yc\")\nregion = Rect2(226, 226, 113, 113)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eaick\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(0, 0, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eeb53\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(113, 0, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_be7ix\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(226, 0, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt0g\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(339, 0, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eslci\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(0, 93, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uoec4\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(113, 93, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ga5ku\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(226, 93, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_025nr\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(339, 93, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8mgfx\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(0, 186, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e6jug\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(113, 186, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x7pvd\"]\natlas = ExtResource(\"8_7okpo\")\nregion = Rect2(226, 186, 113, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_74fqx\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(0, 0, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ovty\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(78, 0, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pk4ck\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(156, 0, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cgmbq\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(234, 0, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gdd7x\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(0, 126, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s5a4w\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(78, 126, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ik4nc\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(156, 126, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_juh1w\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(234, 126, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b8jcn\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(0, 252, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pkpcd\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(78, 252, 78, 126)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4toba\"]\natlas = ExtResource(\"9_oid0y\")\nregion = Rect2(156, 252, 78, 126)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ew3n8\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gne3q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ljvcx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u70o3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q2208\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eoiuo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ttpcf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t8tyh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3u460\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tkyux\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a1wr5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_324el\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rqyo6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6sasb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fyy8g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sy0y1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lj7an\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_faun0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0ytbl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gtkfk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1ygfn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_obcq4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_76iij\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ogbca\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tuxvg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ci77i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2be0s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lqyy2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fvfvs\")\n}],\n\"loop\": true,\n\"name\": &\"death_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gia6k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vi1ma\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rwl1f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eg2o2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8l6vi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o0iiy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mtmvn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qck7v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e08eb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_58e3p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5vcqh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r46ac\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8s00o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7gm51\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wudct\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1im0y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7udwp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jijhu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xyjgy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bm8ep\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7q1ay\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qxkpt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_okpc0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0vjhe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ivofi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vefrk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3x7lv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7da05\")\n}],\n\"loop\": true,\n\"name\": &\"death_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rofmt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7k2wa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_up74v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b4yrt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g5cs5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xs3ks\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_evclp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jm71u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_63ted\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vhif0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2f105\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6biln\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ce12\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aqx6p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rxy6y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k64j6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j0ib1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6hmlq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_phdjt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oe2bp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bvmg8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6fcj1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h03hc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_73yuo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kyonr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q8oo4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cenox\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vqxc2\")\n}],\n\"loop\": true,\n\"name\": &\"death_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dr4um\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ttaj2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fkk0u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6auud\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cglm1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1tcat\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_44var\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_86y8d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_voi0h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dygok\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_opj51\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sw78q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_56ath\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ltc2y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fi47w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2c3c2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_unjat\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kt6xk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wy4xj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ybw75\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xojon\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vpqqm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fhhik\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3h74o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dus3x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7s7dg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7vp2t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7fhbr\")\n}],\n\"loop\": true,\n\"name\": &\"death_W\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rnnbx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x7mi6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xms8h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xnmrv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_733cm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pjcmt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3apgs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2gu1x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vx73k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i17l8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nvbh1\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_axsn1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_33qun\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nkm1v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hkhpm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_asg7g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8gfjb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fw466\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qki8c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sbsu6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ibh1d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5e7lj\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eaick\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eeb53\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_be7ix\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lrt0g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eslci\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uoec4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ga5ku\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_025nr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8mgfx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e6jug\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x7pvd\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_74fqx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3ovty\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pk4ck\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cgmbq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gdd7x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s5a4w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ik4nc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_juh1w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b8jcn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pkpcd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4toba\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"orc_champion_creep\" instance=ExtResource(\"1_e7002\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -90)\nscale = Vector2(1.8, 1.8)\nsprite_frames = SubResource(\"SpriteFrames_ew3n8\")\nanimation = &\"death_E\"\noffset = Vector2(4.44444, 19.4444)\nsprite_sheets_dir = \"res://assets/creeps/orc/champion\"\n_animation_offset_map = {\n\"death_E\": Vector2(8, 35),\n\"death_N\": Vector2(29, 26),\n\"death_S\": Vector2(-29, 33),\n\"death_W\": Vector2(-9, 14),\n\"slow_run_E\": Vector2(9, 27),\n\"slow_run_N\": Vector2(28, 18),\n\"slow_run_S\": Vector2(-29, 27),\n\"slow_run_W\": Vector2(-9, 13)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -140.0\noffset_bottom = -131.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-82, -154, 79, -161, 48, 13, -56, 14)\n"
  },
  {
    "path": "src/creeps/instances/orc/orc_mass_creep.tscn",
    "content": "[gd_scene load_steps=183 format=3 uid=\"uid://cntnl5vc2q4tk\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_dsks8\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c031gwyl83vsh\" path=\"res://assets/creeps/orc/mass/death_E.png\" id=\"2_0k14c\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://byqwfls7534ta\" path=\"res://assets/creeps/orc/mass/death_N.png\" id=\"3_8s8x7\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dc3ghqhhglmqi\" path=\"res://assets/creeps/orc/mass/death_S.png\" id=\"4_i7rbf\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://e7syh2jbikvl\" path=\"res://assets/creeps/orc/mass/death_W.png\" id=\"5_yoyk6\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bd5vg4oke4m70\" path=\"res://assets/creeps/orc/mass/slow_run_E.png\" id=\"6_ixk0m\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://jmweiopkc2gm\" path=\"res://assets/creeps/orc/mass/slow_run_N.png\" id=\"7_i5ntd\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://beanme0cwvawx\" path=\"res://assets/creeps/orc/mass/slow_run_S.png\" id=\"8_ktlcq\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c2kjqefq762mo\" path=\"res://assets/creeps/orc/mass/slow_run_W.png\" id=\"9_i1emj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m4poa\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3bn8m\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nn510\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d8hae\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 0, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ap6am\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_41o1t\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xws11\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a8cda\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 155, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m281i\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mugrh\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0oejv\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jy7cv\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 310, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kn41x\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7fu2b\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mn8gk\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nxxpr\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 465, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e868s\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1lm2j\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ix07f\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cr33x\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 620, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h03of\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8qrxa\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e20g1\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vmreo\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 775, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1pya4\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(0, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ptkll\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(154, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ebktr\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(308, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d8ajq\"]\natlas = ExtResource(\"2_0k14c\")\nregion = Rect2(462, 930, 154, 155)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ey01u\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_55jeb\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_873h4\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cay2s\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 0, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eerbk\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_or31t\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2yrid\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xlx76\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 102, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t53dm\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oidof\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f2ann\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ugbxe\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 204, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tg8uh\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vyfac\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xfl65\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8evn7\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 306, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a2gvl\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_72kko\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_54jla\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ttq4e\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 408, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ccv8\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jebof\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qimd1\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pbqm4\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 510, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nw46e\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(0, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l5bux\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(142, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_haxo2\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(284, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gb7ob\"]\natlas = ExtResource(\"3_8s8x7\")\nregion = Rect2(426, 612, 142, 102)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j8r16\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_07txe\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v2867\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_75v0d\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 0, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v7pna\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qrsbk\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4kvpr\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xqm0j\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 156, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f0ipm\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gffk1\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j8n45\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yhmv7\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 312, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0gspi\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d4su4\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ypyak\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_101fd\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 468, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j757c\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_46pke\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s8fcd\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iitt2\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 624, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p7kun\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7ebep\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m2lpo\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oak4u\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 780, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r8n2p\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(0, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l6p80\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(143, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ir5x5\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(286, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dvhgv\"]\natlas = ExtResource(\"4_i7rbf\")\nregion = Rect2(429, 936, 143, 156)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8y8mq\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1mtcu\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0q5im\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_npw7o\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 0, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qggtc\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wjwbx\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t511q\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ybbsr\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 96, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d6njt\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8xg5s\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6xrv8\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v4sd3\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 192, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u6c7i\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_few0i\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4pyh8\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b5718\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 288, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vvpj7\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0rvsu\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h0mmh\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wv33v\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 384, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_65sy7\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ktxas\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_70fji\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pqoyt\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 480, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_002g3\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(0, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u8yhr\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(154, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hv57j\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(308, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nmxi4\"]\natlas = ExtResource(\"5_yoyk6\")\nregion = Rect2(462, 576, 154, 96)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vir34\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(0, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ohblr\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(105, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vb618\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(210, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_og8a1\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(315, 0, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_13ukr\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(0, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ucgcw\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(105, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kqmr7\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(210, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_llmai\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(315, 93, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4if0i\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(0, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w2j10\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(105, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_du5l6\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(210, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n8dje\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(315, 186, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vdrs7\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(0, 279, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6go0k\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(105, 279, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_78yal\"]\natlas = ExtResource(\"6_ixk0m\")\nregion = Rect2(210, 279, 105, 93)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qvap4\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(0, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aold4\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(100, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q7nnb\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(200, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j4204\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(300, 0, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2sk3g\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(0, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q1yaq\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(100, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a1o36\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(200, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xp2ls\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(300, 101, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a75tt\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(0, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_smxgd\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(100, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hnju2\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(200, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_04rsh\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(300, 202, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_boiu7\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(0, 303, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w6rle\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(100, 303, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wq4lr\"]\natlas = ExtResource(\"7_i5ntd\")\nregion = Rect2(200, 303, 100, 101)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7v273\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(0, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i58s3\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(100, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7bpaf\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(200, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ytc17\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(300, 0, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m83fi\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(0, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2m8mg\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(100, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ha5f\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(200, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y48lo\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(300, 86, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lxjj7\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(0, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ku27o\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(100, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jnq7c\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(200, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y8tkc\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(300, 172, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tfrrl\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(0, 258, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1qffg\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(100, 258, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vrujt\"]\natlas = ExtResource(\"8_ktlcq\")\nregion = Rect2(200, 258, 100, 86)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_id7vd\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(0, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_joqha\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(105, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ruv28\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(210, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_biu3n\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(315, 0, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xjnpc\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(0, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tdfdo\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(105, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vpnpr\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(210, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g0y2t\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(315, 104, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5fp22\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(0, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eh2se\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(105, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6cxah\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(210, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ywg1n\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(315, 208, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_245bj\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(0, 312, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ddo4\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(105, 312, 105, 104)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ts4mh\"]\natlas = ExtResource(\"9_i1emj\")\nregion = Rect2(210, 312, 105, 104)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_7574l\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m4poa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3bn8m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nn510\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d8hae\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ap6am\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_41o1t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xws11\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a8cda\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m281i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mugrh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0oejv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jy7cv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kn41x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7fu2b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mn8gk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nxxpr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e868s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1lm2j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ix07f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cr33x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h03of\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8qrxa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e20g1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vmreo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1pya4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ptkll\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ebktr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d8ajq\")\n}],\n\"loop\": true,\n\"name\": &\"death_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ey01u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_55jeb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_873h4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cay2s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eerbk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_or31t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2yrid\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xlx76\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t53dm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oidof\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f2ann\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ugbxe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tg8uh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vyfac\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xfl65\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8evn7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a2gvl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_72kko\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_54jla\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ttq4e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ccv8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jebof\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qimd1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pbqm4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nw46e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l5bux\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_haxo2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gb7ob\")\n}],\n\"loop\": true,\n\"name\": &\"death_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j8r16\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_07txe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v2867\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_75v0d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v7pna\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qrsbk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4kvpr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xqm0j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f0ipm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gffk1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j8n45\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yhmv7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0gspi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d4su4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ypyak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_101fd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j757c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_46pke\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s8fcd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iitt2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p7kun\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7ebep\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m2lpo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oak4u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r8n2p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l6p80\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ir5x5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dvhgv\")\n}],\n\"loop\": true,\n\"name\": &\"death_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8y8mq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1mtcu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0q5im\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_npw7o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qggtc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wjwbx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t511q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ybbsr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d6njt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8xg5s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6xrv8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v4sd3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u6c7i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_few0i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4pyh8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b5718\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vvpj7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0rvsu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h0mmh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wv33v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_65sy7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ktxas\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_70fji\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pqoyt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_002g3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u8yhr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hv57j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nmxi4\")\n}],\n\"loop\": true,\n\"name\": &\"death_W\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vir34\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ohblr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vb618\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_og8a1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_13ukr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ucgcw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kqmr7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_llmai\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4if0i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w2j10\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_du5l6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n8dje\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vdrs7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6go0k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_78yal\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qvap4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aold4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q7nnb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j4204\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2sk3g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q1yaq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a1o36\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xp2ls\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a75tt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_smxgd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hnju2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_04rsh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_boiu7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w6rle\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wq4lr\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7v273\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i58s3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7bpaf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ytc17\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m83fi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2m8mg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ha5f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y48lo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lxjj7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ku27o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jnq7c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y8tkc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tfrrl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1qffg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vrujt\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_id7vd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_joqha\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ruv28\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_biu3n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xjnpc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tdfdo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vpnpr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g0y2t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5fp22\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eh2se\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6cxah\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ywg1n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_245bj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3ddo4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ts4mh\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"orc_mass_creep\" instance=ExtResource(\"1_dsks8\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -60)\nsprite_frames = SubResource(\"SpriteFrames_7574l\")\nanimation = &\"death_E\"\noffset = Vector2(5, 40)\nsprite_sheets_dir = \"res://assets/creeps/orc/mass\"\n_animation_offset_map = {\n\"death_E\": Vector2(5, 40),\n\"death_N\": Vector2(27, 26),\n\"death_S\": Vector2(-27, 36),\n\"death_W\": Vector2(-5, 22),\n\"slow_run_E\": Vector2(-8, 37),\n\"slow_run_N\": Vector2(9, 27),\n\"slow_run_S\": Vector2(-9, 30),\n\"slow_run_W\": Vector2(7, 24)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -100.0\noffset_bottom = -91.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-44, -114, 43, -111, 49, 15, -48, 13)\n"
  },
  {
    "path": "src/creeps/instances/orc/orc_normal_creep.tscn",
    "content": "[gd_scene load_steps=167 format=3 uid=\"uid://djkjsywbrlcmo\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cmcahg14hpv5j\" path=\"res://src/creeps/instances/creep.tscn\" id=\"1_yb17k\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://3fls0dd5msho\" path=\"res://assets/creeps/orc/normal/death_E.png\" id=\"2_lwtan\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ceyrhdt7hrlvb\" path=\"res://assets/creeps/orc/normal/death_N.png\" id=\"3_ls6cr\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ca3nyf1hqvlca\" path=\"res://assets/creeps/orc/normal/death_S.png\" id=\"4_e3n44\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://nh8ulueomejj\" path=\"res://assets/creeps/orc/normal/death_W.png\" id=\"5_hukkq\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dby3igs0d3hvn\" path=\"res://assets/creeps/orc/normal/slow_run_E.png\" id=\"6_l05kn\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bns6kclfij3yy\" path=\"res://assets/creeps/orc/normal/slow_run_N.png\" id=\"7_fyb51\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bshgy2yv32i6a\" path=\"res://assets/creeps/orc/normal/slow_run_S.png\" id=\"8_lonxs\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://5hpj51wwf21h\" path=\"res://assets/creeps/orc/normal/slow_run_W.png\" id=\"9_l7nwh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ll3xp\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 0, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8141i\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 0, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kwfj1\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 0, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ce6s6\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 0, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hk51e\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 167, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_855di\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 167, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jx5sb\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 167, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cetqq\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 167, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g50xn\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 334, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_odk4u\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 334, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k8ggi\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 334, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2fd3p\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 334, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gj5a4\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 501, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l77l8\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 501, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wtbm6\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 501, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vbnac\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 501, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1qji2\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 668, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1k7xe\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 668, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ld1et\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 668, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rsrmk\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 668, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_trnly\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 835, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qvr68\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 835, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ij8j5\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 835, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u87g2\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 835, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xy7wo\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(0, 1002, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h6bmp\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(136, 1002, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6sqx0\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(272, 1002, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wikx0\"]\natlas = ExtResource(\"2_lwtan\")\nregion = Rect2(408, 1002, 136, 167)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oxlbq\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 0, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2hi4b\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 0, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rwpt6\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 0, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u41gf\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 0, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2wmjx\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 123, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sfo57\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 123, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3atsi\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 123, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gkcpm\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 123, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5qjlq\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 246, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tuc66\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 246, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6422h\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 246, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nkhks\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 246, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pkgv8\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 369, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lbyqs\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 369, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f0i74\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 369, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1lh8l\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 369, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6773g\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 492, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_alp67\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 492, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_abdlr\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 492, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a0654\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 492, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wyrl8\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 615, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2x7fq\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 615, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m4aan\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 615, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q2vj6\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 615, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yoydv\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(0, 738, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_juepf\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(147, 738, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_unc33\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(294, 738, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5n1w7\"]\natlas = ExtResource(\"3_ls6cr\")\nregion = Rect2(441, 738, 147, 123)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s5brd\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 0, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pbpsy\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 0, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yy0cw\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 0, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_77ufj\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 0, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nu22g\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 147, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lqi5c\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 147, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2g8ha\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 147, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t0hkk\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 147, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cfaae\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 294, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eb37e\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 294, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_65ojj\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 294, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6srqr\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 294, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iy725\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 441, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qiaki\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 441, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a6l5b\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 441, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nwjxi\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 441, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_msees\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 588, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_peu0r\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 588, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lutxx\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 588, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a4w7j\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 588, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_llvw5\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 735, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cup6o\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 735, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jv611\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 735, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cgo14\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 735, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jgohl\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(0, 882, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_31vp6\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(147, 882, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v4hk8\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(294, 882, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5dhu4\"]\natlas = ExtResource(\"4_e3n44\")\nregion = Rect2(441, 882, 147, 147)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t3pmw\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 0, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2inbw\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 0, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ltsro\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 0, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vtlym\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 0, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oybfv\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 121, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yp106\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 121, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k1al3\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 121, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xkauk\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 121, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_31nnx\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 242, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j6d85\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 242, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4srqu\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 242, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1lw7h\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 242, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cu7yg\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 363, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e6n0s\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 363, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_83vxx\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 363, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cvy4v\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 363, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_krwo1\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 484, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_unu7f\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 484, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_et1nb\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 484, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ijrkw\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 484, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7tw8o\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 605, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rfghh\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 605, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tbsbb\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 605, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e1yav\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 605, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ykut\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(0, 726, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_22vcq\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(136, 726, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7pw6d\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(272, 726, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ta4ph\"]\natlas = ExtResource(\"5_hukkq\")\nregion = Rect2(408, 726, 136, 121)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cmsl7\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(0, 0, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ks2jb\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(92, 0, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6wi1w\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(184, 0, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kx3bv\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(276, 0, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ydbc4\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(0, 112, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lyf8r\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(92, 112, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7bx3w\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(184, 112, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2084t\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(276, 112, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fbrha\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(0, 224, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h416e\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(92, 224, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_16uvx\"]\natlas = ExtResource(\"6_l05kn\")\nregion = Rect2(184, 224, 92, 112)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_24st7\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(0, 0, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x18ks\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(108, 0, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_38gks\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(216, 0, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tsbbp\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(324, 0, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8o73g\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(0, 130, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yqgpt\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(108, 130, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i1yak\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(216, 130, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2p0xy\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(324, 130, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3cjb1\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(0, 260, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ei3id\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(108, 260, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xb4rd\"]\natlas = ExtResource(\"7_fyb51\")\nregion = Rect2(216, 260, 108, 130)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eyfa3\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(0, 0, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kb48d\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(108, 0, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cttta\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(216, 0, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_20t1b\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(324, 0, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_20q4f\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(0, 115, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uprky\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(108, 115, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jkouv\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(216, 115, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jh7at\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(324, 115, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0cryy\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(0, 230, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4revn\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(108, 230, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lr4up\"]\natlas = ExtResource(\"8_lonxs\")\nregion = Rect2(216, 230, 108, 115)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mpkiu\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(0, 0, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jpy5c\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(92, 0, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f0nb7\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(184, 0, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tegcb\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(276, 0, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qfmhp\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(0, 138, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jbw6l\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(92, 138, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n0l1p\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(184, 138, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e44ma\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(276, 138, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_btitr\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(0, 276, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vc4d8\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(92, 276, 92, 138)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mlxhh\"]\natlas = ExtResource(\"9_l7nwh\")\nregion = Rect2(184, 276, 92, 138)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_qkl2r\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ll3xp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8141i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kwfj1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ce6s6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hk51e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_855di\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jx5sb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cetqq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g50xn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_odk4u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k8ggi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2fd3p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gj5a4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l77l8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wtbm6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vbnac\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1qji2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1k7xe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ld1et\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rsrmk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_trnly\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qvr68\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ij8j5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u87g2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xy7wo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h6bmp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6sqx0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wikx0\")\n}],\n\"loop\": true,\n\"name\": &\"death_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oxlbq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2hi4b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rwpt6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u41gf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2wmjx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sfo57\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3atsi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gkcpm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5qjlq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tuc66\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6422h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nkhks\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pkgv8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lbyqs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f0i74\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1lh8l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6773g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_alp67\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_abdlr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a0654\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wyrl8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2x7fq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m4aan\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q2vj6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yoydv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_juepf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_unc33\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5n1w7\")\n}],\n\"loop\": true,\n\"name\": &\"death_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s5brd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pbpsy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yy0cw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_77ufj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nu22g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lqi5c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2g8ha\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t0hkk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cfaae\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eb37e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_65ojj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6srqr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iy725\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qiaki\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a6l5b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nwjxi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_msees\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_peu0r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lutxx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a4w7j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_llvw5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cup6o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jv611\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cgo14\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jgohl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_31vp6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v4hk8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5dhu4\")\n}],\n\"loop\": true,\n\"name\": &\"death_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t3pmw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2inbw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ltsro\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vtlym\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oybfv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yp106\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k1al3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xkauk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_31nnx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j6d85\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4srqu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1lw7h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cu7yg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e6n0s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_83vxx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cvy4v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_krwo1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_unu7f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_et1nb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ijrkw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7tw8o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rfghh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tbsbb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e1yav\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ykut\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_22vcq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7pw6d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ta4ph\")\n}],\n\"loop\": true,\n\"name\": &\"death_W\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cmsl7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ks2jb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6wi1w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kx3bv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ydbc4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lyf8r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7bx3w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2084t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fbrha\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h416e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_16uvx\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_E\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_24st7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x18ks\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_38gks\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tsbbp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8o73g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yqgpt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i1yak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2p0xy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3cjb1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ei3id\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xb4rd\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_N\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eyfa3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kb48d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cttta\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_20t1b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_20q4f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uprky\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jkouv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jh7at\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0cryy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4revn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lr4up\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_S\",\n\"speed\": 15.0\n}, {\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mpkiu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jpy5c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f0nb7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tegcb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qfmhp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jbw6l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n0l1p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e44ma\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_btitr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vc4d8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mlxhh\")\n}],\n\"loop\": true,\n\"name\": &\"slow_run_W\",\n\"speed\": 15.0\n}]\n\n[node name=\"orc_normal_creep\" instance=ExtResource(\"1_yb17k\")]\n\n[node name=\"Sprite\" parent=\"Visual/SpriteParent\" index=\"0\"]\nposition = Vector2(0, -85)\nscale = Vector2(1.4, 1.4)\nsprite_frames = SubResource(\"SpriteFrames_qkl2r\")\nanimation = &\"death_E\"\noffset = Vector2(17.1429, 31.4286)\nsprite_sheets_dir = \"res://assets/creeps/orc/normal\"\n_animation_offset_map = {\n\"death_E\": Vector2(24, 44),\n\"death_N\": Vector2(51, 17),\n\"death_S\": Vector2(-52, 34),\n\"death_W\": Vector2(-24, 12),\n\"slow_run_E\": Vector2(19, 18),\n\"slow_run_N\": Vector2(27, 11),\n\"slow_run_S\": Vector2(-27, 17),\n\"slow_run_W\": Vector2(-19, 8)\n}\n\n[node name=\"HealthBar\" parent=\"Visual\" index=\"1\"]\noffset_top = -150.0\noffset_bottom = -141.0\n\n[node name=\"CollisionPolygon2D\" parent=\"Visual/SelectionArea\" index=\"0\"]\npolygon = PackedVector2Array(-89, -166, 64, -163, 63, 6, -82, 7)\n"
  },
  {
    "path": "src/creeps/packed_metadata.gd",
    "content": "class_name PackedMetadata\n\n\n# Stores metadata about packed sprite sheets that are\n# produced by PackSpriteSheet.gd.\n# \n# Source rects are always 512x512 but packed rect can be any\n# size and not square.\n#\n# Offset is the difference between center of original frame\n# and packed frame. Note that this is stored in ratio of\n# sprite sheet width/height and not pixels. This is for\n# cases where sprite sheet is resized during load.\n\n\nenum Column {\n\tNAME = 0,\n\tROW_COUNT,\n\tCOL_COUNT,\n\tSPRITE_COUNT,\n\tOFFSET_X,\n\tOFFSET_Y,\n\tCOUNT,\n}\n\nconst METADATA_FILENAME: String = \"metadata.csv\"\n\nvar _name: String = \"\"\nvar _row_count: int = 0\nvar _col_count: int = 0\nvar _sprite_count: int = 0\nvar _offset: Vector2 = Vector2.ZERO\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_row_count() -> int:\n\treturn _row_count\n\n\nfunc get_col_count() -> int:\n\treturn _col_count\n\n\nfunc get_sprite_count() -> int:\n\treturn _sprite_count\n\n\nfunc get_offset() -> Vector2:\n\treturn _offset\n\n\nfunc convert_to_csv_line() -> Array:\n\tvar csv_line: Array = []\n\tcsv_line.resize(Column.COUNT)\n\n\tcsv_line[Column.NAME] = _name\n\tcsv_line[Column.ROW_COUNT] = _row_count\n\tcsv_line[Column.COL_COUNT] = _col_count\n\tcsv_line[Column.SPRITE_COUNT] = _sprite_count\n\tcsv_line[Column.OFFSET_X] = _offset.x\n\tcsv_line[Column.OFFSET_Y] = _offset.y\n\n\treturn csv_line\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(sheet_path: String, packed_sheet: Image, rect: Rect2i, offset_pixels: Vector2, sprite_count: int) -> PackedMetadata:\n\tvar metadata: PackedMetadata = PackedMetadata.new()\n\tmetadata._name = PackedMetadata._get_animation_name(sheet_path)\n\tmetadata._row_count = roundi(float(packed_sheet.get_height()) / rect.size.y)\n\tmetadata._col_count = roundi(float(packed_sheet.get_width()) / rect.size.x)\n\tmetadata._sprite_count = sprite_count\n\tmetadata._offset = offset_pixels / Vector2(packed_sheet.get_size())\n\n\treturn metadata\n\n\nstatic func convert_from_csv_line(csv_line: Array) -> PackedMetadata:\n\tif csv_line.size() != Column.COUNT:\n\t\tpush_error(\"Malformed metadata string: \", csv_line)\n\n\t\treturn PackedMetadata.new()\n\n\tvar name: String = csv_line[Column.NAME]\n\n\tvar row_count: int = csv_line[Column.ROW_COUNT].to_int()\n\tvar col_count: int = csv_line[Column.COL_COUNT].to_int()\n\tvar sprite_count: int = csv_line[Column.SPRITE_COUNT].to_int()\n\n\tvar offset_x: float = csv_line[Column.OFFSET_X].to_float()\n\tvar offset_y: float = csv_line[Column.OFFSET_Y].to_float()\n\tvar offset: Vector2 = Vector2(offset_x, offset_y)\n\n\tvar metadata: PackedMetadata = PackedMetadata.new()\n\tmetadata._name = name\n\tmetadata._row_count = row_count\n\tmetadata._col_count = col_count\n\tmetadata._sprite_count = sprite_count\n\tmetadata._offset = offset\n\n\treturn metadata\n\n\nstatic func get_metadata_for_sheet(sheet_path: String) -> PackedMetadata:\n\tvar metadata_path: String = PackedMetadata.get_metadata_path(sheet_path)\n\n\tvar animation_name: String = PackedMetadata._get_animation_name(sheet_path)\n\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(metadata_path)\n\n\tvar metadata: PackedMetadata = PackedMetadata.new()\n\tfor csv_line in csv:\n\t\tvar this_metadata: PackedMetadata = PackedMetadata.convert_from_csv_line(csv_line)\n\n\t\tif this_metadata._name == animation_name:\n\t\t\tmetadata = this_metadata\n\n\t\t\tbreak\n\n\treturn metadata\n\n\nstatic func _get_animation_name(sheet_path: String) -> String:\n\tvar animation_name: String = sheet_path.get_file().trim_suffix(sheet_path.get_extension()).trim_suffix(\".\")\n\n\treturn animation_name\n\n\nstatic func get_metadata_path(sheet_path: String) -> String:\n\tvar metadata_path: String = \"%s/%s\" % [sheet_path.get_base_dir(), METADATA_FILENAME]\n\n\treturn metadata_path\n\n\nstatic func get_legend_line() -> Array:\n\tvar legend_line: Array = [\n\t\t\"name\",\n\t\t\"row_count\",\n\t\t\"col_count\",\n\t\t\"sprite_count\",\n\t\t\"offset_x\",\n\t\t\"offset_y\",\n\t]\n\n\treturn legend_line\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_armored.gd",
    "content": "class_name CreepArmored extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_armored\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_ARMOR, 10, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ARMOR_PERC, 0.4, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_broody.gd",
    "content": "class_name CreepBroody extends BuffType\n\n\nconst EGG_SCALE_MIN: float = 0.6\nconst EGG_SCALE_MAX: float = 1.0\nconst EGG_GROW_TIME: float = 3.0\n\nconst LESSER_HATCHLING_COUNT: int = 5\nconst LESSER_HATCHLING_HEALTH: float = 0.02\nconst LESSER_HATCHLING_SCALE: float = 0.3\nconst LESSER_HATCHLING_RANDOM_OFFSET: float = 100\nconst GREATER_HATCHLING_HEALTH: float = 0.10\nconst GREATER_HATCHLING_SCALE: float = 0.6\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_broody\", 0, 0, true, parent)\n\n\tadd_event_on_create(on_create)\n\n\nfunc on_create(event: Event):\n\tvar autocast: Autocast = Autocast.make(171, self)\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tcreep.add_autocast(autocast)\n\n\nfunc on_autocast(event: Event):\n#\tLay an egg\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar caster: Creep = autocast.get_caster()\n\tvar caster_pos: Vector2 = caster.get_position_wc3_2d()\n\tvar egg_effect: int = Effect.create_animated(\"res://src/effects/barrel.tscn\", Vector3(caster_pos.x, caster_pos.y, 0), 0)\n\tEffect.set_auto_destroy_enabled(egg_effect, false)\n\tEffect.set_scale(egg_effect, EGG_SCALE_MIN)\n\tEffect.set_color(egg_effect, Color.GREEN)\n\n#\tSave properties of caster\n\tvar caster_scene_path: String = caster.get_scene_file_path()\n\tvar caster_scene: PackedScene = load(caster_scene_path)\n\tvar caster_path: Path2D = caster.get_move_path()\n\tvar player: Player = caster.get_player()\n\tvar caster_armor_type: ArmorType.enm = caster.get_armor_type()\n\tvar caster_race: CreepCategory.enm = caster.get_category()\n\tvar caster_size: CreepSize.enm = caster.get_size()\n\tvar caster_health: float = caster.get_overall_health()\n\tvar caster_armor: float = caster.get_base_armor()\n\tvar caster_level: int = caster.get_spawn_level()\n\tvar caster_path_index: int = caster._current_path_index\n\n#\tAdd delay before spawning hatchlings. Increase egg scale\n#\twhile waiting.\n\tfor i in range(0, 5):\n\t\tvar sleep_time: float = EGG_GROW_TIME / 6\n\t\tawait Utils.create_manual_timer(sleep_time, self).timeout\n\n\t\tvar egg_grow_progress: float = i / 6.0\n\t\tvar egg_scale: float = EGG_SCALE_MIN + egg_grow_progress * (EGG_SCALE_MAX - EGG_SCALE_MIN)\n\t\tEffect.set_scale(egg_effect, egg_scale)\n\n\tEffect.destroy_effect(egg_effect)\n\n\tif !Utils.unit_is_valid(caster):\n\t\treturn\n\n#\tCreate hatchlings\n\tvar hatchling_type_is_lesser: int = Utils.rand_chance(Globals.synced_rng, 0.5)\n\n\tif hatchling_type_is_lesser:\n\t\tvar hatchling_health = caster_health * LESSER_HATCHLING_HEALTH\n\n\t\tfor i in range(0, LESSER_HATCHLING_COUNT):\n\t\t\tvar hatchling: Creep = caster_scene.instantiate()\n\t\t\thatchling.set_properties(caster_path, player, caster_size, caster_armor_type, caster_race, hatchling_health, caster_armor, caster_level)\n\n\t\t\tvar random_offset: Vector2 = Vector2(Globals.synced_rng.randf_range(-1, 1) * LESSER_HATCHLING_RANDOM_OFFSET, Globals.synced_rng.randf_range(-1, 1) * LESSER_HATCHLING_RANDOM_OFFSET)\n\t\t\tvar hatchling_pos: Vector2 = caster_pos + random_offset\n\t\t\thatchling.set_position_wc3_2d(hatchling_pos)\n\t\t\t\n\t\t\thatchling.set_portal_damage_multiplier(LESSER_HATCHLING_HEALTH)\n\t\t\thatchling._current_path_index = caster_path_index\n\n\t\t\tUtils.add_object_to_world(hatchling)\n\t\t\t\n\t\t\thatchling.set_unit_scale(LESSER_HATCHLING_SCALE)\n\telse:\n\t\tvar hatchling_health = caster_health * GREATER_HATCHLING_HEALTH\n\n\t\tvar hatchling: Creep = caster_scene.instantiate()\n\t\thatchling.set_properties(caster_path, player, caster_size, caster_armor_type, caster_race, hatchling_health, caster_armor, caster_level)\n\n\t\tvar hatchling_pos: Vector2 = caster_pos\n\t\thatchling.set_position_wc3_2d(hatchling_pos)\n\t\thatchling.set_portal_damage_multiplier(GREATER_HATCHLING_HEALTH)\n\t\thatchling._current_path_index = caster_path_index\n\n\t\tUtils.add_object_to_world(hatchling)\n\n\t\thatchling.set_unit_scale(GREATER_HATCHLING_SCALE)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_dart.gd",
    "content": "class_name CreepDart extends BuffType\n\n# NOTE: this special is not affected by silence, on purpose.\n# This is how it was in the original game.\n\nconst DART_CHANCE: float = 300\nconst DART_CD: float = 6\nconst DART_DISTANCE: float = 300\n\nvar tired_bt: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_dart\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.60, 0.0)\n\tset_buff_modifier(modifier)\n\n\ttired_bt = BuffType.new(\"tired_bt\", DART_CD, 0, true, self\n\t\t)\n\ttired_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\ttired_bt.set_buff_icon_color(Color.LIGHT_BLUE)\n\ttired_bt.set_buff_tooltip(tr(\"MS3N\"))\n\ttired_bt.set_is_purgable(false)\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tif !creep.calc_chance(DART_CHANCE):\n\t\treturn\n\n\tvar dart_is_on_cd: bool = creep.get_buff_of_type(tired_bt) != null\n\n\tif dart_is_on_cd:\n\t\treturn\n\n\tvar creep_pos: Vector2 = creep.get_position_wc3_2d()\n\n\tvar path: Path2D = creep.get_move_path()\n\tvar path_index: int = creep._current_path_index\n\tvar path_point: Vector2 = Utils.get_path_point_wc3(path, path_index)\n\tvar distance_to_path_point_squared: float = creep_pos.distance_squared_to(path_point)\n\tvar dart_would_overshoot_path_point: bool = distance_to_path_point_squared < pow(DART_DISTANCE, 2)\n\n\tif dart_would_overshoot_path_point:\n\t\treturn\n\n\tvar dart_vector: Vector2 = creep_pos.direction_to(path_point) * DART_DISTANCE\n\tvar dart_pos: Vector2 = creep_pos + dart_vector\n\tcreep.set_position_wc3_2d(dart_pos)\n\n\ttired_bt.apply(creep, creep, 1)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_ethereal.gd",
    "content": "class_name CreepEthereal extends BuffType\n\n\nconst ETHEREAL_PERIOD: float = 5.0\nconst ETHEREAL_DURATION: float = 2.0\n\n\nvar ethereal_active_buff: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_ethereal\", 0, 0, true, parent)\n\n\tethereal_active_buff = BuffType.new(\"creep_ethereal_active\", ETHEREAL_DURATION, 0, true, self)\n\tethereal_active_buff.add_event_on_damaged(on_damaged)\n\tethereal_active_buff.add_event_on_create(on_create)\n\tethereal_active_buff.add_event_on_cleanup(on_cleanup)\n\tethereal_active_buff.set_buff_icon(\"res://resources/icons/generic_icons/aries.tres\")\n\tethereal_active_buff.set_buff_icon_color(Color.CYAN)\n\tethereal_active_buff.set_buff_tooltip(tr(\"W31K\"))\n\n\tadd_periodic_event(on_periodic, ETHEREAL_PERIOD)\n\n\nfunc on_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar creep_is_silenced: bool = creep.is_silenced()\n\n\tif creep_is_silenced:\n\t\treturn\n\n\tethereal_active_buff.apply(creep, creep, 0)\n\n\nfunc on_damaged(event: Event):\n\tvar caster: Unit = event.get_target()\n\tvar is_arcane: bool = caster.get_attack_type() == AttackType.enm.ARCANE\n\n\tif event.is_spell_damage() || is_arcane:\n\t\tevent.damage *= 1.4\n\telse:\n\t\tevent.damage = 0\n\n\n# NOTE: these two f-ns make the creep look transparent while\n# ethereal\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tcreep.set_sprite_color(Color.html(\"aaffaaaa\"))\n\tcreep.add_ethereal()\n\n\nfunc on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tcreep.set_sprite_color(Color.WHITE)\n\tcreep.remove_ethereal()\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_evasion.gd",
    "content": "class_name CreepEvasion extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_evasion\", 0, 0, true, parent)\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tCreepEvasion.evasion_effect(event, 0.25)\n\n\nstatic func evasion_effect(event: Event, chance: float):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar tower: Unit = event.get_target()\n\tvar evade_success: bool = creep.calc_chance(chance)\n\n\tif evade_success && !event.is_spell_damage():\n\t\tevent.damage = 0\n\t\ttower.get_player().display_floating_text_x(Utils.tr(\"FLOATING_TEXT_MISS\"), tower, Color.RED, 0.05, 0.0, 2.0)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_evolving.gd",
    "content": "class_name CreepEvolving extends BuffType\n\n# NOTE: this special is not affected by silence, on purpose.\n# This is how it was in the original game.\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_evolving\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\tadd_event_on_create(on_create)\n\n\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_int = 0\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tvar life_max: float = creep.get_overall_health()\n\tvar damage_ratio: float = Utils.divide_safe(event.damage, life_max)\n\n\tvar attacker: Unit = event.get_target()\n\tvar tower: Tower = attacker as Tower\n\n\tif tower == null:\n\t\treturn\n\n\tvar element: Element.enm = tower.get_element()\n\n\tvar proc_count: int = buff.user_int\n\n\tif damage_ratio > 0.05:\n\t\tvar mod_type: ModificationType.enm = Element.convert_to_dmg_from_element_mod(element)\n\n\t\tvar mod_value: float = -0.4\n\t\tfor i in range(0, proc_count):\n\t\t\tmod_value /= 2\n\n\t\tcreep.modify_property(mod_type, mod_value)\n\n\t\tvar new_proc_count: int = proc_count + 1\n\t\tbuff.user_int = new_proc_count\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_fireball.gd",
    "content": "class_name CreepFireball extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_fireball\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar attacker: Unit = event.get_target()\n\n\tif !creep.calc_chance(0.05):\n\t\treturn\n\n\tcreep.kill_instantly(attacker)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_flock.gd",
    "content": "class_name CreepFlock extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_flock\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, -0.50, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_EXP_GRANTED, -0.50, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH, -0.50, 0.0)\n\tset_buff_modifier(modifier)\n\n\tadd_event_on_create(on_create)\n\n\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit()\n\n\tcreep.set_portal_damage_multiplier(0.5)\n\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_ghost.gd",
    "content": "class_name CreepGhost extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_ghost\", 0, 0, true, parent)\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar ignore_attack_damage: bool = creep.calc_chance(0.90)\n\n\tif ignore_attack_damage && !event.is_spell_damage():\n\t\tevent.damage = 0\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_gravid.gd",
    "content": "class_name CreepGravid extends BuffType\n\n\nconst MATURED_TIME_MAX: float = 12\nconst SCALE_MIN: float = 0.4\nconst SCALE_MAX: float = 1.0\nconst CHILD_POS_RAND_OFFSET: float = 30\n\nconst CHILD_COUNT_WEIGHTS: Dictionary = {\n\t2: 1.0,\n\t3: 1.0,\n\t4: 1.0,\n\t5: 0.2,\n}\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_gravid\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, -0.75, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_EXP_GRANTED, -0.75, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH, -0.75, 0.0)\n\tset_buff_modifier(modifier)\n\n\tadd_event_on_create(on_create)\n\tadd_periodic_event(periodic, 0.5)\n\tadd_event_on_death(on_death)\n\n\n# The first creep starts as \"matured\"\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_real = MATURED_TIME_MAX\n\n\nfunc periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar maturing_timer: float = buff.user_real\n\tmaturing_timer += 0.5\n\tbuff.user_real = maturing_timer\n\n\tupdate_creep_scale(creep, maturing_timer)\n\n\n# NOTE: limit to 2 children for champions because there are\n# many champions per wave. Otherwise, champions could spawn\n# too many children which would make a wave unreasonably\n# difficult.\nfunc on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar adult: Creep = buff.get_buffed_unit()\n\tvar adult_maturing_timer: float = buff.user_real\n\tvar adult_is_matured: bool = adult_maturing_timer >= MATURED_TIME_MAX\n\n\tif !adult_is_matured:\n\t\treturn\n\n\tvar child_count: int\n\tvar adult_size: CreepSize.enm = adult.get_size()\n\tvar adult_is_champion: bool = adult_size == CreepSize.enm.CHAMPION\n\tif adult_is_champion:\n\t\tchild_count = 2\n\telse:\n\t\tchild_count = Utils.random_weighted_pick(Globals.synced_rng, CHILD_COUNT_WEIGHTS)\n\n\tvar adult_pos: Vector2 = adult.get_position_wc3_2d()\n\tvar adult_scene_path: String = adult.get_scene_file_path()\n\tvar adult_path: Path2D = adult.get_move_path()\n\tvar player: Player = adult.get_player()\n\tvar adult_armor_type: ArmorType.enm = adult.get_armor_type()\n\tvar adult_race: CreepCategory.enm = adult.get_category()\n\tvar child_health: float = adult.get_overall_health() / child_count * 1.2\n\tvar adult_armor: float = adult.get_base_armor()\n\tvar adult_level: int = adult.get_spawn_level()\n\tvar adult_path_index: int = adult._current_path_index\n\n\tvar creep_scene: PackedScene = load(adult_scene_path)\n\tvar child_mana: float = adult.get_overall_mana() / child_count\n\tvar adult_specials: Array[int] = adult.get_special_list()\n\tvar adult_facing: float = adult.get_unit_facing()\n\tvar child_pos_path_offset: float = Globals.synced_rng.randf_range(50, 150)\n\tvar adult_move_vector: Vector2 = Vector2(child_pos_path_offset, 0).rotated(deg_to_rad(adult_facing))\n\n\tvar child_portal_damage_multiplier: float = 1.0 / child_count / 2\n\n\tfor i in range(0, child_count):\n\t\tvar child_creep: Creep = creep_scene.instantiate()\n\t\tchild_creep.set_properties(adult_path, player, adult_size, adult_armor_type, adult_race, child_health, adult_armor, adult_level)\n\n\t\tvar random_offset: Vector2 = Vector2(Globals.synced_rng.randf_range(-1, 1) * CHILD_POS_RAND_OFFSET, Globals.synced_rng.randf_range(-1, 1) * CHILD_POS_RAND_OFFSET)\n\t\tvar offset_on_path: Vector2 = i * adult_move_vector.rotated(deg_to_rad(180))\n\t\tvar child_pos: Vector2 = adult_pos + random_offset + offset_on_path\n\t\t\n\t\tchild_creep.set_base_mana(child_mana)\n\t\tchild_creep.set_mana(child_mana)\n\t\tchild_creep.set_position_wc3_2d(child_pos)\n\t\tchild_creep._current_path_index = adult_path_index\n\n\t\tchild_creep.set_portal_damage_multiplier(child_portal_damage_multiplier)\n\n\t\tUtils.add_object_to_world(child_creep)\n\n\t\tWaveSpecial.apply_to_creep(adult_specials, child_creep)\n\n\t\tvar child_gravid_buff: Buff = child_creep.get_buff_of_type(self)\n\n\t\tif child_gravid_buff == null:\n\t\t\tpush_error(\"Child gravid buff is somehow null\")\n\n\t\t\treturn\n\n#\t\tNOTE: set mature timer to 0. Note that this\n#\t\toverwrites the initial value set in on_create()\n\t\tvar maturing_timer: float = 0\n\t\tchild_gravid_buff.user_real = maturing_timer\n\t\tupdate_creep_scale(child_creep, maturing_timer)\n\n\nfunc update_creep_scale(creep: Creep, maturing_timer: float):\n\tvar creep_is_matured: bool = maturing_timer >= MATURED_TIME_MAX\n\n\tif creep_is_matured:\n\t\treturn\n\n\tvar creep_scale: float = SCALE_MIN + maturing_timer / MATURED_TIME_MAX * (SCALE_MAX - SCALE_MIN)\n\tcreep.set_unit_scale(creep_scale)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_greater_speed.gd",
    "content": "class_name CreepGreaterSpeed extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_greater_speed\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.6, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_greater_spell_resistance.gd",
    "content": "class_name CreepGreaterSpellResistance extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_greater_spell_resistance\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, -0.80, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_heavy_armored.gd",
    "content": "class_name CreepHeavyArmored extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_heavy_armored\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_ARMOR, 25, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ARMOR_PERC, 1.0, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_invisible.gd",
    "content": "class_name CreepInvisible extends BuffType\n\n\n# NOTE: this is commented out because invisibility mechanic\n# is not implemented\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_invisible\", 0, 0, true, parent)\n\n\t# add_event_on_create(on_create)\n\n\n# func on_create(event: Event):\n# \tvar buff: Buff = event.get_buff()\n# \tvar creep: Unit = buff.get_buffed_unit()\n# \tcreep.set_invisible(true)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_magic_immunity.gd",
    "content": "class_name CreepMagicImmunity extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_magic_immunity\", 0, 0, true, parent)\n\tadd_periodic_event(periodic, 0.1)\n\n\nfunc periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar creep_mana: float = creep.get_mana()\n\tvar should_be_immune: bool = creep_mana >= 10\n\tcreep.set_immune(should_be_immune)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_mana_drain_aura.gd",
    "content": "class_name CreepManaDrainAura extends BuffType\n\n\nvar slow_aura_effect: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_mana_drain_aura\", 0, 0, true, parent)\n\n\tvar draw_below_unit: bool = true\n\tset_special_effect(\"res://src/effects/spell_aire_flat.tscn\", 0, 1.0, Color.SKY_BLUE, draw_below_unit)\n\n\tslow_aura_effect = BuffType.create_aura_effect_type(\"creep_slow_aura_effect\", false, self)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, -2.0, 0.0)\n\tslow_aura_effect.set_buff_modifier(modifier)\n\tslow_aura_effect.set_buff_tooltip(tr(\"RTAD\"))\n\n\tadd_aura(105, self)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_manashield+.gd",
    "content": "class_name CreepManaShieldPlus extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_mana_shield_plus\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tvar spend_mana: bool = false\n\tCreepManaShield.shield_effect(event, spend_mana)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_manashield.gd",
    "content": "class_name CreepManaShield extends BuffType\n\n# TODO: add explode visual and also make it so that there's\n# no corpse.\n\nstatic var _max_cost_map: Dictionary = {\n\tCreepSize.enm.MASS: 3,\n\tCreepSize.enm.NORMAL: 6,\n\tCreepSize.enm.AIR: 12,\n\tCreepSize.enm.CHAMPION: 12,\n\tCreepSize.enm.BOSS: 12,\n\tCreepSize.enm.CHALLENGE_MASS: 0,\n\tCreepSize.enm.CHALLENGE_BOSS: 0,\n}\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_mana_shield\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tvar spend_mana: bool = true\n\tCreepManaShield.shield_effect(event, spend_mana)\n\n\nstatic func shield_effect(event: Event, spend_mana: bool):\n\tvar caster: Unit = event.get_target()\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tvar creep_size: CreepSize.enm = creep.get_size_including_challenge_sizes()\n\tvar shield_cost_max: float = _max_cost_map[creep_size]\n\tvar damage_ratio: float = Utils.divide_safe(event.damage, creep.get_overall_health())\n\tvar shield_cost: float = min(80 * damage_ratio, shield_cost_max)\n\n\tvar mana_ratio = creep.get_mana_ratio()\n\tvar damage_multiplier: float = clampf(1.0 - 0.8 * mana_ratio, 0.2, 1.0)\n\tevent.damage *= damage_multiplier\n\n\tif spend_mana:\n\t\tcreep.subtract_mana(shield_cost, false)\n\n#\tNOTE: when creep reaches 0 mana it's supposed to\n#\texplode. Simulate this by killing creep instantly.\n\tif creep.get_mana() == 0:\n\t\tcaster.kill_instantly(creep)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_meaty.gd",
    "content": "class_name CreepMeaty extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_meaty\", 0, 0, true, parent)\n\n\tadd_event_on_death(on_death)\n\n\nfunc on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar unit: Unit = buff.get_buffed_unit()\n\tvar caster: Unit = event.get_target()\n\n\tvar creep: Creep = unit as Creep\n\n\tif creep == null:\n\t\treturn\n\n#\tNOTE: this condition is a bit confusing. The way it\n#\tworks is that if creep is below max level, it will\n#\talways drop food. If it's above max level, it has 10%\n#\tchance to drop food. Currently, creeps can't go above\n#\tmax level so this only applies to a potential future\n#\t\"neverending\" game length.\n\tif creep.get_spawn_level() < Utils.get_max_level() || creep.calc_bad_chance(0.1):\n\t\tcreep.drop_item_by_id(caster, false, ItemProperties.CONSUMABLE_CHICKEN_ID)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_mechanical.gd",
    "content": "class_name CreepMechanical extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_semi_mechanical\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.90, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_necromancer.gd",
    "content": "class_name CreepNecromancer extends BuffType\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] in original game,\n# Necromancers raise skeletons. Don't have sprites for\n# skeletons so raising creeps using their original sprites.\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] original script\n# appears to set health of revived creep to double of the\n# original amount. Not sure if this is correct? Left at 100%\n# of original health for now.\n\n# NOTE: this special is not affected by silence, on purpose.\n# This is how it was in the original game.\n\n\nconst RAISE_DELAY: float = 2\nconst RAISE_MANA_COST: float = 10\n\n\nvar necromancer_aura_bt: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_necromancer\", 0, 0, true, parent)\n\n\tnecromancer_aura_bt = BuffType.create_aura_effect_type(\"necromancer_aura_bt\", true, self)\n\tnecromancer_aura_bt.set_hidden()\n\tnecromancer_aura_bt.add_event_on_death(necromancer_aura_bt_on_death)\n\n\tadd_aura(106, self)\n\n\nfunc necromancer_aura_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar original_creep: Creep = buff.get_buffed_unit()\n\tvar creep_size: CreepSize.enm = original_creep.get_size()\n\tvar creep_is_lesser_size: bool = creep_size == CreepSize.enm.MASS || creep_size == CreepSize.enm.NORMAL\n\n\tif !creep_is_lesser_size:\n\t\treturn\n\n# \tNOTE: need to save all creep properties now before creep\n# \tis destroyed\n\tvar creep_uid: int = original_creep.get_uid()\n\tvar creep_pos: Vector2 = original_creep.get_position_wc3_2d()\n\tvar creep_scene_path: String = original_creep.get_scene_file_path()\n\tvar creep_path: Path2D = original_creep.get_move_path()\n\tvar player: Player = original_creep.get_player()\n\tvar creep_armor_type: ArmorType.enm = original_creep.get_armor_type()\n\tvar creep_race: CreepCategory.enm = original_creep.get_category()\n\tvar creep_health: float = original_creep.get_overall_health()\n\tvar creep_armor: float = original_creep.get_base_armor()\n\tvar creep_level: int = original_creep.get_spawn_level()\n\tvar creep_path_index: int = original_creep._current_path_index\n\t\n\tvar necromancer: Creep = buff.get_caster()\n\n\tawait Utils.create_manual_timer(RAISE_DELAY, self).timeout\n\n\tif !Utils.unit_is_valid(necromancer):\n\t\treturn\n\n\tvar necromancer_has_enough_mana: bool = necromancer.get_mana() >= RAISE_MANA_COST\n\n\tif !necromancer_has_enough_mana:\n\t\treturn\n\n\tnecromancer.subtract_mana(RAISE_MANA_COST, false)\n\t\n\tvar it: Iterate = Iterate.over_units_in_range_of(null, TargetType.new(TargetType.CORPSES), creep_pos, 1000)\n\n\tvar corpse_for_creep: CreepCorpse = null\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar corpse: CreepCorpse = next as CreepCorpse\n\n\t\tif corpse == null:\n\t\t\tcontinue\n\n\t\tvar corpse_match: bool = corpse.get_creep_uid() == creep_uid\n\n\t\tif corpse_match:\n\t\t\tcorpse_for_creep = corpse\n\n\t\t\tbreak\n\n\tif corpse_for_creep == null:\n\t\treturn\n\n# \tNOTE: creep specials are not carried over on purpose\n\tvar creep_scene: PackedScene = load(creep_scene_path)\n\tvar raised_creep: Creep = creep_scene.instantiate()\n\traised_creep.set_properties(creep_path, player, creep_size, creep_armor_type, creep_race, creep_health, creep_armor, creep_level)\n\n\traised_creep.set_position_wc3_2d(creep_pos)\n\traised_creep._current_path_index = creep_path_index\n\n\traised_creep.set_portal_damage_multiplier(0.5)\n\n\tUtils.add_object_to_world(raised_creep)\n\n\tvar necromancer_pos: Vector2 = necromancer.get_position_wc3_2d()\n\tvar effect_on_necromancer: int = Effect.create_simple(\"res://src/effects/upgrade_tower.tscn\", necromancer_pos)\n\tEffect.set_color(effect_on_necromancer, Color.PURPLE)\n\tEffect.set_z_index(effect_on_necromancer, Effect.Z_INDEX_BELOW_CREEPS)\n\tvar effect_on_raised_creep: int = Effect.create_simple(\"res://src/effects/freezing_breath_purple.tscn\", creep_pos)\n\tEffect.set_z_index(effect_on_raised_creep, Effect.Z_INDEX_BELOW_CREEPS)\n\n\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, necromancer, raised_creep)\n\tlightning.modulate = Color.PURPLE\n\tlightning.set_lifetime(0.5)\n\n\tcorpse_for_creep.remove_from_game()\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_protector.gd",
    "content": "class_name CreepProtector extends BuffType\n\n\n# NOTE: this doesn't 100% match original code logic but end\n# result is the same. Used autocast so that channeling is\n# affected by silence.\n\n\nconst PROTECTOR_RANGE: int = 1000\n\n\nvar aura_bt: BuffType\nvar channel_bt: BuffType\nvar curse_bt: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_protector\", 0, 0, true, parent)\n\n\tadd_event_on_create(on_create)\n\t\n\tchannel_bt = BuffType.new(\"channel_bt\", 0, 0, true, self)\n\tchannel_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\tchannel_bt.set_buff_icon_color(Color.DARK_RED)\n\tchannel_bt.set_buff_tooltip(tr(\"LT32\"))\n\t\n\tcurse_bt = BuffType.new(\"curse_bt\", 1.5, 0, false, self\n\t\t)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -1.3, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, -2, 0.0)\n\tcurse_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\tcurse_bt.set_buff_icon_color(Color.DARK_RED)\n\tcurse_bt.set_buff_tooltip(tr(\"M3QZ\"))\n\tcurse_bt.set_buff_modifier(modifier)\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.add_event_on_death(aura_bt_on_death)\n\taura_bt.set_hidden()\n\n\tadd_aura(107, self)\n\n\nfunc on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar protector: Unit = buff.get_buffed_unit()\n\n\tvar autocast: Autocast = Autocast.make(172, self)\n\tprotector.add_autocast(autocast)\n\n\nfunc aura_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar protector: Unit = buff.get_caster()\n\n\tvar channel_buff: Buff = protector.get_buff_of_type(channel_bt)\n\n\tvar protector_is_channeling: bool = channel_buff != null\n\n\tif protector_is_channeling:\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(protector, TargetType.new(TargetType.CREEPS + TargetType.SIZE_MASS + TargetType.SIZE_NORMAL + TargetType.SIZE_BOSS + TargetType.SIZE_AIR), PROTECTOR_RANGE)\n\t\tvar non_champion_count: int = it.count()\n\t\tvar stop_channel: bool = non_champion_count == 0\n\n\t\tif stop_channel:\n\t\t\tchannel_buff.remove_buff()\n\telse:\n\t\tvar attacker: Unit = event.get_target()\n\t\tvar new_channel_buff: Buff = channel_bt.apply_to_unit_permanent(protector, protector, 0)\n\t\tnew_channel_buff.user_int = attacker.get_instance_id()\n\n\nfunc on_autocast(event: Event):\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar protector: Unit = autocast.get_caster()\n\tvar channel_buff: Buff = protector.get_buff_of_type(channel_bt)\n\tvar protector_is_channeling: bool = channel_buff != null\n\n\tif !protector_is_channeling:\n\t\treturn\n\t\n\tvar cursed_tower_instance_id: int = channel_buff.user_int\n\tvar cursed_tower_object: Object = instance_from_id(cursed_tower_instance_id)\n\n\tif cursed_tower_object == null || !Utils.unit_is_valid(cursed_tower_object):\n\t\treturn\n\n\tvar cursed_tower: Unit = cursed_tower_object as Unit\n\n\tvar tower_pos: Vector2 = cursed_tower.get_position_wc3_2d()\n\tvar protector_pos: Vector2 = protector.get_position_wc3_2d()\n\tvar cursed_tower_is_in_range: bool = VectorUtils.in_range(tower_pos, protector_pos, PROTECTOR_RANGE)\n\n\tif !cursed_tower_is_in_range:\n\t\tchannel_buff.remove_buff()\n\n\t\treturn\n\n\tcurse_bt.apply(protector, cursed_tower, 0)\n\n\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, protector, cursed_tower)\n\tlightning.modulate = Color.DARK_OLIVE_GREEN\n\tlightning.set_lifetime(1.0)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_purge_revenge.gd",
    "content": "class_name CreepPurgeRevenge extends BuffType\n\n\nvar slow_attack: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_purge_revenge\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\n\tslow_attack = BuffType.new(\"creep_slow_attack\", 4.0, 0.0, false, self)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -1.5, 0.0)\n\tslow_attack.set_buff_modifier(modifier)\n\tslow_attack.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\tslow_attack.set_buff_icon_color(Color.DARK_RED)\n\tslow_attack.set_buff_tooltip(tr(\"N3BA\"))\n\tslow_attack.set_special_effect(\"res://src/effects/purge_buff_target.tscn\", 50, 1.0, Color(Color.GREEN, 0.75))\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar attacker: Unit = event.get_target()\n\tvar creep_is_silenced: bool = creep.is_silenced()\n\n\tif creep_is_silenced:\n\t\treturn\n\n\tif !creep.calc_chance(0.15):\n\t\treturn\n\n\tfor i in range(0, 2):\n\t\tattacker.purge_buff(true)\n\t\n\tslow_attack.apply(creep, attacker, 1)\n\n\tSFX.sfx_at_unit(SfxPaths.MAGIC_CONFUSE, attacker)\n\t\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_regeneration.gd",
    "content": "class_name CreepRegeneration extends BuffType\n\n\nvar _regen_ratio_map: Dictionary = {\n\tCreepSize.enm.MASS: 0.05,\n\tCreepSize.enm.NORMAL: 0.025,\n\tCreepSize.enm.AIR: 0.0285,\n\tCreepSize.enm.CHAMPION: 0.022,\n\tCreepSize.enm.BOSS: 0.007,\n\tCreepSize.enm.CHALLENGE_MASS: 0.0,\n\tCreepSize.enm.CHALLENGE_BOSS: 0.0,\n}\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_regeneration\", 0, 0, true, parent)\n\tadd_event_on_create(on_create)\n\n\nfunc on_create(event: Event):\n\tCreepRegeneration.regen_special_on_create(event, _regen_ratio_map)\n\n\nstatic func regen_special_on_create(event: Event, regen_ratio_map: Dictionary):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar creep_size: CreepSize.enm = creep.get_size_including_challenge_sizes()\n\tvar creep_hp: float = creep.get_overall_health()\n\tvar regen_ratio: float = regen_ratio_map[creep_size]\n\tvar regen_value: float = creep_hp * regen_ratio\n\n\tcreep.modify_property(ModificationType.enm.MOD_HP_REGEN, regen_value)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_relic_raider.gd",
    "content": "class_name CreepRelicRaider extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_relic_raider\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, -0.50, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH, 0.8, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH, 0.3, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_rich.gd",
    "content": "class_name CreepRich extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_rich\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, 0.60, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_EXP_GRANTED, -1.0, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_second_chance.gd",
    "content": "class_name CreepSecondChance extends BuffType\n\n# NOTE: this special is not affected by silence, on purpose.\n# This is how it was in the original game.\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_second_chance\", 0, 0, true, parent)\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tvar life: float = creep.get_health()\n\tvar mana_ratio: float = creep.get_mana_ratio()\n\tvar damage_is_mortal: bool = (life - event.damage) <= 0\n\tvar chance_success: bool = creep.calc_chance(0.5)\n\tvar enough_mana: bool = mana_ratio > 0.33\n\n\tif damage_is_mortal && chance_success && enough_mana:\n\t\tvar life_after_heal: float = Globals.synced_rng.randf_range(0.2, 1.0) * creep.get_overall_health() * mana_ratio + event.damage\n\t\tcreep.set_health_over_max(life_after_heal)\n\t\tvar mana_to_subtract: float = creep.get_overall_mana() / 3\n\t\tcreep.subtract_mana(mana_to_subtract, false)\n\t\tcreep.get_player().display_floating_text(tr(\"CREEP_SPECIAL_SECOND_CHANCE\"), creep, Color.RED)\n\n#\t\tNOTE: this is how it works in original game. Need to\n#\t\tmodify lowest health so that the creep deals less\n#\t\tportal damage after reviving.\n\t\tcreep._lowest_health = creep.get_health() * creep.get_mana_ratio()\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_semi-mechanical.gd",
    "content": "class_name CreepSemiMechanical extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_semi_mechanical\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.50, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_slow.gd",
    "content": "class_name CreepSlow extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_slow\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.33, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_slow_aura.gd",
    "content": "class_name CreepSlowAura extends BuffType\n\n\nvar slow_aura_effect: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_slow_aura\", 0, 0, true, parent)\n\n\tvar draw_below_unit: bool = true\n\tset_special_effect(\"res://src/effects/spell_aire_flat.tscn\", 0, 1.0, Color.ORANGE, draw_below_unit)\n\t\n\tslow_aura_effect = BuffType.create_aura_effect_type(\"creep_slow_aura_effect\", false, self)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.50, 0.0)\n\tslow_aura_effect.set_buff_modifier(modifier)\n\tslow_aura_effect.set_buff_tooltip(tr(\"ZW9E\"))\n\n\tadd_aura(108, self)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_speed.gd",
    "content": "class_name CreepSpeed extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_speed\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.25, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_spell_resistance.gd",
    "content": "class_name CreepSpellResistance extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_spell_resistance\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, -0.50, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_spellbinder.gd",
    "content": "class_name CreepSpellbinder extends BuffType\n\n# NOTE: this special is not affected by silence, on purpose.\n# This is how it was in the original game.\n\n\nvar silence_bt: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_spellbinder\", 0, 0, true, parent)\n\n\tsilence_bt = CbSilence.new(\"silence_bt\", 0, 0, false, self)\n\n\tadd_periodic_event(on_periodic, 5.0)\n\n\nfunc on_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tvar I: Iterate = Iterate.over_units_in_range_of_caster(creep, TargetType.new(TargetType.TOWERS), 1100.0)\n\n\tvar zap_count: int = 0\n\n\twhile true:\n\t\tvar tower: Unit = I.next_random()\n\n\t\tif tower == null:\n\t\t\tbreak\n\n\t\tif zap_count >= 3:\n\t\t\tbreak\n\n\t\tif creep.get_mana() < 50:\n\t\t\tbreak\n\n\t\tcreep.subtract_mana(50, true)\n\n\t\tvar stolen_mana: float = tower.get_overall_mana() * 0.3\n\t\tcreep.add_mana(stolen_mana)\n\t\ttower.subtract_mana(stolen_mana, true)\n\n\t\tsilence_bt.apply_only_timed(creep, tower, 5.0) \n\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, creep, tower)\n\t\tlightning.modulate = Color.PURPLE\n\t\tlightning.set_lifetime(0.2)\n\n\t\tzap_count += 1\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_strong.gd",
    "content": "class_name CreepStrong extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_strong\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_EXP_GRANTED, 0.50, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, 0.25, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_stun_revenge.gd",
    "content": "class_name CreepStunRevenge extends BuffType\n\n\nvar stun_bt: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_stun_revenge\", 0, 0, true, parent)\n\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\tstun_bt.set_special_effect(\"res://src/effects/shackle.tscn\", 50, 1.0, Color(Color.GOLD, 0.75))\n\n\tadd_event_on_attacked(on_attacked)\n\n\nfunc on_attacked(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar attacker: Unit = event.get_target()\n\t\n\tvar creep_is_silenced: bool = creep.is_silenced()\n\tif creep_is_silenced:\n\t\treturn\n\n\tvar stun_success: bool = creep.calc_chance(0.3)\n\tif stun_success:\n\t\tstun_bt.apply_only_timed(creep, attacker, 3.0)\n\n\t\tSFX.sfx_at_unit(SfxPaths.MAGIC_FIZZLE, attacker)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_ultra_wisdom.gd",
    "content": "class_name CreepUltraWisdom extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_ultra_wisdom\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, -1.0, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_EXP_GRANTED, 2.0, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH, -1.0, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_unlucky.gd",
    "content": "class_name CreepUnlucky extends BuffType\n\n\nvar unlucky_active: BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_unlucky\", 0, 0, true, parent)\n\n\tadd_event_on_damaged(on_damaged)\n\n\tunlucky_active = BuffType.new(\"unlucky_active\", 8.0, 0, false, self\n\t\t)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.0, -0.001)\n\tunlucky_active.set_buff_modifier(modifier)\n\tunlucky_active.set_buff_icon(\"res://resources/icons/generic_icons/aquarius.tres\")\n\tunlucky_active.set_buff_icon_color(Color.YELLOW)\n\n\nfunc on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar attacker: Unit = event.get_target()\n\tvar creep_is_silenced: bool = creep.is_silenced()\n\n\tif creep_is_silenced:\n\t\treturn\n\n\tif !creep.calc_chance(0.30):\n\t\treturn\n\n\tvar active_buff: Buff = attacker.get_buff_of_type(unlucky_active)\n\n\tif active_buff != null:\n\t\tactive_buff = unlucky_active.apply(creep, attacker, active_buff.get_level() + 10)\n\t\tactive_buff.refresh_duration()\n\telse:\n\t\tactive_buff = unlucky_active.apply(creep, attacker, 10)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_xtreme_armor.gd",
    "content": "class_name CreepXtremeArmor extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_xtreme_armor\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_ARMOR, 100, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_ARMOR_PERC, 4.0, 0.0)\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.25, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_xtreme_evasion.gd",
    "content": "class_name CreepXtremeEvasion extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_xtreme_evasion\", 0, 0, true, parent)\n\tadd_event_on_damaged(on_damaged)\n\n\nfunc on_damaged(event: Event):\n\tCreepEvasion.evasion_effect(event, 0.66)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_xtreme_regeneration.gd",
    "content": "class_name CreepXtremeRegeneration extends BuffType\n\n\nvar _regen_ratio_map: Dictionary = {\n\tCreepSize.enm.MASS: 0.175,\n\tCreepSize.enm.NORMAL: 0.0875,\n\tCreepSize.enm.AIR: 0.1,\n\tCreepSize.enm.CHAMPION: 0.078,\n\tCreepSize.enm.BOSS: 0.025,\n\tCreepSize.enm.CHALLENGE_MASS: 0.0,\n\tCreepSize.enm.CHALLENGE_BOSS: 0.0,\n}\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_xtreme_regeneration\", 0, 0, true, parent)\n\tadd_event_on_create(on_create)\n\n\nfunc on_create(event: Event):\n\tCreepRegeneration.regen_special_on_create(event, _regen_ratio_map)\n"
  },
  {
    "path": "src/creeps/special_buffs/creep_xtreme_speed.gd",
    "content": "class_name CreepXtremeSpeed extends BuffType\n\n\nfunc _init(parent: Node):\n\tsuper(\"creep_extreme_speed\", 0, 0, true, parent)\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, 10.0, 0.0)\n\tset_buff_modifier(modifier)\n"
  },
  {
    "path": "src/creeps/special_icons/CreepArmoredSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cqcgv22udnpjb\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_g8uxl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bce4dy61dykla\" path=\"res://resources/icons/generic_icons/armor_vest.tres\" id=\"2_jr3jv\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_g8uxl\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.843137, 0.807843, 1, 1)\nshader_parameter/base_colour = Color(0.305882, 0.317647, 0.333333, 1)\n\n[node name=\"CreepArmoredSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 48.0\noffset_bottom = 48.0\ntexture = ExtResource(\"2_jr3jv\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepBroodySpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://daynfndxtkpr0\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_uht4p\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cdqtd51r814ka\" path=\"res://resources/icons/generic_icons/egg.tres\" id=\"2_xbww4\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_uht4p\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.596078, 0, 0.168627, 1)\nshader_parameter/base_colour = Color(0.164706, 0, 0, 1)\n\n[node name=\"CreepBroodySpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_xbww4\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepDartSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://lsm1meqw5plt\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_j57ju\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c3yr4au2yukn\" path=\"res://resources/icons/generic_icons/perpendicular_rings.tres\" id=\"2_fkvl1\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_j57ju\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.964706, 0, 0.529412, 1)\nshader_parameter/base_colour = Color(0.164706, 0, 0, 1)\n\n[node name=\"CreepDartSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_fkvl1\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepEtherealSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://7u1b6otikkd1\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_1gfta\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://yri0380ravrp\" path=\"res://resources/icons/generic_icons/aries.tres\" id=\"2_pjmpl\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_1gfta\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.529412, 0.984314, 0.431373, 1)\nshader_parameter/base_colour = Color(0.164706, 0, 0, 1)\n\n[node name=\"CreepEtherialSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_pjmpl\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepEvasionSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cs1i1aup8oku0\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_8kp88\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cqi7jcn16pgoc\" path=\"res://resources/icons/generic_icons/ophiucus.tres\" id=\"2_c6drv\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_8kp88\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.819608, 0.776471, 0.639216, 1)\nshader_parameter/base_colour = Color(1, 1, 1, 1)\n\n[node name=\"CreepEvasionSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_c6drv\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepEvolvingSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://20g14dk04wbr\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_5gto3\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://6ytfhd8i1ve5\" path=\"res://resources/icons/generic_icons/amber_mosquito.tres\" id=\"2_wqomj\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_5gto3\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.447059, 0.321569, 0, 1)\nshader_parameter/base_colour = Color(0.964706, 0.862745, 0, 1)\n\n[node name=\"CreepEvolvingSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_wqomj\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepFireballSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://u8qsr7dpevfr\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_j5kvo\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://csbk40h1qfx2g\" path=\"res://resources/icons/generic_icons/burning_dot.tres\" id=\"2_hg65t\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_j5kvo\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.811765, 0, 0, 1)\nshader_parameter/base_colour = Color(0.945098, 0.67451, 0, 1)\n\n[node name=\"CreepFireballSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_hg65t\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepFlockSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cotc3khp8au0o\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_8x0cx\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://1qm7k37swric\" path=\"res://resources/icons/generic_icons/bat_mask.tres\" id=\"2_koyul\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_8x0cx\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.486275, 0.592157, 0.886275, 1)\nshader_parameter/base_colour = Color(0.0705882, 0.113725, 0.262745, 1)\n\n[node name=\"CreepFlockSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_koyul\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepGhostSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://blv4rp01buw1r\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_7ygsy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://br1e4jv3ceixt\" path=\"res://resources/icons/generic_icons/ghost.tres\" id=\"2_x7h7m\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_7ygsy\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 1, 1, 1)\nshader_parameter/base_colour = Color(0.662745, 0.67451, 0.694118, 1)\n\n[node name=\"CreepGhostSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_x7h7m\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepGravidSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://wtkqviwbxgnv\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_4utae\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bybxbjvfd64tr\" path=\"res://resources/icons/generic_icons/alien_skull.tres\" id=\"2_jxar2\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_4utae\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.345098, 0, 0.352941, 1)\nshader_parameter/base_colour = Color(1, 0.466667, 1, 1)\n\n[node name=\"CreepGravidSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_jxar2\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepGreaterSpeedSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dfr13kgj7x2wi\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_a77wb\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://btvgi5m658qtv\" path=\"res://resources/icons/generic_icons/sprint.tres\" id=\"2_lhs0j\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_a77wb\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.443137, 0.282353, 1)\nshader_parameter/base_colour = Color(1, 0.733333, 0.733333, 1)\n\n[node name=\"CreepGreaterSpeedSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_lhs0j\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepGreaterSpellResistanceSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://88r7lbtw8j3r\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_1y4hv\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://2drii204c2r3\" path=\"res://resources/icons/generic_icons/azul_flake.tres\" id=\"2_fcuen\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_1y4hv\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.968627, 0.498039, 1, 1)\nshader_parameter/base_colour = Color(0.713726, 1, 0.960784, 1)\n\n[node name=\"CreepGreaterSpellResistanceSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_fcuen\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepHeavyArmoredSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://w4kid3fh4sm3\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_ursof\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://s0bsohkidpi6\" path=\"res://resources/icons/generic_icons/chest_armor.tres\" id=\"2_1t8c4\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_ursof\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.690196, 0.596078, 1, 1)\nshader_parameter/base_colour = Color(0.305882, 0.317647, 0.333333, 1)\n\n[node name=\"CreepHeavyArmoredSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_1t8c4\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepInvisibleSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://c4mrni3vclgri\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_oybwv\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bl4odykcddi37\" path=\"res://resources/icons/generic_icons/semi_closed_eye.tres\" id=\"2_i07h1\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_oybwv\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.662745, 1, 0, 1)\nshader_parameter/base_colour = Color(0.784314, 0.796078, 0.788235, 1)\n\n[node name=\"CreepInvisibleSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_i07h1\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepMagicImmunitySpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://da1jhpmr42kfl\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_kbsv5\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cfimexaqalwcy\" path=\"res://resources/icons/generic_icons/star_swirl.tres\" id=\"2_mg8p0\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_kbsv5\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.972549, 0, 1, 1)\nshader_parameter/base_colour = Color(0, 0.933333, 0.862745, 1)\n\n[node name=\"CreepMagicImmunitySpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_mg8p0\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepManaDrainAuraSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://gcxxjeh33ae2\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_fvjuy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cjwek0aj8k6pw\" path=\"res://resources/icons/generic_icons/atomic_slashes.tres\" id=\"2_8kvlq\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_fvjuy\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.819608, 0, 1)\nshader_parameter/base_colour = Color(1, 1, 1, 1)\n\n[node name=\"CreepManaDrainAuraSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_8kvlq\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepManaShieldPlusSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bka1n2hcj67db\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_jnwb4\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://beq6yjrsvld5e\" path=\"res://resources/icons/generic_icons/shiny_omega.tres\" id=\"2_5qpam\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_jnwb4\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0, 0.156863, 1, 1)\nshader_parameter/base_colour = Color(0.643137, 0.996078, 1, 1)\n\n[node name=\"CreepManaShieldPlusSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_5qpam\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepManaShieldSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://rvdqm8u4j5bw\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_g4hk1\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://xcruhv1n8wnd\" path=\"res://resources/icons/generic_icons/omega.tres\" id=\"2_b5sp3\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_g4hk1\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.14902, 0.380392, 1, 1)\nshader_parameter/base_colour = Color(0.752941, 0.882353, 1, 1)\n\n[node name=\"CreepManaShieldSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_b5sp3\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepMeatySpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://b6u8nl8ranvuf\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_dgh1u\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dyaarp6hgeswd\" path=\"res://resources/icons/generic_icons/meat.tres\" id=\"2_wy7id\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_dgh1u\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.721569, 0, 1)\nshader_parameter/base_colour = Color(0.756863, 0.121569, 0.109804, 1)\n\n[node name=\"CreepMeatySpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_wy7id\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepMechanicalSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cl1lu8ba1cs0j\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_k21nl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b37u11w37lqw0\" path=\"res://resources/icons/generic_icons/pokecog.tres\" id=\"2_dpggw\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_k21nl\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 1, 1, 1)\nshader_parameter/base_colour = Color(0.486275, 0.592157, 0.886275, 1)\n\n[node name=\"CreepMechanicalSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_dpggw\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepNecromancerSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://drdhv6karit1p\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_7qeiv\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dhbxbxuk7n8kk\" path=\"res://resources/icons/generic_icons/animal_skull.tres\" id=\"2_3aiik\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_7qeiv\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0, 0.941176, 0, 1)\nshader_parameter/base_colour = Color(0, 0, 0, 1)\n\n[node name=\"CreepNecromancerSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_3aiik\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepProtectorSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://6cjvjiids6ld\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_fpx8o\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://digugf0f1udtb\" path=\"res://resources/icons/generic_icons/barbute.tres\" id=\"2_s7y24\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_fpx8o\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.756863, 0.592157, 0.403922, 1)\nshader_parameter/base_colour = Color(1, 0.894118, 0.709804, 1)\n\n[node name=\"CreepProtectorSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_s7y24\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepPurgeRevengeSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bymobm2m6y5n3\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_ck8fi\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bv7gu3v3jconv\" path=\"res://resources/icons/generic_icons/alligator_clip.tres\" id=\"2_jp5bk\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_ck8fi\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0, 0, 0, 1)\nshader_parameter/base_colour = Color(1, 1, 1, 1)\n\n[node name=\"CreepPurgeRevengeSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_jp5bk\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepRegenerationSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dlnhiv421w7ni\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_wfe1e\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bqmpxcpl04uem\" path=\"res://resources/icons/generic_icons/angel_outfit.tres\" id=\"2_urtyd\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_wfe1e\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.380392, 0.552941, 0.341176, 1)\nshader_parameter/base_colour = Color(0.803922, 0.933333, 0.552941, 1)\n\n[node name=\"CreepRegenerationSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_urtyd\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepRelicRaiderSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://d0sr0hwd5ljut\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_keaus\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cp2vrv08ceg4b\" path=\"res://resources/icons/generic_icons/holy_grail.tres\" id=\"2_2i6ua\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_keaus\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0, 0.0862745, 0, 1)\nshader_parameter/base_colour = Color(0.984314, 0.890196, 0.188235, 1)\n\n[node name=\"CreepRelicRaiderSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_2i6ua\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepRichSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://5wgj1anon2fx\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_a0vt6\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c3lshombp5ddb\" path=\"res://resources/icons/generic_icons/gold_bar.tres\" id=\"2_brup6\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_a0vt6\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.564706, 0, 1)\nshader_parameter/base_colour = Color(0.984314, 0.890196, 0, 1)\n\n[node name=\"CreepRichSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_brup6\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSecondChanceSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://c7r6urhr0bgya\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_3rxja\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cxttw8oegbi1v\" path=\"res://resources/icons/generic_icons/ankh.tres\" id=\"2_pcybo\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_3rxja\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.843137, 0.733333, 1)\nshader_parameter/base_colour = Color(0, 0, 0, 1)\n\n[node name=\"CreepSecondChanceSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_pcybo\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSemiMechanicalSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bhsl4h3i1yovg\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_7sf1x\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://d3o7wv5cxj5lo\" path=\"res://resources/icons/generic_icons/cog.tres\" id=\"2_tsjmv\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_7sf1x\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.756863, 0.756863, 0.756863, 1)\nshader_parameter/base_colour = Color(0.364706, 0.47451, 0.815686, 1)\n\n[node name=\"CreepSemiMechanicalSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_tsjmv\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSlowAuraSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://c277lcbi08qem\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_s8gel\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cghaedw51shn4\" path=\"res://resources/icons/generic_icons/moebius_trefoil.tres\" id=\"2_oh3hr\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_s8gel\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0, 0, 0, 1)\nshader_parameter/base_colour = Color(0.733333, 0.501961, 0.501961, 1)\n\n[node name=\"CreepSlowAuraSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_oh3hr\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSlowSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bf783dn7rl3wl\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_6nmdr\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dy6pmoeog7xwx\" path=\"res://resources/icons/generic_icons/turtle_shell.tres\" id=\"2_dc605\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_6nmdr\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.0784314, 0.576471, 1, 1)\nshader_parameter/base_colour = Color(0.733333, 1, 0.733333, 1)\n\n[node name=\"CreepSlowSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_dc605\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSpeedSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://ctvqljbi8gaig\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_lxlko\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c52golqtdlvcf\" path=\"res://resources/icons/generic_icons/barefoot.tres\" id=\"2_s7yqn\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_lxlko\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.52549, 0.627451, 1)\nshader_parameter/base_colour = Color(1, 0.733333, 0.733333, 1)\n\n[node name=\"CreepSpeedSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_s7yqn\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSpellResistanceSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dpa6pagrtlhrw\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_j2soa\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://d1vbf1m1dlxcu\" path=\"res://resources/icons/generic_icons/polar_star.tres\" id=\"2_ad7qo\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_j2soa\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.996078, 0.670588, 1, 1)\nshader_parameter/base_colour = Color(0.643137, 1, 0.952941, 1)\n\n[node name=\"CreepSpellResistanceSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_ad7qo\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepSpellbinderSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cvjv71rohr7u8\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_731wp\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://d3chlr7i32uae\" path=\"res://resources/icons/generic_icons/aquarius.tres\" id=\"2_efe5x\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_731wp\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.819608, 0, 1)\nshader_parameter/base_colour = Color(1, 1, 1, 1)\n\n[node name=\"CreepSpellbinderSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_efe5x\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepStrongSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://c3obl8kagogr2\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_s7xmn\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bndmfop66ljoa\" path=\"res://resources/icons/generic_icons/biceps.tres\" id=\"2_7nvgj\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_s7xmn\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0, 0, 1)\nshader_parameter/base_colour = Color(0.784314, 0.796078, 0.788235, 1)\n\n[node name=\"CreepStrongSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_7nvgj\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepStunRevengeSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://s8v6e6200qmu\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_quycq\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dxwtuus1sd40x\" path=\"res://resources/icons/generic_icons/pisces.tres\" id=\"2_ovin3\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_quycq\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.819608, 0, 1)\nshader_parameter/base_colour = Color(1, 1, 1, 1)\n\n[node name=\"CreepStunRevengeSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_ovin3\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepUltraWisdomSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dj53clib3ccy8\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_dxw3i\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://xjkqhdkmldw0\" path=\"res://resources/icons/generic_icons/beard.tres\" id=\"2_7mq6o\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_dxw3i\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.529412, 0.984314, 0.431373, 1)\nshader_parameter/base_colour = Color(0.164706, 0, 0, 1)\n\n[node name=\"CreepUltraWisdomSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_7mq6o\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepUnluckySpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bpo0ohs6kxb12\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_emcc2\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bo0c4w2nvf7q7\" path=\"res://resources/icons/generic_icons/over_infinity.tres\" id=\"2_2kqaj\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_emcc2\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.756863, 0.592157, 1, 1)\nshader_parameter/base_colour = Color(0.890196, 0.976471, 0.533333, 1)\n\n[node name=\"CreepUnluckySpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_2kqaj\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepXtremeArmorSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dnvqrleh2gjhj\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_xd3tm\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://g6kxhqq1cbfk\" path=\"res://resources/icons/generic_icons/abdominal_armor.tres\" id=\"2_vuq6y\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_xd3tm\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(0.576471, 0.431373, 1, 1)\nshader_parameter/base_colour = Color(0.305882, 0.317647, 0.333333, 1)\n\n[node name=\"CreepXtremeArmoredSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_vuq6y\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepXtremeEvasionSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://brhl7dbsapvbb\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_s2wu0\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dxwtuus1sd40x\" path=\"res://resources/icons/generic_icons/pisces.tres\" id=\"2_aayl8\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_s2wu0\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.819608, 0, 1)\nshader_parameter/base_colour = Color(1, 1, 1, 1)\n\n[node name=\"CreepXtremeEvasionSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_aayl8\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepXtremeRegenerationSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bbxsym4jt0o0b\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_sd4vg\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bqmpxcpl04uem\" path=\"res://resources/icons/generic_icons/angel_outfit.tres\" id=\"2_36bme\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_sd4vg\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.835294, 0.12549, 1)\nshader_parameter/base_colour = Color(0.952941, 0.92549, 0.760784, 1)\n\n[node name=\"CreepXtremeRegenerationSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_36bme\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/special_icons/CreepXtremeSpeedSpecial.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bj5byjt5pu5md\"]\n\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/glowing_outline_2.gdshader\" id=\"1_voecc\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cmfyy8y822jj7\" path=\"res://resources/icons/generic_icons/fire_dash.tres\" id=\"2_itdwn\"]\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_haw6a\"]\nresource_local_to_scene = true\nshader = ExtResource(\"1_voecc\")\nshader_parameter/max_line_width = 3.0\nshader_parameter/min_line_width = 2.08165e-12\nshader_parameter/freq = 10.0\nshader_parameter/block_size = 4.0\nshader_parameter/outline_colour = Color(1, 0.188235, 0.439216, 1)\nshader_parameter/base_colour = Color(1, 0.733333, 0.733333, 1)\n\n[node name=\"CreepXtremeSpeedSpecial\" type=\"TextureRect\"]\nmodulate = Color(1, 0.117647, 1, 1)\nmaterial = SubResource(\"ShaderMaterial_haw6a\")\ncustom_minimum_size = Vector2(16, 16)\noffset_right = 16.0\noffset_bottom = 16.0\ntexture = ExtResource(\"2_itdwn\")\nexpand_mode = 3\n"
  },
  {
    "path": "src/creeps/wave.gd",
    "content": "class_name Wave\nextends Node\n\n\nenum State {\n\tPENDING,\n\tSPAWNING,\n\tSPAWNED,\n\tFINISHED,\n}\n\nsignal finished()\n\n\nconst _size_chances: Dictionary = {\n\tCreepSize.enm.MASS: 15,\n\tCreepSize.enm.NORMAL: 50,\n\tCreepSize.enm.AIR: 15,\n\tCreepSize.enm.BOSS: 20,\n}\n\nconst _champion_count_chances: Dictionary = {\n\tCreepSize.enm.MASS: {\n\t\t0: 70,\n\t\t1: 30,\n\t},\n\tCreepSize.enm.NORMAL: {\n\t\t0: 42.5,\n\t\t1: 30,\n\t\t2: 20,\n\t\t3: 7.5,\n\t},\n\tCreepSize.enm.AIR: {\n\t\t0: 100,\n\t},\n\tCreepSize.enm.BOSS: {\n\t\t0: 100,\n\t},\n}\n\n\nvar _alive_creep_list: Array[Creep] = []\nvar _level: int\nvar _race: CreepCategory.enm\nvar _armor_type: ArmorType.enm\nvar state: Wave.State = Wave.State.PENDING\nvar _specials: Array[int] = []\nvar _base_hp: float = 0.0\nvar _base_armor: float = 0.0\nvar _creep_combination: Array[CreepSize.enm]\nvar _creep_size: CreepSize.enm\n\n\n#########################\n### Code starts here  ###\n#########################\n\nfunc _init(level: int, difficulty: int):\n\t_level = level\n\t_creep_size = Wave._generate_creep_size(_level)\n\t_race = Wave._generate_creep_race(_creep_size)\n\t_armor_type = Wave._get_random_armor_type(_level, _creep_size)\n\t_creep_combination = Wave._generate_creep_combination(_level, _creep_size)\n\tvar wave_has_champions: bool = _creep_combination.has(CreepSize.enm.CHAMPION)\n\t_specials = WaveSpecial.get_random(_level, _creep_size, wave_has_champions)\n\t_base_hp = Wave._calculate_base_hp(_level, difficulty, _armor_type)\n\t_base_armor = Wave._calculate_base_armor(_level, difficulty)\n\n#\tNOTE: double the amount of creeps when wave special is\n#\t\"Flock\"\n\tif _specials.has(WaveSpecialProperties.FLOCK):\n\t\tvar original_combination: Array[CreepSize.enm] = _creep_combination.duplicate()\n\n\t\tfor creep_size in original_combination:\n\t\t\t_creep_combination.append(creep_size)\n\n\nfunc _ready():\n\tset_name(\"Wave\")\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_creep_tree_exited(creep: Creep):\n\t_alive_creep_list.erase(creep)\n\n\tif _alive_creep_list.is_empty() && state == Wave.State.SPAWNED:\n\t\tstate = Wave.State.FINISHED\n\t\tfinished.emit()\n\n\n#########################\n### Setters / Getters ###\n#########################\n\n\n# Returns a list of scenes used by creeps in this wave\nfunc get_used_scene_list() -> Array[String]:\n\tvar scene_list: Array[String] = []\n\n\tfor creep_size in _creep_combination:\n\t\tvar scene_name: String = Wave.get_scene_name_for_creep_type(creep_size, _race)\n\n\t\tif !scene_list.has(scene_name):\n\t\t\tscene_list.append(scene_name)\n\n\treturn scene_list\n\n\nfunc get_creep_race() -> CreepCategory.enm:\n\treturn _race\n\n\nfunc get_creep_size() -> CreepSize.enm:\n\treturn _creep_size\n\n\n# Returns an array of CreepSize enm.that should be spawned\n# in the same order as they are stored in this array.\nfunc get_creep_combination() -> Array[CreepSize.enm]:\n\treturn _creep_combination\n\n\nfunc get_creep_count() -> int:\n\treturn _creep_combination.size()\n\n\n# [MASS, MASS, MASS, CHAMPION]\n# =>\n# \"3 Mass, 1 Champion\"\nfunc get_creep_combination_string() -> String:\n\tvar is_final_boss: bool = _level == Utils.get_max_level()\n\tif is_final_boss:\n\t\treturn \"[color=GOLD]%s[/color]\" % tr(\"FINAL_BOSS_TEXT\")\n\n\tvar size_count_map: Dictionary = {}\n\n\tfor size in _creep_combination:\n\t\tif !size_count_map.has(size):\n\t\t\tsize_count_map[size] = 0\n\n\t\tsize_count_map[size] += 1\n\n#\tNOTE: champions go first, order for other sizes doesn't\n#\tmatter\n\tvar size_list_ordered: Array[CreepSize.enm] = [CreepSize.enm.CHAMPION, CreepSize.enm.NORMAL, CreepSize.enm.AIR, CreepSize.enm.MASS, CreepSize.enm.BOSS, CreepSize.enm.CHALLENGE_MASS, CreepSize.enm.CHALLENGE_BOSS]\n\n\tvar string_split: Array[String] = []\n\n\tfor size in size_list_ordered:\n\t\tif !size_count_map.has(size):\n\t\t\tcontinue\n\n\t\tvar count: int = size_count_map[size]\n\t\tvar size_string: String = CreepSize.convert_to_colored_string(size)\n\t\tvar count_and_size_string: String = \"[color=GOLD]%d[/color] %s\" % [count, size_string]\n\n\t\tstring_split.append(count_and_size_string)\n\n\tvar combination_string: String = \", \".join(string_split)\n\n\treturn combination_string\n\n\n# Armor type of the creeps\nfunc get_armor_type() -> ArmorType.enm:\n\treturn _armor_type\n\n\nfunc get_level() -> int:\n\treturn _level\n\n\nfunc get_specials() -> Array[int]:\n\treturn _specials\n\n\nfunc get_race() -> CreepCategory.enm:\n\treturn _race\n\n\n# Returns an array of possible Creep sizes\n# which can be spawned in this wave\nfunc get_creep_sizes() -> Array[CreepSize.enm]:\n\tvar result: Array[CreepSize.enm] = []\n\tvar creep_combination: Array[CreepSize.enm] = get_creep_combination()\n\n\tfor creep_size in creep_combination:\n\t\tif !result.has(creep_size):\n\t\t\tresult.append(creep_size)\n\t\n\treturn result\n\n\nfunc get_base_hp() -> float:\n\tif Config.override_creep_health() != 0:\n\t\tvar override_creep_health: float = Config.override_creep_health()\n\n\t\treturn override_creep_health\n\n\treturn _base_hp\n\n\nfunc get_base_armor() -> float:\n\treturn _base_armor\n\n\nfunc add_alive_creep(creep: Creep):\n\t_alive_creep_list.append(creep)\n\tcreep.tree_exited.connect(_on_creep_tree_exited.bind(creep))\n\n\n# Calculates base HP for a Creep based on \n# the wave level \nstatic func _calculate_base_hp(level: int, difficulty: Difficulty.enm, armor_type: ArmorType.enm) -> float:\n\tvar a: float\n\tvar b: float\n\tvar c: float\n\tvar d: float\n\tvar e: float\n\tvar f: float\n\tvar g: float\n\n\tmatch difficulty:\n\t\tDifficulty.enm.BEGINNER:\n\t\t\ta = 29 * 1.2\n\t\t\tb = 20 * 1.6\n\t\t\tc = 1.4 * 1.3\n\t\t\td = 0.015\n\t\t\te = 0.0001\n\t\t\tf = 0.000007 * 1.9\n\t\t\tg = 0.000000011\n\t\tDifficulty.enm.EASY:\n\t\t\ta = 35 * 1.2\n\t\t\tb = 26 * 1.6\n\t\t\tc = 1.6 * 1.3\n\t\t\td = 0.018\n\t\t\te = 0.0003\n\t\t\tf = 0.000009 * 1.9\n\t\t\tg = 0.000000012\n\t\tDifficulty.enm.MEDIUM:\n\t\t\ta = 42 * 1.2\n\t\t\tb = 33 * 1.6\n\t\t\tc = 1.8 * 1.3\n\t\t\td = 0.021\n\t\t\te = 0.0005\n\t\t\tf = 0.000011 * 1.9\n\t\t\tg = 0.000000013\n\t\tDifficulty.enm.HARD:\n\t\t\ta = 50 * 1.2\n\t\t\tb = 41 * 1.6\n\t\t\tc = 2.0 * 1.3\n\t\t\td = 0.024\n\t\t\te = 0.0008\n\t\t\tf = 0.000013 * 1.9\n\t\t\tg = 0.000000015\n\t\tDifficulty.enm.EXTREME:\n\t\t\ta = 59 * 1.2\n\t\t\tb = 50 * 1.6\n\t\t\tc = 2.2 * 1.3\n\t\t\td = 0.027\n\t\t\te = 0.001\n\t\t\tf = 0.000015 * 1.9\n\t\t\tg = 0.000000018\n\n\tvar wave_is_bonus: bool = Utils.wave_is_bonus(level)\n\n#\tNOTE: extra hp multiplier can be found in jass code but\n#\tit's located far from the code which implements the main\n#\thealth formula. Search for \"(.9-\" strings to find it in\n#\tmultiple locations.\n\tvar extra_hp_multiplier: float = (0.9 - (level * 0.002))\n\t\n#\tNOTE: this formula gradually reverses the direction of\n#\textra_hp_multiplier from decreasing to increasing and\n#\tfinally to exponential\n\tif wave_is_bonus:\n\t\textra_hp_multiplier += pow(1.0001, pow((level - Constants.WAVE_COUNT_NEVERENDING) / 2.0, 2.4)) - 1.0\n\n\tvar j: int = level - 1\n\tvar health: float = a + j * (b + j * (c + j * (d + j * (e + j * (f + j * g)))))\n\thealth = health * extra_hp_multiplier\n\n\tif armor_type == ArmorType.enm.SIF:\n\t\thealth *= Constants.SIF_CREEP_HEALTH_MULTIPLIER\n\n\treturn health\n\n\n# NOTE: base armor for waves is rounded down - this is\n# intentional and how it works in original game\nstatic func _calculate_base_armor(level: int, difficulty: Difficulty.enm) -> float:\n\tvar a: float\n\tvar b: float\n\tvar c: float\n\n\tmatch difficulty:\n\t\tDifficulty.enm.BEGINNER:\n\t\t\ta = 0\n\t\t\tb = 0.26\n\t\t\tc = 0\n\t\tDifficulty.enm.EASY:\n\t\t\ta = 2\n\t\t\tb = 0.28\n\t\t\tc = 0\n\t\tDifficulty.enm.MEDIUM:\n\t\t\ta = 4\n\t\t\tb = 0.3\n\t\t\tc = 0\n\t\tDifficulty.enm.HARD:\n\t\t\ta = 6\n\t\t\tb = 0.32\n\t\t\tc = 0.0004\n\t\tDifficulty.enm.EXTREME:\n\t\t\ta = 8\n\t\t\tb = 0.34\n\t\t\tc = 0.001\n\n\tvar j: int = level - 1\n\tvar base_armor: float = floor(a + j * (b + j * c))\n\n\treturn base_armor\n\n\nstatic func _generate_creep_race(creep_size: CreepSize.enm) -> CreepCategory.enm:\n\tvar override_creep_race_string: String = Config.override_creep_race()\n\tif !override_creep_race_string.is_empty():\n\t\tvar override_creep_race: CreepCategory.enm = CreepCategory.from_string(override_creep_race_string)\n\n\t\treturn override_creep_race\n\n\tvar size_is_challenge: bool = CreepSize.is_challenge(creep_size)\n\n\tif size_is_challenge:\n\t\treturn CreepCategory.enm.CHALLENGE\n\n\tvar race_list: Array[CreepCategory.enm] = [\n\t\tCreepCategory.enm.UNDEAD,\n\t\tCreepCategory.enm.MAGIC,\n\t\tCreepCategory.enm.NATURE,\n\t\tCreepCategory.enm.ORC,\n\t\tCreepCategory.enm.HUMANOID,\n\t]\n\n\tvar random_race: CreepCategory.enm = Utils.pick_random(Globals.synced_rng, race_list)\n\n\treturn random_race\n\n\nstatic func _generate_creep_size(level: int) -> CreepSize.enm:\n\tvar override_creep_size_string: String = Config.override_creep_size()\n\tif !override_creep_size_string.is_empty():\n\t\tvar override_creep_size: CreepSize.enm = CreepSize.from_string(override_creep_size_string)\n\n\t\treturn override_creep_size\n\n\tvar challenge: bool = (level % 8) == 0\n\tvar challenge_mass: bool = (level % 120) % 16 == 0 && (level % 120) != 0\n\n\tif challenge:\n\t\tif challenge_mass:\n\t\t\treturn CreepSize.enm.CHALLENGE_MASS\n\t\telse:\n\t\t\treturn CreepSize.enm.CHALLENGE_BOSS\n\telse:\n\t\tvar random_regular_creep: CreepSize.enm = Utils.random_weighted_pick(Globals.synced_rng, _size_chances)\n\n\t\treturn random_regular_creep\n\n\nstatic func _get_random_armor_type(wave_level: int, creep_size: CreepSize.enm) -> ArmorType.enm:\n\tvar override_creep_armor_string: String = Config.override_creep_armor()\n\tif !override_creep_armor_string.is_empty():\n\t\tvar override_creep_armor: ArmorType.enm = ArmorType.from_string(override_creep_armor_string)\n\n\t\treturn override_creep_armor\n\n\tvar is_challenge: bool = CreepSize.is_challenge(creep_size)\n\n\tif is_challenge:\n\t\treturn ArmorType.enm.ZOD\n\n\tvar regular_armor_list: Array = [\n\t\tArmorType.enm.HEL,\n\t\tArmorType.enm.MYT,\n\t\tArmorType.enm.LUA,\n\t\tArmorType.enm.SOL,\n\t]\n\n\tvar can_spawn_sif: bool = wave_level >= 32\n\n\tif can_spawn_sif && Utils.rand_chance(Globals.synced_rng, Constants.SIF_ARMOR_CHANCE):\n\t\treturn ArmorType.enm.SIF\n\telse:\n\t\tvar random_regular_armor: ArmorType.enm = Utils.pick_random(Globals.synced_rng, regular_armor_list)\n\n\t\treturn random_regular_armor\n\n\n# Generates a creep combination. If wave contains champions,\n# then champions are inserted in regular intervals between\n# other creeps.\nstatic func _generate_creep_combination(wave_level: int, creep_size: CreepSize.enm) -> Array[CreepSize.enm]:\n\tvar combination: Array[CreepSize.enm] = []\n\n\tvar wave_capacity: int = 20 + wave_level / 40\n\tvar champion_count: int = _generate_champion_count(wave_level, creep_size)\n\tvar champion_weight: int = int(CreepSize.get_weight(CreepSize.enm.CHAMPION))\n\tvar unit_weight: int = int(CreepSize.get_weight(creep_size))\n\n\tvar total_unit_count: int = -1\n\tvar champion_unit_ratio: float = -1\n\tvar regular_unit_ratio: float = -1\n\n\tif creep_size == CreepSize.enm.CHALLENGE_BOSS:\n\t\ttotal_unit_count = 1\n\telif champion_count > 0:\n\t\ttotal_unit_count = (wave_capacity - champion_count * champion_weight) / unit_weight + champion_count\n\t\tchampion_unit_ratio = float(total_unit_count) / champion_count\n\t\tregular_unit_ratio = float(total_unit_count) / champion_count / 2\n\telse:\n\t\ttotal_unit_count = wave_capacity / unit_weight\n\n\tvar champion_count_so_far: int = 0\n\n\tfor k in range(0, total_unit_count):\n\t\tvar spawn_champion: bool = int(regular_unit_ratio + champion_unit_ratio * champion_count_so_far - 0.5) == k\n\n\t\tif spawn_champion:\n\t\t\tcombination.append(CreepSize.enm.CHAMPION)\n\t\t\tchampion_count_so_far = champion_count_so_far + 1\n\t\telse:\n\t\t\tcombination.append(creep_size)\n\n\treturn combination\n\n\nstatic func _generate_champion_count(wave_level: int, creep_size: CreepSize.enm) -> int:\n\tvar is_challenge: bool = CreepSize.is_challenge(creep_size)\n\n\tif is_challenge:\n\t\treturn 0\n\n\tvar chance_of_champion_count: Dictionary = _champion_count_chances[creep_size]\n\tvar champion_count: int = Utils.random_weighted_pick(Globals.synced_rng, chance_of_champion_count)\n\n\tif champion_count > 0:\n\t\tchampion_count = champion_count + int(wave_level / 120)\n\n\treturn champion_count\n\n\nstatic func get_scene_name_for_creep_type(creep_size: CreepSize.enm, creep_race: CreepCategory.enm) -> String:\n\tif creep_size == CreepSize.enm.CHALLENGE_BOSS:\n\t\treturn \"ChallengeBoss\"\n\telif creep_size == CreepSize.enm.CHALLENGE_MASS:\n\t\treturn \"ChallengeMass\"\n\n#\tNOTE: must use convert_to_string() which is non-display\n#\tstring here because this is for filename, so no\n#\ttranslation needed!\n\tvar creep_size_string: String = CreepSize.convert_to_string(creep_size)\n\tvar creep_race_string: String = CreepCategory.convert_to_string(creep_race)\n#\tNOTE: currently, all creep races use orc scenes. Loading\n#\tonly orc scenes because loading creep scenes is taking a\n#\tlong time in-game and it serves no purpose, because\n#\tagain, all creeps are orcs visually.\n# \tRemove this when other creep race scenes are added but\n# \tshould also improve perfomance so that loading creep\n# \tscenes doesn't lag the game.\n\tif Config.load_only_orc_scenes():\n\t\tcreep_race_string = CreepCategory.convert_to_string(CreepCategory.enm.ORC)\n\tvar scene_name: String = creep_race_string.capitalize() + creep_size_string.capitalize()\n\n\treturn scene_name\n"
  },
  {
    "path": "src/creeps/wave_path.gd",
    "content": "class_name WavePath extends Path2D\n\n\n@export var is_air: bool\n@export var player_id: int\n\n\nfunc _ready():\n\tadd_to_group(\"wave_paths\")\n"
  },
  {
    "path": "src/creeps/wave_spawner.gd",
    "content": "class_name WaveSpawner extends Node\n\n\nsignal wave_spawned(level: int)\nsignal wave_finished(level: int)\n\n\nvar _wave_list: Array[Wave] = []\nvar _current_wave: Wave = null\nvar _player: Player = null\n\n@export var _creep_spawner: CreepSpawner\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_wave(level: int) -> Wave:\n\tvar index: int = level - 1\n\n\tvar in_bounds: bool = 0 <= index && index < _wave_list.size()\n\n\tif in_bounds:\n\t\tvar wave: Wave = _wave_list[index]\n\n\t\treturn wave\n\telse:\n\t\treturn null\n\n\nfunc set_player(player: Player):\n\t_player = player\n\t_creep_spawner.set_player(player)\n\n\nfunc generate_waves():\n\tvar wave_count: int = Globals.get_wave_count()\n\t_generate_waves_for_level_range(1, wave_count)\n\n\nfunc start_wave(level: int):\n\tvar wave: Wave = get_wave(level)\n\t\n\tif wave == null:\n\t\tpush_error(\"Failed to start wave #%d because it's null\" % level)\n\t\t\n\t\treturn\n\t\n\twave.state = Wave.State.SPAWNING\n\n\t_current_wave = wave\n\n\t_creep_spawner.start_spawning_wave(wave)\n\t\n\t_add_message_about_wave(wave)\n\t\n\tprint_verbose(\"Wave has started [%s].\" % wave)\n\n\nfunc current_wave_is_finished() -> bool:\n\tif _current_wave == null:\n\t\treturn true\n\n\tvar is_finished: bool = _current_wave.state == Wave.State.FINISHED\n\n\treturn is_finished\n\n\nfunc wave_is_finished(level: int) -> bool:\n\tvar wave: Wave = get_wave(level)\n\n\tif wave == null:\n\t\treturn false\n\n\tvar is_finished: bool = wave.state == Wave.State.FINISHED\n\n\treturn is_finished\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _generate_waves_for_level_range(level_start: int, wave_count: int):\n\tvar difficulty: Difficulty.enm = Globals.get_difficulty()\n\n\tfor wave_level in range(level_start, level_start + wave_count):\n\t\tvar wave: Wave = Wave.new(wave_level, difficulty)\n\t\t_wave_list.append(wave)\n\t\twave.finished.connect(_on_wave_finished.bind(wave))\n\t\tadd_child(wave, true)\n\n\tvar should_print_wave_info: bool = Config.print_wave_info()\n\tif should_print_wave_info:\n\t\t_print_wave_info()\n\n\nfunc _print_wave_info():\n\tfor wave in _wave_list:\n\t\tvar wave_level: int = wave.get_level()\n\t\tvar creep_combination_string: String = wave.get_creep_combination_string()\n\n\t\tvar special_name_list: Array[String] = []\n\t\tfor special in wave.get_specials():\n\t\t\tvar special_name: String = WaveSpecialProperties.get_special_name(special)\n\t\t\tspecial_name_list.append(special_name)\n\n\t\tvar specials_string: String\n\t\tif !special_name_list.is_empty():\n\t\t\tspecials_string = \",\".join(special_name_list)\n\t\telse:\n\t\t\tspecials_string = \"none\"\n\n\t\tprint(\"Wave [%s] will have creeps [%s] of race [%s] and armor type [%s]\" % [wave_level, creep_combination_string, CreepCategory.get_display_string(wave.get_race()), ArmorType.get_display_string(wave.get_armor_type())])\n\t\tprint(\"    Specials: %s\" % specials_string)\n\n\t\tvar creep_size_list: Array = wave.get_creep_sizes()\n\n\t\tfor creep_size in creep_size_list:\n\t\t\tvar creep_health: float = CreepSpawner.get_creep_health(wave, creep_size)\n\t\t\tvar creep_size_string: String = CreepSize.get_display_string(creep_size)\n\t\t\tprint(\"%s's HP: %s\" % [creep_size_string, creep_health])\n\n#\t\tNOTE: need to add delay between prints to avoid\n#\t\toverflowing the console. Console overflow is not\n#\t\tcritical but it does cut off the messages.\n\t\tif wave_level % 20 == 0:\n\t\t\tawait get_tree().create_timer(0.1).timeout\n\n\nfunc _add_message_about_wave(wave: Wave):\n\tif _player != PlayerManager.get_local_player():\n\t\treturn\n\t\n\tvar combination_string: String = wave.get_creep_combination_string()\n\n\tvar creep_race: CreepCategory.enm = wave.get_race()\n\tvar race_string: String = CreepCategory.convert_to_colored_string(creep_race)\n\n\tvar creep_armor: ArmorType.enm = wave.get_armor_type()\n\tvar armor_string: String = ArmorType.convert_to_colored_string(creep_armor)\n\n\tvar wave_level: int = wave.get_level()\n\tvar wave_is_bonus: int = Utils.wave_is_bonus(wave_level)\n\tvar wave_header_text: String\n\tif !wave_is_bonus:\n\t\twave_header_text = tr(\"MESSAGE_WAVE_LEVEL\").format({LEVEL = wave_level})\n\telse:\n\t\twave_header_text = tr(\"MESSAGE_WAVE_LEVEL_BONUS\").format({LEVEL = wave_level})\n\n\tMessages.add_normal(_player, wave_header_text)\n\tMessages.add_normal(_player, tr(\"MESSAGE_WAVE_PROPS\").format({CREEP_COMBINATION = combination_string, RACE = race_string, ARMOR = armor_string}))\n\n\tvar special_list: Array[int] = wave.get_specials()\n\n\tfor special in special_list:\n\t\tvar special_name: String = WaveSpecialProperties.get_special_name(special)\n\t\tvar description: String = WaveSpecialProperties.get_description(special)\n\t\tvar special_string: String = \"[color=BLUE]%s[/color] - %s\" % [special_name, description]\n\n\t\tMessages.add_normal(_player, special_string)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_creep_spawner_all_creeps_spawned():\n\tif _current_wave == null:\n\t\treturn\n\n\t_current_wave.state = Wave.State.SPAWNED\n\tvar level: int = _current_wave.get_level()\n\twave_spawned.emit(level)\n\tprint_verbose(\"Wave has been spawned [%s].\" % _current_wave)\n\n\nfunc _on_wave_finished(wave: Wave):\n\tvar team: Team = _player.get_team()\n\tvar finished_the_game: bool = team.finished_the_game()\n\tif finished_the_game:\n\t\treturn\n\n\tvar level: int = wave.get_level()\n\twave_finished.emit(level)\n\n# \tKeep generating extra waves in neverending mode\n\tvar game_is_neverending: bool = Globals.game_is_neverending()\n\tif game_is_neverending:\n\t\tvar last_generated_level: int = _wave_list.back().get_level()\n\t\tvar distance_to_last_generated_wave: int = last_generated_level - level\n\n\t\tif distance_to_last_generated_wave < 20:\n\t\t\t_generate_waves_for_level_range(last_generated_level + 1, 20)\n"
  },
  {
    "path": "src/creeps/wave_spawner.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bah0cloqblp5n\"]\n\n[ext_resource type=\"Script\" path=\"res://src/creeps/wave_spawner.gd\" id=\"1_isnnd\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b80b85lbixydk\" path=\"res://src/creeps/creep_spawner.tscn\" id=\"2_rvsq0\"]\n\n[node name=\"WaveSpawner\" type=\"Node\" node_paths=PackedStringArray(\"_creep_spawner\")]\nscript = ExtResource(\"1_isnnd\")\n_creep_spawner = NodePath(\"CreepSpawner\")\n\n[node name=\"CreepSpawner\" parent=\".\" instance=ExtResource(\"2_rvsq0\")]\n\n[connection signal=\"all_creeps_spawned\" from=\"CreepSpawner\" to=\".\" method=\"_on_creep_spawner_all_creeps_spawned\"]\n"
  },
  {
    "path": "src/effects/ancient_protector_missile.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://b7caj5bx5chdf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dwdvvm6bwoxfw\" path=\"res://assets/effects/bdragon/ancient_protector_missile_293.png\" id=\"1_dtt27\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d71op\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nkfj8\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_161ok\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_omscn\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8behb\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j2joj\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e7c86\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lbpsi\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fqmbo\"]\natlas = ExtResource(\"1_dtt27\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_pupj3\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d71op\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nkfj8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_161ok\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_omscn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8behb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j2joj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e7c86\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lbpsi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fqmbo\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"AncientProtectorMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_pupj3\")\nframe_progress = 0.185146\n"
  },
  {
    "path": "src/effects/animated_dead_target.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://g0d3fiham0sk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4t5ody7wg6wa\" path=\"res://assets/effects/bdragon/animated_dead_target_102.png\" id=\"1_a2uqr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d4ipg\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yt6nb\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b00yj\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j4cl5\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mq865\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yqbu1\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_abyq1\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2ne80\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8okl7\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v8dlw\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pm4ug\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(640, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3a8p1\"]\natlas = ExtResource(\"1_a2uqr\")\nregion = Rect2(704, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_y3yei\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d4ipg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yt6nb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b00yj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j4cl5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mq865\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yqbu1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_abyq1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2ne80\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8okl7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v8dlw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pm4ug\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3a8p1\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"AnimatedDeadTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_y3yei\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/apply_potion.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://bbf1c5ci54rq7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bvcsmcf7c2lf8\" path=\"res://assets/effects/bdragon/apply_potion_537.png\" id=\"1_f5a57\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5n06j\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_byw1w\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_awbl5\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_672yt\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7g7kt\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y1173\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lhkp8\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0c47g\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o33j3\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7466c\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sbi70\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ixtki\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a5hu1\"]\natlas = ExtResource(\"1_f5a57\")\nregion = Rect2(768, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_evfuv\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5n06j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_byw1w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_awbl5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_672yt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7g7kt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y1173\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lhkp8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0c47g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o33j3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7466c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sbi70\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ixtki\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a5hu1\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"ApplyPotion\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_evfuv\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/effects/arcane_tower_attack.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://bgciop3ybbla1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4xwqnjdc1ipo\" path=\"res://assets/effects/bdragon/arcane_tower_attack_024.png\" id=\"1_jh6a2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4fat0\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yrx5f\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5tqu6\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hbyh7\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eti3x\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q7dm0\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ywcr\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xfip6\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_epp1p\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8m7xa\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bhpjs\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ip4ja\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c28qr\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2boyy\"]\natlas = ExtResource(\"1_jh6a2\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_c3hhn\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4fat0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yrx5f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5tqu6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hbyh7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eti3x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q7dm0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3ywcr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xfip6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_epp1p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8m7xa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bhpjs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ip4ja\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c28qr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2boyy\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"ArcaneTowerAttack\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_c3hhn\")\n"
  },
  {
    "path": "src/effects/arcane_tower_attack_flat.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://b74645564x2rj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c4xwqnjdc1ipo\" path=\"res://assets/effects/bdragon/arcane_tower_attack_024.png\" id=\"1_fefxl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ebq2y\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_il6u3\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b6rxe\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ctskr\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_js1is\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4jngu\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rjdwu\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gj7ok\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qxgp2\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i5nbd\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_46s1s\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mpwh6\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5tvd3\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xp0g5\"]\natlas = ExtResource(\"1_fefxl\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_nl1h5\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ebq2y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_il6u3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b6rxe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ctskr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_js1is\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4jngu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rjdwu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gj7ok\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qxgp2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i5nbd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_46s1s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mpwh6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5tvd3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xp0g5\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"ArcaneTowerAttackFlat\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_nl1h5\")\n"
  },
  {
    "path": "src/effects/avatar_caster.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://ci6751l13nudt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bpanfd3kpr8y7\" path=\"res://assets/effects/bdragon/avatar_caster_10.png\" id=\"1_bnj11\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8gbya\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_75m3w\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nebk8\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_or21k\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7483e\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g1bn4\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3x001\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_54yes\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nxk42\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f6wqs\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c0k7o\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3s4y8\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tu3mi\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(768, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hqlwq\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(832, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kasfb\"]\natlas = ExtResource(\"1_bnj11\")\nregion = Rect2(896, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_kekuo\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8gbya\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_75m3w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nebk8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_or21k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7483e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g1bn4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3x001\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_54yes\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nxk42\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f6wqs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c0k7o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3s4y8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tu3mi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hqlwq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kasfb\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"AvatarCaster\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_kekuo\")\n"
  },
  {
    "path": "src/effects/banshee_missile.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://bkpf10l0dy061\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c1q82fl7tji4e\" path=\"res://assets/effects/bdragon/banshee_missile_487.png\" id=\"1_m6kd1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d4kjn\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g2cak\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ujfg\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r5jgl\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cv5he\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4np4p\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r57wi\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o8aak\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aw6hk\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b4wso\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_va830\"]\natlas = ExtResource(\"1_m6kd1\")\nregion = Rect2(640, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_dwuiq\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d4kjn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g2cak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ujfg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r5jgl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cv5he\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4np4p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r57wi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o8aak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aw6hk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b4wso\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_va830\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"BansheeMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_dwuiq\")\noffset = Vector2(0, 5)\n"
  },
  {
    "path": "src/effects/barrel.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://iyviqm3y5a2q\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://itq2i72y2h0w\" path=\"res://resources/misc/barrel.tres\" id=\"1_wcjpj\"]\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_8r1yn\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": ExtResource(\"1_wcjpj\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 5.0\n}]\n\n[node name=\"barrel\" type=\"AnimatedSprite2D\"]\nsprite_frames = SubResource(\"SpriteFrames_8r1yn\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/effects/blink_target.tscn",
    "content": "[gd_scene load_steps=23 format=3 uid=\"uid://bqwrfx4gm8ur7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://l77fhcp00n6l\" path=\"res://assets/effects/bdragon/blink_target_720.png\" id=\"1_0lj67\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w24ex\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_moks2\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1w8gu\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_spvuf\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rk7fi\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ccp7\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wri8p\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mkgck\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pwe6x\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vn8pu\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sevqp\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lau5y\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_203wg\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ue1ew\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7p14t\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(896, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8s0ov\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(960, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_48xt4\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(1024, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pw7ak\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(1088, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8mmns\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(1152, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o6rjf\"]\natlas = ExtResource(\"1_0lj67\")\nregion = Rect2(1216, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_va45q\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w24ex\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_moks2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1w8gu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_spvuf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rk7fi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ccp7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wri8p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mkgck\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pwe6x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vn8pu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sevqp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lau5y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_203wg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ue1ew\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7p14t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8s0ov\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_48xt4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pw7ak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8mmns\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o6rjf\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"BlinkTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_va45q\")\n"
  },
  {
    "path": "src/effects/blood_splatter.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://djhj3tmsnmjua\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cueu6nx32scn\" path=\"res://assets/effects/bdragon/blood_splatter_376.png\" id=\"1_7dy51\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ffvbt\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nn3wr\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u3o23\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jwiir\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rxi3f\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fx6op\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w4su3\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jv0sx\"]\natlas = ExtResource(\"1_7dy51\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_fhqgd\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ffvbt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nn3wr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u3o23\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jwiir\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rxi3f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fx6op\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w4su3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jv0sx\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"BloodSplatter\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 0.06, 0.06, 1)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_fhqgd\")\n"
  },
  {
    "path": "src/effects/build_tower.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://cy4uhju281nqs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dng7ptld4y130\" path=\"res://assets/effects/bdragon/build_tower_648.png\" id=\"1_2fucf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_up3nf\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u83yy\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4vq0c\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4s0yj\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xdv52\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2jyxo\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v0owr\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_npx3t\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7lxwn\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kwmb2\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ep27l\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xch5m\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i8o0q\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(768, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_okuyw\"]\natlas = ExtResource(\"1_2fucf\")\nregion = Rect2(832, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_3tyis\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_up3nf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u83yy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4vq0c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4s0yj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xdv52\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2jyxo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v0owr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_npx3t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7lxwn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kwmb2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ep27l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xch5m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i8o0q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_okuyw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 40.0\n}]\n\n[node name=\"BuildTower\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_3tyis\")\n"
  },
  {
    "path": "src/effects/charm_target.tscn",
    "content": "[gd_scene load_steps=25 format=3 uid=\"uid://cek1qdno751sb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c75jmqs4u7hnv\" path=\"res://assets/effects/bdragon/charm_target_703.png\" id=\"1_1tipi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oxb6b\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lxnj0\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4pe8i\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o2toh\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vkl0v\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_knjn3\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ex8na\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hemmp\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p750o\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t3ayd\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3cfl0\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_48q5k\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_beusq\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p2we2\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ajm21\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(896, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j04hu\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(960, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hy2ij\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(1024, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w7bxr\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(1088, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8afcw\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(1152, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vgavu\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(1216, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4d7q5\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(1280, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jfbeg\"]\natlas = ExtResource(\"1_1tipi\")\nregion = Rect2(1344, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_tgw63\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oxb6b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lxnj0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4pe8i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o2toh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vkl0v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_knjn3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ex8na\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hemmp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p750o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t3ayd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3cfl0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_48q5k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_beusq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p2we2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ajm21\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j04hu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hy2ij\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w7bxr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8afcw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vgavu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4d7q5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jfbeg\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"CharmTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_tgw63\")\n"
  },
  {
    "path": "src/effects/chimaera_acid.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://c6i4cmhc3c8my\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c22lkk5uieshi\" path=\"res://assets/effects/bdragon/freezing_breath_519.png\" id=\"1_c6rpb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t7tvl\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_obaoj\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2sktu\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8d3c3\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h7px3\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mhike\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sy2kp\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_48fcq\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gal16\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ft1iu\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(576, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4usnv\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(640, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0atpr\"]\natlas = ExtResource(\"1_c6rpb\")\nregion = Rect2(704, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_6qi7j\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t7tvl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_obaoj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2sktu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8d3c3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h7px3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mhike\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sy2kp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_48fcq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gal16\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ft1iu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4usnv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0atpr\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"ChimaeraAcid\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_6qi7j\")\n"
  },
  {
    "path": "src/effects/cloud_of_fog_cycle.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://b1sjijjdpnr1r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dhm5njivfgxpo\" path=\"res://assets/effects/bdragon/cloud_of_fog_382.png\" id=\"1_pr31m\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c1f4r\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nkcgb\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hv5dv\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vprnd\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ign78\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_scbr7\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y3468\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4cpke\"]\natlas = ExtResource(\"1_pr31m\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ocar1\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c1f4r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nkcgb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hv5dv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vprnd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ign78\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_scbr7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y3468\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4cpke\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 10.0\n}]\n\n[node name=\"CloudOfFogCycle\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(5, 5)\nsprite_frames = SubResource(\"SpriteFrames_ocar1\")\nframe_progress = 0.540459\n"
  },
  {
    "path": "src/effects/cloud_of_fog_small.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://dip8vxqytpavb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://m4w03jglmnu1\" path=\"res://assets/effects/bdragon/cloud_of_fog_small_428.png\" id=\"1_j8cn1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bj0ph\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2yppv\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t5oxt\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2mora\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_01tpa\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7545u\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s0tnu\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_huko8\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pm7lp\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mht78\"]\natlas = ExtResource(\"1_j8cn1\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_pm8ay\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bj0ph\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2yppv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t5oxt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2mora\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_01tpa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7545u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s0tnu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_huko8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pm7lp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mht78\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"CloudOfFogSmall\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(4, 4)\nsprite_frames = SubResource(\"SpriteFrames_pm8ay\")\nframe_progress = 0.372588\n"
  },
  {
    "path": "src/effects/cripple_target.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://ccodrffahp8tj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://crdvk0hy3x3px\" path=\"res://assets/effects/bdragon/cripple_target_198.png\" id=\"1_cpj8v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lgq3s\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nfulb\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_boenl\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_74dha\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_soji6\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_52am6\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sv0v4\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gemns\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_24754\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1q7ng\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d1uu5\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(640, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uvq1y\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(704, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bwuid\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(768, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4k5bo\"]\natlas = ExtResource(\"1_cpj8v\")\nregion = Rect2(832, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_muy4r\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lgq3s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nfulb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_boenl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_74dha\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_soji6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_52am6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sv0v4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gemns\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_24754\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1q7ng\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d1uu5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uvq1y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bwuid\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4k5bo\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 10.0\n}]\n\n[node name=\"CrippleTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_muy4r\")\nframe_progress = 0.218859\n"
  },
  {
    "path": "src/effects/crushing_wave.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://cq8xe3fb6xuxr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bxvpwc34g1fgw\" path=\"res://assets/effects/bdragon/crushing_wave_damage_584.png\" id=\"1_caqbs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pwhyi\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x2rd6\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cwltl\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o0dv1\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s2gca\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4dtag\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8k7ha\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u8h8y\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m7epd\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bdqy3\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wpncf\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yrt1a\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lqe0e\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s32l5\"]\natlas = ExtResource(\"1_caqbs\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_psb4e\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pwhyi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x2rd6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cwltl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o0dv1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s2gca\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4dtag\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8k7ha\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u8h8y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m7epd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bdqy3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wpncf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yrt1a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lqe0e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s32l5\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"CrushingWave\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_psb4e\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/crypt_fiend_eggsack.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://dg2rixdb7aj6f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cvu38ecsot0h2\" path=\"res://assets/effects/bdragon/crypt_fiend_eggsack_528.png\" id=\"1_h2p80\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bgn62\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xkubf\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qu6ft\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cae27\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wv873\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p1cxe\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kormx\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_reyo0\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_icltg\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m5683\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(576, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qyt78\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(640, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ubj1h\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(704, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xc8jw\"]\natlas = ExtResource(\"1_h2p80\")\nregion = Rect2(768, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ejq8q\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bgn62\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xkubf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qu6ft\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cae27\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wv873\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p1cxe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kormx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_reyo0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_icltg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m5683\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qyt78\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ubj1h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xc8jw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"CryptFiendEggsack\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_ejq8q\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/effects/cyclone_target.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://bgdjeu5jssgol\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d4e4pstgsefwc\" path=\"res://assets/effects/bdragon/cyclone_target_269.png\" id=\"1_7d2tp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0mw5a\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ki783\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cit7g\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fibwm\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j35mx\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pg7nk\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d1vvc\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7tak5\"]\natlas = ExtResource(\"1_7d2tp\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_dwxxm\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0mw5a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ki783\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cit7g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fibwm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j35mx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pg7nk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d1vvc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7tak5\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"CycloneTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_dwxxm\")\n"
  },
  {
    "path": "src/effects/death_and_decay.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://dsffc5jrrdshf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8w3beqtm72u\" path=\"res://assets/effects/bdragon/death_and_decay_71.png\" id=\"1_872xf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ynnvo\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ctu4a\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7nlbp\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_blb5m\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dloox\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ql04f\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f0jbw\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3o1eh\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7tdll\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jnoj0\"]\natlas = ExtResource(\"1_872xf\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_lb34n\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ynnvo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ctu4a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7nlbp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_blb5m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dloox\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ql04f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f0jbw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3o1eh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7tdll\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jnoj0\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"DeathAndDecay\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_lb34n\")\n"
  },
  {
    "path": "src/effects/death_coil.tscn",
    "content": "[gd_scene load_steps=26 format=3 uid=\"uid://dgolqtowte6ol\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cbmu8xdosr3xw\" path=\"res://assets/effects/bdragon/death_coil_special_728.png\" id=\"1_t04v8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k2e0n\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uokek\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i4p6x\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_epb70\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0o0o6\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u1vgt\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gt4ey\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g2yny\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u3lk1\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ck2vq\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i6mm4\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(640, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gmm02\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(704, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rnnoh\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(768, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ink0m\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(832, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6r6f2\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(896, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mol63\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(960, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7c21s\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1024, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uh8hr\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1088, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sk6lb\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1152, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0ojw0\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1216, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1jnyc\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1280, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3u8r6\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1344, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gp8pb\"]\natlas = ExtResource(\"1_t04v8\")\nregion = Rect2(1408, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_nojri\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k2e0n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uokek\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i4p6x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_epb70\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0o0o6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u1vgt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gt4ey\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g2yny\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u3lk1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ck2vq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i6mm4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gmm02\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rnnoh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ink0m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6r6f2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mol63\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7c21s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uh8hr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sk6lb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0ojw0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1jnyc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3u8r6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gp8pb\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"DeathCoil\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_nojri\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/effects/death_explode.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://b7nt8wkq2674l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ctpc46l8ddp8n\" path=\"res://assets/effects/death_explode.png\" id=\"1_8bwr6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7ut7b\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 0, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_70y7o\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 32, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mblfv\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 64, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q4y38\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 96, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cpvjx\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 128, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0q04q\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 160, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lmk5h\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 192, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u7j6p\"]\natlas = ExtResource(\"1_8bwr6\")\nregion = Rect2(0, 224, 32, 32)\n\n[sub_resource type=\"SpriteFrames\" id=\"5\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7ut7b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_70y7o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mblfv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q4y38\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cpvjx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0q04q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lmk5h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u7j6p\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"DeathExplode\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 0.913725, 0.25098, 0.784314)\nscale = Vector2(1.333, 1)\nsprite_frames = SubResource(\"5\")\nframe_progress = 0.0517739\n"
  },
  {
    "path": "src/effects/devour.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://b3yf31o8mphom\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dqligfo47vxn1\" path=\"res://assets/effects/bdragon/devour_509.png\" id=\"1_4440m\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fb0tq\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hrjmx\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0ljqw\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hijwb\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qg533\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ipnd\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vmlci\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cpkfx\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lwefk\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q6k34\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qcpo8\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dyu4q\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_14aur\"]\natlas = ExtResource(\"1_4440m\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_2632c\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fb0tq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hrjmx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0ljqw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hijwb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qg533\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3ipnd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vmlci\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cpkfx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lwefk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q6k34\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qcpo8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dyu4q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_14aur\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"Devour\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_2632c\")\n"
  },
  {
    "path": "src/effects/dispel_magic_target.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://lyv8nkvods62\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://e2i8sa520qes\" path=\"res://assets/effects/bdragon/dispel_magic_target_456.png\" id=\"1_rvuxd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8f0f3\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1doih\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_68ytc\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hbfoh\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_482e0\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h3ucb\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pxbh2\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p516b\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_elg5g\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mxbj1\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2kwy8\"]\natlas = ExtResource(\"1_rvuxd\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_8pfav\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8f0f3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1doih\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_68ytc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hbfoh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_482e0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h3ucb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pxbh2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p516b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_elg5g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mxbj1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2kwy8\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"DispelMagicTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_8pfav\")\nframe = 8\nframe_progress = 0.0656656\n"
  },
  {
    "path": "src/effects/doom_death.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://bxoxandj44hx6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b7j12e3p73bqd\" path=\"res://assets/effects/bdragon/doom_death_451.png\" id=\"1_pq4kx\"]\n[ext_resource type=\"AudioStream\" uid=\"uid://cpc66xggsayen\" path=\"res://assets/sfx/michel_baradari_lava.ogg\" id=\"2_1ae74\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5t06c\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5q2yw\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mp0c6\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_chmld\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kftar\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_alvjn\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xr8q1\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_28xev\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1v43d\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g7asw\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bit6o\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(640, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xokin\"]\natlas = ExtResource(\"1_pq4kx\")\nregion = Rect2(704, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_xsd1p\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5t06c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5q2yw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mp0c6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_chmld\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kftar\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_alvjn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xr8q1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_28xev\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1v43d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g7asw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bit6o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xokin\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"DoomDeath\" type=\"AnimatedSprite2D\"]\nscale = Vector2(6, 3)\nsprite_frames = SubResource(\"SpriteFrames_xsd1p\")\n\n[node name=\"AudioStreamPlayer2D\" type=\"AudioStreamPlayer2D\" parent=\".\"]\nstream = ExtResource(\"2_1ae74\")\nautoplay = true\n"
  },
  {
    "path": "src/effects/effects_container.gd",
    "content": "extends Node2D\n\n\n# Stores effects as children and also maps them to id's. Use\n# globally via Effects autoload.\n\n\n# Map active effects to integer id's\n# \n# NOTE: effect id's start from id 1 (instead of 0) so that\n# when effect id is 0 it is treated as invalid. 0 needs to\n# be invalid because some tower scripts require that by\n# initializing effect id vars to 0.\nvar _id_max: int = 1\nvar _effect_map: Dictionary = {}\nvar _effect_original_scale_map: Dictionary = {}\nvar _free_id_list: Array = []\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: effect must be an AnimatedSprite2D scene\nfunc create_animated(effect_path: String, effect_pos: Vector3, _facing: float) -> int:\n\tvar id: int = _create_internal(effect_path)\n\tvar effect: Node2D = _effect_map[id]\n\tvar pos_canvas: Vector2 = VectorUtils.wc3_to_canvas(effect_pos)\n\teffect.position = pos_canvas\n\tadd_child(effect)\n\teffect.play()\n\n\treturn id\n\n\nfunc create_simple_at_unit_attached(effect_path: String, unit: Unit, body_part: Unit.BodyPart, z_offset: float) -> int:\n\tvar id: int = _create_internal(effect_path)\n\tvar effect: Node2D = _effect_map[id]\n\n\tvar body_part_offset: Vector2 = unit.get_body_part_offset(body_part)\n\tbody_part_offset.y -= z_offset\n\teffect.offset += body_part_offset / effect.scale.y\n\n\tvar unit_visual: Node2D = unit.get_visual_node()\n\tif unit_visual != null:\n\t\tunit_visual.add_child(effect)\n\t\teffect.play()\n\telse:\n\t\tpush_error(\"Couldn't add effect to unit because unit_visual is null. Make sure that Unit._set_visual_node() is called before any possible effects.\")\n\n\treturn id\n\n\nfunc get_effect(effect_id: int) -> Node2D:\n\tif !_effect_map.has(effect_id):\n\t\treturn null\n\n#\tNOTE: effects maybe become invalid if unit which carries\n#\tthe effect dies. Then a timer for destroying effect may\n#\ttrigger a call to get_effect. In such cases, clean up\n#\tthe effect and return null.\n\tif !is_instance_valid(_effect_map[effect_id]):\n\t\t_effect_map.erase(effect_id)\n\n\t\treturn null\n\n\tvar effect: Node2D = _effect_map[effect_id]\n\n\treturn effect\n\n\nfunc get_effect_original_scale(effect_id: int) -> Vector2:\n\tif !_effect_original_scale_map.has(effect_id):\n\t\tpush_error(\"get_effect_original_scale() failed to find original effect scale\")\n\n\t\treturn Vector2.ONE\n\n\tvar original_scale: Vector2 = _effect_original_scale_map[effect_id]\n\n\treturn original_scale\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _create_internal(effect_path: String) -> int:\n\tvar effect_path_exists: bool = ResourceLoader.exists(effect_path)\n\n\tvar effect_scene: PackedScene\n\tif effect_path_exists:\n\t\teffect_scene = load(effect_path)\n\telse:\n\t\teffect_scene = Preloads.placeholder_effect_scene\n\n\t\tpush_error(\"Invalid effect path:\", effect_path, \". Using placeholder effect.\")\n\n\tvar effect: Node2D = effect_scene.instantiate()\n\n\tif !effect is AnimatedSprite2D:\n\t\tprint_debug(\"Effect scene must be AnimatedSprite2D. Effect path with problem:\", effect_path, \". Using placeholder effect.\")\n\n\t\teffect.queue_free()\n\t\teffect = Preloads.placeholder_effect_scene.instantiate()\n\n#\tSilence SFX children of effect node, if SFX are disabled\n#\tin settings\n\tvar sfx_are_enabled: bool = Settings.get_bool_setting(Settings.ENABLE_SFX)\n\tif !sfx_are_enabled:\n\t\tvar effect_child_list: Array[Node] = effect.get_children()\n\n\t\tfor effect_child in effect_child_list:\n\t\t\tif effect_child is AudioStreamPlayer2D || effect_child is AudioStreamPlayer:\n\t\t\t\teffect_child.autoplay = false\n\n\tvar enable_vfx: bool = Settings.get_bool_setting(Settings.ENABLE_VFX)\n\teffect.visible = enable_vfx\n\n\tvar id: int = _make_effect_id()\n\t_effect_map[id] = effect\n\t_effect_original_scale_map[id] = effect.scale\n\n\treturn id\n\n\nfunc _make_effect_id() -> int:\n\tif !_free_id_list.is_empty():\n\t\tvar id: int = _free_id_list.pop_back()\n\n\t\treturn id\n\telse:\n\t\tvar id: int = _id_max\n\t\t_id_max += 1\n\n\t\treturn id\n"
  },
  {
    "path": "src/effects/faerie_dragon_missile.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://ckc75bhlxyjjd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cuavhpswhvx4s\" path=\"res://assets/effects/bdragon/faerie_dragon_missile_482.png\" id=\"1_ipone\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fv4pb\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rypq6\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nrcw2\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tpyjc\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q7efe\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rauqc\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ti8vg\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oflan\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vvcc0\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aw8qb\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_haipm\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qi1ll\"]\natlas = ExtResource(\"1_ipone\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_vxulq\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fv4pb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rypq6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nrcw2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tpyjc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q7efe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rauqc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ti8vg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oflan\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vvcc0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aw8qb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_haipm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qi1ll\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FaerieDragonMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_vxulq\")\n"
  },
  {
    "path": "src/effects/firelord_death_explode.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://davhdbkgnhxpk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcgbhwc4vii7u\" path=\"res://assets/effects/bdragon/firelord_death_explode_77.png\" id=\"1_jg3f6\"]\n[ext_resource type=\"AudioStream\" uid=\"uid://b7lwjrggou2kv\" path=\"res://assets/sfx/442827__qubodup__fireball.ogg\" id=\"2_chcyt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7psvk\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k55ix\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rdcmc\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4sfa6\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sy5s3\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3vnjs\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8ej7y\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ix5y7\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_daswo\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d8b84\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4nerj\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(640, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qxy68\"]\natlas = ExtResource(\"1_jg3f6\")\nregion = Rect2(704, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_jup3m\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7psvk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k55ix\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rdcmc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4sfa6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sy5s3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3vnjs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8ej7y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ix5y7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_daswo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d8b84\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4nerj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qxy68\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FirelordDeathExplode\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_jup3m\")\n\n[node name=\"AudioStreamPlayer2D\" type=\"AudioStreamPlayer2D\" parent=\".\"]\nstream = ExtResource(\"2_chcyt\")\nautoplay = true\n"
  },
  {
    "path": "src/effects/flame_strike_embers.tscn",
    "content": "[gd_scene load_steps=20 format=3 uid=\"uid://bd1cpwcedufav\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ddtif7hi5hsjr\" path=\"res://assets/effects/bdragon/flame_strike_embers_702.png\" id=\"1_l2nug\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wl87s\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yq25k\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i8jfi\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_belfd\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kfn8j\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7pdrp\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1kamg\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2tkeh\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i2p4g\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_irp4h\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_py315\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(640, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b46sb\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(704, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x272q\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(768, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2rgit\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(832, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nngdo\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(896, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sg5xn\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(960, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2lapw\"]\natlas = ExtResource(\"1_l2nug\")\nregion = Rect2(1024, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_6jyyu\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wl87s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yq25k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i8jfi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_belfd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kfn8j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7pdrp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1kamg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2tkeh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i2p4g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_irp4h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_py315\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b46sb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x272q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2rgit\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nngdo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sg5xn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2lapw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"FlameStrikeEmbers\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_6jyyu\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/effects/flower_aura.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://cbbhsyg5lx04c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c78vkmjgqto8v\" path=\"res://assets/effects/bdragon/flower_aura_655.png\" id=\"1_24vkn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cybiw\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dqdfj\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fyynp\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ku0fk\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xrjgs\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7clxc\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_04tg6\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3caqb\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_13n50\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_71tfj\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(576, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f7x3n\"]\natlas = ExtResource(\"1_24vkn\")\nregion = Rect2(640, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_t4vsi\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cybiw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dqdfj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fyynp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ku0fk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xrjgs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7clxc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_04tg6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3caqb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_13n50\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_71tfj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f7x3n\")\n}],\n\"loop\": false,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"FlowerAura\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_t4vsi\")\n"
  },
  {
    "path": "src/effects/frag_boom_spawn.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://dv700loyarjl6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://yvx6sbavyr4p\" path=\"res://assets/effects/bdragon/frag_boom_spawn_426.png\" id=\"1_c056e\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tbsg6\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(0, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3bi8x\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(64, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bx5dm\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(128, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_56a07\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(192, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x4su2\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(256, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pldba\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(320, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3ydjl\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(384, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8f1hp\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(448, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_syvot\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(512, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tkrrw\"]\natlas = ExtResource(\"1_c056e\")\nregion = Rect2(576, 384, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_oah3o\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tbsg6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3bi8x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bx5dm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_56a07\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x4su2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pldba\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3ydjl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8f1hp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_syvot\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tkrrw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FragBoomSpawn\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_oah3o\")\nframe_progress = 0.718487\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/effects/freezing_breath.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://b6xc510pecjto\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c22lkk5uieshi\" path=\"res://assets/effects/bdragon/freezing_breath_519.png\" id=\"1_x73t7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4dg2m\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_glv7w\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bsjlp\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8t23j\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xdht4\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j7yn2\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gwjhr\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_clv04\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nox7l\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gjobo\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ihecd\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hyyeh\"]\natlas = ExtResource(\"1_x73t7\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_8b75q\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4dg2m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_glv7w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bsjlp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8t23j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xdht4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j7yn2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gwjhr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_clv04\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nox7l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gjobo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ihecd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hyyeh\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FreezingBreath\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_8b75q\")\n"
  },
  {
    "path": "src/effects/freezing_breath_purple.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://dmd0qdxhvb0ca\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c22lkk5uieshi\" path=\"res://assets/effects/bdragon/freezing_breath_519.png\" id=\"1_fg7gp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sc2ie\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s4ux5\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kipmj\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_earf8\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_po1j6\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j2k3b\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0umsg\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b6p1b\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1b3dq\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_itkjn\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pd28y\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i1owy\"]\natlas = ExtResource(\"1_fg7gp\")\nregion = Rect2(704, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_q657i\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sc2ie\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s4ux5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kipmj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_earf8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_po1j6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j2k3b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0umsg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b6p1b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1b3dq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_itkjn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pd28y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i1owy\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FreezingBreathPurple\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_q657i\")\n"
  },
  {
    "path": "src/effects/frost_armor_damage.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://b6wo728k513rb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ijncv7mjaq1q\" path=\"res://assets/effects/bdragon/frost_armor_damage_474.png\" id=\"1_cmcqp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dy0jx\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m5t2d\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5i7iy\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0ecng\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yy61w\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hl0no\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_egre0\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xq0ny\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wxth2\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0r5t4\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uxq5c\"]\natlas = ExtResource(\"1_cmcqp\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_usgri\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dy0jx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m5t2d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5i7iy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0ecng\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yy61w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hl0no\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_egre0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xq0ny\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wxth2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0r5t4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uxq5c\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FrostArmorDamage\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_usgri\")\n"
  },
  {
    "path": "src/effects/frost_armor_damage_purple.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://cyukhjvhwm8p5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ijncv7mjaq1q\" path=\"res://assets/effects/bdragon/frost_armor_damage_474.png\" id=\"1_mw0qm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7rr6y\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oerh5\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_poptb\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2ci7n\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ppdvm\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aijmc\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vv3tv\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_312s2\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bixgr\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mb586\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wb7wk\"]\natlas = ExtResource(\"1_mw0qm\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_dmtq4\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7rr6y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oerh5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_poptb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2ci7n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ppdvm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aijmc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vv3tv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_312s2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bixgr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mb586\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wb7wk\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"FrostArmorDamagePurple\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_dmtq4\")\n"
  },
  {
    "path": "src/effects/frost_bolt_missile.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://w4v40ecvuobv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cvxaisa1jliqu\" path=\"res://assets/effects/bdragon/frost_bolt_missile_063.png\" id=\"1_qhmyf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_30fya\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vq7ws\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0woco\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g3lyk\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_611hu\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c27se\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vl6ox\"]\natlas = ExtResource(\"1_qhmyf\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_v11v7\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_30fya\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vq7ws\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0woco\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g3lyk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_611hu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c27se\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vl6ox\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"FrostBoltMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_v11v7\")\n"
  },
  {
    "path": "src/effects/glaive.tscn",
    "content": "[gd_scene load_steps=21 format=3 uid=\"uid://d21tamnhvp66t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://204ebjk0432r\" path=\"res://assets/effects/bdragon/glaive_746.png\" id=\"1_8j6dx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v5mij\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i4702\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_honjl\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3fbj2\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_61nen\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_83iiv\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ofwie\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oq1sw\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_py341\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mtrom\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ma6y0\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fifra\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xc6h3\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(768, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1jt41\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(832, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cq03k\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(896, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7yilb\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(960, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sv86o\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(1024, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4yhos\"]\natlas = ExtResource(\"1_8j6dx\")\nregion = Rect2(1088, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_7a8aw\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v5mij\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i4702\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_honjl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3fbj2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_61nen\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_83iiv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ofwie\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oq1sw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_py341\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mtrom\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ma6y0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fifra\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xc6h3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1jt41\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cq03k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7yilb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sv86o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4yhos\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"Glaive\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_7a8aw\")\n"
  },
  {
    "path": "src/effects/gold_credit.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://c6quw8maco8ba\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bg6jx8tkf0t6l\" path=\"res://assets/effects/bdragon/gold_credit_88.png\" id=\"1_1yym6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wmtf3\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ufllw\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_64ypc\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8sk0o\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hvnpy\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_alnm1\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gqr8k\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c7w8v\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pdsst\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c0cld\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vqqj8\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7u51a\"]\natlas = ExtResource(\"1_1yym6\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_42d85\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wmtf3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ufllw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_64ypc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8sk0o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hvnpy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_alnm1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gqr8k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c7w8v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pdsst\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c0cld\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vqqj8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7u51a\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"GoldCredit\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 0.873333, 0.24, 1)\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_42d85\")\n"
  },
  {
    "path": "src/effects/healing_wave_target.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://dligwgua1y7i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c56ujjaxdg1my\" path=\"res://assets/effects/bdragon/healing_wave_target_453.png\" id=\"1_vsvcm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jfxu3\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ly6yu\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v5ca6\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qulq6\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5jrtc\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4kynm\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8pbe1\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2sr6i\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sgprc\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qpeum\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(576, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rctxn\"]\natlas = ExtResource(\"1_vsvcm\")\nregion = Rect2(640, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_22wvr\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jfxu3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ly6yu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v5ca6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qulq6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5jrtc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4kynm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8pbe1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2sr6i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sgprc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qpeum\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rctxn\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"HealingWaveTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_22wvr\")\n"
  },
  {
    "path": "src/effects/holy_bolt.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://bs40lw6xkpf0e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bfnbtlckgbnfs\" path=\"res://assets/effects/bdragon/holy_bolt_241.png\" id=\"1_vi0kc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gnq3a\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hcoco\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gcp4e\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r6b6h\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yxs87\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3u0j8\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iykam\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bbr3d\"]\natlas = ExtResource(\"1_vi0kc\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ych44\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gnq3a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hcoco\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gcp4e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r6b6h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yxs87\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3u0j8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iykam\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bbr3d\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"HolyBolt\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 4)\nsprite_frames = SubResource(\"SpriteFrames_ych44\")\noffset = Vector2(5, -18)\n"
  },
  {
    "path": "src/effects/holy_bolt_green.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://c0b5004kkobgi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bfnbtlckgbnfs\" path=\"res://assets/effects/bdragon/holy_bolt_241.png\" id=\"1_cbjmy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gj0l4\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5wchm\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3p1ld\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lstya\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ewwje\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ot7u\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xwrrp\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_difnr\"]\natlas = ExtResource(\"1_cbjmy\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_7b1us\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gj0l4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5wchm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3p1ld\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lstya\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ewwje\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ot7u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xwrrp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_difnr\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"HolyBoltGreen\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 4)\nsprite_frames = SubResource(\"SpriteFrames_7b1us\")\noffset = Vector2(-5, -18)\n"
  },
  {
    "path": "src/effects/howl_caster.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://hghu1sxl0so8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://blekt36dlhmd2\" path=\"res://assets/effects/bdragon/undead_dissipate_633.png\" id=\"1_04fi1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qqdhy\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_45dhf\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mu5a5\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h3fy3\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_isd8s\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tlnd1\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_74tmk\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2b05t\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u1d3a\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qmh3k\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v5pnm\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(640, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ggus3\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(704, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8003y\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(768, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mcwed\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(832, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oj5jc\"]\natlas = ExtResource(\"1_04fi1\")\nregion = Rect2(896, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_sksoq\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qqdhy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_45dhf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mu5a5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h3fy3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_isd8s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tlnd1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_74tmk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2b05t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_u1d3a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qmh3k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v5pnm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ggus3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8003y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mcwed\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oj5jc\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"HowlCaster\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(10, 5)\nsprite_frames = SubResource(\"SpriteFrames_sksoq\")\n"
  },
  {
    "path": "src/effects/immolation_damage.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://dfblikx15it53\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://hyqt8yi512yh\" path=\"res://assets/effects/bdragon/immolation_damage_541.png\" id=\"1_fpn0k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yv26w\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lxnhq\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7qyyr\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uf80b\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_punm6\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_we3e1\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w6fki\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xmpcs\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8t1rk\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xucrr\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1pfbp\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(640, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ffxa\"]\natlas = ExtResource(\"1_fpn0k\")\nregion = Rect2(704, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_abh3a\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yv26w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lxnhq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7qyyr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uf80b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_punm6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_we3e1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w6fki\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xmpcs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8t1rk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xucrr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1pfbp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ffxa\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ImmolationDamage\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_abh3a\")\nframe_progress = 0.660254\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/impale_hit_target.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://cjhffln1edi7x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tnlbuwsjjav0\" path=\"res://assets/effects/bdragon/impale_hit_target_529.png\" id=\"1_alffg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7k27h\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4gi8s\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0ifo2\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r2tcx\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s73h3\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_122u6\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5qvne\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_48vp5\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(448, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yycwo\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(512, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tgrbt\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(576, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gt1l6\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(640, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j5oro\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(704, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_33gbx\"]\natlas = ExtResource(\"1_alffg\")\nregion = Rect2(768, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_tnqt1\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7k27h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4gi8s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0ifo2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r2tcx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s73h3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_122u6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5qvne\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_48vp5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yycwo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tgrbt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gt1l6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j5oro\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_33gbx\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ImpaleHitTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_tnqt1\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/impale_target_dust.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://bh7b62sgak2g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brfqvsks7awtk\" path=\"res://assets/effects/bdragon/impale_target_dust_025.png\" id=\"1_pqqq5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ede5t\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(0, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gsr3q\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(64, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ok14\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(128, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_73bph\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(192, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4hkwp\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(256, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_50uyj\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(320, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ajhbn\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(384, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8y704\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(448, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iibh2\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(512, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pf5nq\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(576, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g4ofy\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(640, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yr4o7\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(704, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xgpeu\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(768, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_22yxg\"]\natlas = ExtResource(\"1_pqqq5\")\nregion = Rect2(832, 384, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_a1l7v\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ede5t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gsr3q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5ok14\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_73bph\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4hkwp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_50uyj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ajhbn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8y704\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iibh2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pf5nq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g4ofy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yr4o7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xgpeu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_22yxg\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ImpaleTargetDust\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_a1l7v\")\noffset = Vector2(0, -15)\n"
  },
  {
    "path": "src/effects/incinerate.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://di0emmxcceer4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cujsekapgggit\" path=\"res://assets/effects/bdragon/incinerate_76.png\" id=\"1_08c6g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ieplg\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eg2ce\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c88m6\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_poc6b\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_21h4t\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v0qs1\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fhcwl\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ik1v\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rtk1g\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w3jer\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0l6ne\"]\natlas = ExtResource(\"1_08c6g\")\nregion = Rect2(640, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_fgudu\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ieplg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eg2ce\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c88m6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_poc6b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_21h4t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v0qs1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fhcwl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ik1v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rtk1g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w3jer\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0l6ne\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"Incinerate\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_fgudu\")\n"
  },
  {
    "path": "src/effects/interpolated_sprite.gd",
    "content": "class_name InterpolatedSprite extends Node2D\n\n\n# Draws an AnimatedSprite2D between two units, or two\n# points. You can pass your own custom AnimatedSprite2D to\n# create() function.\n\n# NOTE: this is the analog of Lightning class in JASS\n# Lightning.createFromUnitToUnit() in JASS\n# Lightning.createFromUnitToPoint() in JASS\n# Lightning.createFromPointToUnit() in JASS\n# Lightning.createFromPointToPoint() in JASS\n# Instead do this:\n# InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, ...)\n\n\nconst LIGHTNING: String = \"res://src/sprites/lightning_animation.tscn\"\n\nvar _sprite_scene_path: String\nvar _start_unit: Unit\nvar _end_unit: Unit\nvar _last_start_pos: Vector2 = Vector2.ZERO\nvar _last_end_pos: Vector2 = Vector2.ZERO\nvar _sprite: AnimatedSprite2D\nvar _sprite_width: float\nvar _lifetime_timer: ManualTimer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar sprite_scene: PackedScene = load(_sprite_scene_path)\n\tvar sprite = sprite_scene.instantiate()\n\n\tif !sprite is AnimatedSprite2D:\n\t\tpush_error(\"InterpolatedSprite must receive a scene for AnimatedSprite2D type. Invalid scene: \", _sprite_scene_path)\n\t\t_sprite = null\n\n\t\treturn\n\n\t_sprite = sprite as AnimatedSprite2D\n\tadd_child(_sprite)\n\n\t_sprite_width = _get_sprite_width()\n\n\t_lifetime_timer = ManualTimer.new()\n\t_lifetime_timer.timeout.connect(_on_lifetime_timer_timeout)\n\tadd_child(_lifetime_timer)\n\t\n\t_update_transform()\n\n\nfunc _process(_delta: float):\n\t_update_transform()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_transform():\n\tif _sprite == null:\n\t\treturn\n\n# \tNOTE: if either of the units becomes invalid, use last\n# \tknown position of the unit\n# \tNOTE: use is_instance_valid() instead of\n# \tUtils.unit_is_valid() because we also want to keep track\n# \tof positions of dead units\n\tvar start_pos: Vector2\n\tif is_instance_valid(_start_unit):\n\t\tstart_pos = _start_unit.get_visual_position()\n\t\t_last_start_pos = start_pos\n\telse:\n\t\tstart_pos = _last_start_pos\n\n\tvar end_pos: Vector2\n\tif is_instance_valid(_end_unit):\n\t\tend_pos = _end_unit.get_visual_position()\n\t\t_last_end_pos = end_pos\n\telse:\n\t\tend_pos = _last_end_pos\n\t\n\tvar diff_vector: Vector2 = end_pos - start_pos\n\tvar middle: Vector2 = start_pos + diff_vector / 2\n\t\n\tvar sprite_target_width: float = diff_vector.length()\n\tvar sprite_scale: float = sprite_target_width / _sprite_width\n\tscale.x = sprite_scale\n#\tNOTE: make the line a bit wider if it's very long\n\tscale.y = max(1.0, sqrt(sprite_scale))\n\t\n\tposition = middle\n\trotation = diff_vector.angle()\n\nfunc _get_sprite_width() -> float:\n\tvar sprite_frames: SpriteFrames = _sprite.sprite_frames\n\tvar animation_list: Array = sprite_frames.get_animation_names()\n\t\n\tif animation_list.is_empty():\n\t\treturn 0\n\t\n\tvar animation: String = animation_list[0]\n\tvar frame_count: int = sprite_frames.get_frame_count(animation)\n\t\n\tif frame_count == 0:\n\t\treturn 0\n\t\n\tvar texture: Texture2D = sprite_frames.get_frame_texture(animation, 0)\n\tvar texture_width: float = texture.get_size().x\n\t\n\treturn texture_width\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_lifetime_timer_timeout():\n\tqueue_free()\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc set_lifetime(lifetime: float):\n\t_lifetime_timer.start(lifetime)\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func create_from_unit_to_unit(sprite_scene_path: String, start_unit: Unit, end_unit: Unit) -> InterpolatedSprite:\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite._create_internal(sprite_scene_path, start_unit, end_unit, Vector3.ZERO, Vector3.ZERO)\n\t\n\treturn interpolated_sprite\n\n\nstatic func create_from_point_to_point(sprite_scene_path: String, start_pos: Vector3, end_pos: Vector3) -> InterpolatedSprite:\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite._create_internal(sprite_scene_path, null, null, start_pos, end_pos)\n\t\n\treturn interpolated_sprite\n\n\nstatic func create_from_unit_to_point(sprite_scene_path: String, start_unit: Unit, end_pos: Vector3) -> InterpolatedSprite:\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite._create_internal(sprite_scene_path, start_unit, null, Vector3.ZERO, end_pos)\n\t\n\treturn interpolated_sprite\n\n\n\nstatic func create_from_point_to_unit(sprite_scene_path: String, start_pos: Vector3, end_unit: Unit) -> InterpolatedSprite:\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite._create_internal(sprite_scene_path, null, end_unit, start_pos, Vector3.ZERO)\n\t\n\treturn interpolated_sprite\n\n\nstatic func _create_internal(sprite_scene_path: String, start_unit: Unit, end_unit: Unit, start_pos_3d: Vector3, end_pos_3d: Vector3) -> InterpolatedSprite:\n\tvar start_pos: Vector2 = VectorUtils.wc3_to_canvas(start_pos_3d)\n\tvar end_pos: Vector2 = VectorUtils.wc3_to_canvas(end_pos_3d)\n\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite.new()\n\tinterpolated_sprite._sprite_scene_path = sprite_scene_path\n\tinterpolated_sprite._start_unit = start_unit\n\tinterpolated_sprite._end_unit = end_unit\n\tinterpolated_sprite._last_start_pos = start_pos\n\tinterpolated_sprite._last_end_pos = end_pos\n\tinterpolated_sprite.z_index = 1000\n\n\tUtils.add_object_to_world(interpolated_sprite)\n\n\treturn interpolated_sprite\n"
  },
  {
    "path": "src/effects/keeper_grove_missile.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://d4gfpjag8c6oi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ch2peil7lqosf\" path=\"res://assets/effects/bdragon/keeper_grove_missile_297.png\" id=\"1_ebc0o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jlkd4\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mqrom\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uoaxc\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q8h2b\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4l3pq\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vhrju\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7nuil\"]\natlas = ExtResource(\"1_ebc0o\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_0763r\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jlkd4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mqrom\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uoaxc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q8h2b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4l3pq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vhrju\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7nuil\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"KeeperGroveMissile\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_0763r\")\n"
  },
  {
    "path": "src/effects/level_up.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://dgrextfmy1i5q\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://wspy8ha1qyck\" path=\"res://assets/effects/bdragon/level_up_455.png\" id=\"1_4qc0c\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bbm4i\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i4u87\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1e5p1\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aspal\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nqa46\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e46yd\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_52r1b\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pkiq3\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vsu1k\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b5nc7\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yq6oe\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wpr2a\"]\natlas = ExtResource(\"1_4qc0c\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_h7nd3\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bbm4i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i4u87\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1e5p1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aspal\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nqa46\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e46yd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_52r1b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pkiq3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vsu1k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b5nc7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yq6oe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wpr2a\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"LevelUp\" type=\"AnimatedSprite2D\"]\nscale = Vector2(1.5, 1.5)\nsprite_frames = SubResource(\"SpriteFrames_h7nd3\")\n"
  },
  {
    "path": "src/effects/mana_burn_target.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://dlpk5wbhmrcvu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cgakg4s2ct3ru\" path=\"res://assets/effects/bdragon/mana_burn_target_388.png\" id=\"1_6my7g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tdwi8\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t2jin\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1lmwo\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7mafl\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kjbvw\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q4wkj\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i0vbd\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hjljj\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4ibcw\"]\natlas = ExtResource(\"1_6my7g\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_58ioh\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tdwi8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t2jin\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1lmwo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7mafl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kjbvw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q4wkj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i0vbd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hjljj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4ibcw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ManaBurnTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_58ioh\")\n"
  },
  {
    "path": "src/effects/mana_shield_cycle.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://x0axb4onqksl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b01ug8hkohe4a\" path=\"res://assets/effects/bdragon/mana_shield_026.png\" id=\"1_duhg0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nvxvk\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jhwt7\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_08xtf\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l1h5g\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_337aj\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jdi41\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qygv2\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1kmta\"]\natlas = ExtResource(\"1_duhg0\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_mfroj\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nvxvk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jhwt7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_08xtf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l1h5g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_337aj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jdi41\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qygv2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1kmta\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 10.0\n}]\n\n[node name=\"ManaShieldCycle\" type=\"AnimatedSprite2D\"]\nmodulate = Color(0.784314, 1, 1, 0.854902)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_mfroj\")\n"
  },
  {
    "path": "src/effects/mass_teleport_caster.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://c2q5uy4lvqaru\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ewm7nac57wox\" path=\"res://assets/effects/bdragon/mass_teleport_caster_335.png\" id=\"1_xyfjw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q3pid\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_16py6\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8kid6\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e1rlp\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7ypbf\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_inseg\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ka36p\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mhiqo\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oieb4\"]\natlas = ExtResource(\"1_xyfjw\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_vcynj\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q3pid\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_16py6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8kid6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e1rlp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7ypbf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_inseg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ka36p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mhiqo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oieb4\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"MassTeleportCaster\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_vcynj\")\n"
  },
  {
    "path": "src/effects/mass_teleport_target.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://dsbokl3n7jdy6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biy8bqpp0e7kj\" path=\"res://assets/effects/bdragon/mass_teleport_target_315.png\" id=\"1_ymeb2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sibqa\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yxnkn\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w1e3p\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_arg8c\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p6mil\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qdx4x\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y76x2\"]\natlas = ExtResource(\"1_ymeb2\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_8qbvq\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sibqa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yxnkn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w1e3p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_arg8c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p6mil\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qdx4x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y76x2\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"MassTeleportTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_8qbvq\")\n"
  },
  {
    "path": "src/effects/monsoon_bolt.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://co1383i1og7sk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bfnbtlckgbnfs\" path=\"res://assets/effects/bdragon/holy_bolt_241.png\" id=\"1_pkj7h\"]\n[ext_resource type=\"AudioStream\" uid=\"uid://be4hv3ryg5pv\" path=\"res://assets/sfx/745156__tigreplayz__blast-explosion.ogg\" id=\"2_prinw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jiqfb\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vj5of\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4c6p7\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8dw4g\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ugtig\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0kson\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_et2ma\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8e8hm\"]\natlas = ExtResource(\"1_pkj7h\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_41x4i\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jiqfb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vj5of\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4c6p7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8dw4g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ugtig\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0kson\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_et2ma\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8e8hm\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"MonsoonBolt\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 4)\nsprite_frames = SubResource(\"SpriteFrames_41x4i\")\noffset = Vector2(5, -18)\n\n[node name=\"AudioStreamPlayer2D\" type=\"AudioStreamPlayer2D\" parent=\".\"]\nstream = ExtResource(\"2_prinw\")\nautoplay = true\n"
  },
  {
    "path": "src/effects/moonwell_target.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://cw4w7l3u0of54\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cxngu4anhtvk6\" path=\"res://assets/effects/bdragon/moonwell_target_584.png\" id=\"1_ettex\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0xp7\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_co048\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xbce4\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l5cty\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vekqs\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cmevc\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_84eu4\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b7xjj\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dkrov\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7hp00\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ngvrm\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l1ejp\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_33en7\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0chml\"]\natlas = ExtResource(\"1_ettex\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ws73d\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d0xp7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_co048\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xbce4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l5cty\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vekqs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cmevc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_84eu4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b7xjj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dkrov\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7hp00\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ngvrm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l1ejp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_33en7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0chml\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"MoonwellTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_ws73d\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/mortar_missile.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://1eyng44n6jkh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://brfqvsks7awtk\" path=\"res://assets/effects/bdragon/impale_target_dust_025.png\" id=\"1_ytpxg\"]\n[ext_resource type=\"AudioStream\" uid=\"uid://ccq2kq8imnl2a\" path=\"res://assets/sfx/p0ss_explode2.ogg\" id=\"2_18xnt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t8f2r\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dgung\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ym0f6\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hjubq\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hhsxq\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jfk3g\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fptep\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m6ndi\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fyfdv\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yiy7y\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2a3bo\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(640, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uaba0\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(704, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_11fiv\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(768, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4diy1\"]\natlas = ExtResource(\"1_ytpxg\")\nregion = Rect2(832, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_4084p\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t8f2r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dgung\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ym0f6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hjubq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hhsxq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jfk3g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fptep\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m6ndi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fyfdv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yiy7y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2a3bo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uaba0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_11fiv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4diy1\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"MortarMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_4084p\")\noffset = Vector2(0, -20)\n\n[node name=\"AudioStreamPlayer2D\" type=\"AudioStreamPlayer2D\" parent=\".\"]\nstream = ExtResource(\"2_18xnt\")\nautoplay = true\n"
  },
  {
    "path": "src/effects/naga_death.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://cthhqbavecrye\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjenjgmw6cgt\" path=\"res://assets/effects/bdragon/ne_death_612.png\" id=\"1_dyysg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hs45k\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_osox3\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q3g6s\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_orm1r\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f7ca0\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n7afb\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hnkpm\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nsh7v\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2h1ls\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d3u6y\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6dshd\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_75e0c\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a4ut7\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0sytx\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wutj1\"]\natlas = ExtResource(\"1_dyysg\")\nregion = Rect2(896, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_xgqpo\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hs45k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_osox3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q3g6s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_orm1r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f7ca0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n7afb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hnkpm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nsh7v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2h1ls\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d3u6y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6dshd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_75e0c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a4ut7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0sytx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wutj1\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"NagaDeath\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_xgqpo\")\n"
  },
  {
    "path": "src/effects/ne_cancel_death.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://ciisf2opa4msn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bryrhw6t0k26o\" path=\"res://assets/effects/bdragon/ne_cancel_death_672.png\" id=\"1_1p2qi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t87lv\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hek8p\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_putiv\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0pom6\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_865y1\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dgh5y\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i310u\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7psay\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ghfiw\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_33tx1\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(576, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y0gnk\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(640, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_danlk\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(704, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_owonv\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(768, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wbeyn\"]\natlas = ExtResource(\"1_1p2qi\")\nregion = Rect2(832, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_rly65\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t87lv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hek8p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_putiv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0pom6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_865y1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dgh5y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i310u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7psay\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ghfiw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_33tx1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y0gnk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_danlk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_owonv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wbeyn\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"NeCancelDeath\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_rly65\")\nframe_progress = 0.206289\n"
  },
  {
    "path": "src/effects/ne_death.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://cpnfir3ok371u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjenjgmw6cgt\" path=\"res://assets/effects/bdragon/ne_death_612.png\" id=\"1_sn6bg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tvbcr\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3hfpy\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yslwb\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8q1ta\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n1axq\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6mygy\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b1b2b\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lmrfa\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_smeo8\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_smxbi\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(576, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0fwnb\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(640, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f5lbb\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(704, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kcnsb\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(768, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_igs4k\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(832, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2j0lf\"]\natlas = ExtResource(\"1_sn6bg\")\nregion = Rect2(896, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_3parv\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tvbcr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3hfpy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yslwb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8q1ta\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n1axq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6mygy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b1b2b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lmrfa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_smeo8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_smxbi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0fwnb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f5lbb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kcnsb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_igs4k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2j0lf\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"NeDeath\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_3parv\")\n"
  },
  {
    "path": "src/effects/placeholder.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://djmwggj8te8j0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://8aycp6wxnpve\" path=\"res://assets/effects/bdragon/placeholder_481.png\" id=\"1_1cwr2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qjyg1\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k385l\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_73nos\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dumt7\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p462m\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_to7m5\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qylrt\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xw752\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ecle4\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c5kmy\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o8i8f\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lgmlt\"]\natlas = ExtResource(\"1_1cwr2\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_g0s8x\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qjyg1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k385l\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_73nos\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dumt7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p462m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_to7m5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qylrt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xw752\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ecle4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c5kmy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o8i8f\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lgmlt\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"Placeholder\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_g0s8x\")\n"
  },
  {
    "path": "src/effects/polymorph_target.tscn",
    "content": "[gd_scene load_steps=27 format=3 uid=\"uid://1ruf6272npqa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfs2k3q3dixg\" path=\"res://assets/effects/bdragon/polymorph_target_735.png\" id=\"1_gmka7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ki8tu\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tiy8m\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v5gek\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iw0el\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d2bxm\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ams2b\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_edfhe\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ndjx\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q2ujf\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lw21u\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b150m\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nmvo8\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3g23g\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(768, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b7jr5\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(832, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_brkpa\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(896, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_up1t8\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(960, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_813wf\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1024, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xom1e\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1088, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o7bxb\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1152, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a65cy\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1216, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qlnxv\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1280, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0bbse\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1344, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a073u\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1408, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_67ftb\"]\natlas = ExtResource(\"1_gmka7\")\nregion = Rect2(1472, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_7n854\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ki8tu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tiy8m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v5gek\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iw0el\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d2bxm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ams2b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_edfhe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ndjx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q2ujf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lw21u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b150m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nmvo8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3g23g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b7jr5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_brkpa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_up1t8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_813wf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xom1e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o7bxb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a65cy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qlnxv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0bbse\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a073u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_67ftb\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"PolymorphTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_7n854\")\nframe_progress = 0.17614\n"
  },
  {
    "path": "src/effects/projectile_explosion_astral.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://w81r40obxpn0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_s8i8m\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_avkco\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rg5oy\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sbujt\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_15mep\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hksp6\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_26wwp\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cmqu6\"]\natlas = ExtResource(\"1_s8i8m\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_0kcdo\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_avkco\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rg5oy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sbujt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_15mep\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hksp6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_26wwp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cmqu6\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ProjectileExplodeAstral\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_0kcdo\")\n"
  },
  {
    "path": "src/effects/projectile_explosion_darkness.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://bf4smllvm8luj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_40fio\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5brdp\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(0, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_svbkk\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(64, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n5w56\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(128, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pv0jc\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(192, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uifn4\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(256, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k4smn\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(320, 512, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xwr0y\"]\natlas = ExtResource(\"1_40fio\")\nregion = Rect2(384, 512, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_qjjqh\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5brdp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_svbkk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n5w56\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pv0jc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uifn4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k4smn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xwr0y\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ProjectileExplosionShadow\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_qjjqh\")\n"
  },
  {
    "path": "src/effects/projectile_explosion_fire.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://bye4rre03fc5k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_olx4g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vlwwe\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dx246\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k0kvi\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_86jrb\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d6ait\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d6hhg\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fgu4e\"]\natlas = ExtResource(\"1_olx4g\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_jirbe\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vlwwe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dx246\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k0kvi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_86jrb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d6ait\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d6hhg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fgu4e\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ProjectileExplodeFire\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_jirbe\")\n"
  },
  {
    "path": "src/effects/projectile_explosion_ice.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://u6qbdra7m00b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_lr0rw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bk1lc\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0kq4o\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g5ucj\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t4c0x\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1r2s1\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ffn80\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jna22\"]\natlas = ExtResource(\"1_lr0rw\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_01iaj\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bk1lc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0kq4o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g5ucj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t4c0x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1r2s1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ffn80\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jna22\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"GenericProjectileExplode2\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_01iaj\")\n"
  },
  {
    "path": "src/effects/projectile_explosion_iron.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://ditvgsvu4xyci\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_3vs4d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hvtjk\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(0, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y3dcp\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(64, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h78qn\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(128, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_laf6d\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(192, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cli78\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(256, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nd2ns\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(320, 384, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lpu0i\"]\natlas = ExtResource(\"1_3vs4d\")\nregion = Rect2(384, 384, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_hj8dx\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hvtjk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y3dcp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h78qn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_laf6d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cli78\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nd2ns\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lpu0i\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ProjectileExplosionIron\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_hj8dx\")\n"
  },
  {
    "path": "src/effects/projectile_explosion_nature.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://cigprvusdkmrd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_u45n8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rfxg7\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0204\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nk8vl\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i88ye\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ntyvt\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3rey2\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5rkn7\"]\natlas = ExtResource(\"1_u45n8\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_oqa54\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rfxg7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d0204\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nk8vl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i88ye\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ntyvt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3rey2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5rkn7\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ProjectileExplosionNature\" type=\"AnimatedSprite2D\"]\nmodulate = Color(0.823529, 0.92549, 0.890196, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_oqa54\")\n"
  },
  {
    "path": "src/effects/projectile_explosion_storm.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://diaf51cff1x17\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cyyax4tkjt7au\" path=\"res://assets/effects/bdragon/projectile_explosion_299.png\" id=\"1_bkwaa\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qk7er\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mnxim\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v4get\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p6oje\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_88umi\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gknre\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vu37c\"]\natlas = ExtResource(\"1_bkwaa\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_n0cl7\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qk7er\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mnxim\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v4get\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p6oje\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_88umi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gknre\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vu37c\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ProjectileExplosionStorm\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_n0cl7\")\n"
  },
  {
    "path": "src/effects/purge_buff_target.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://fphxu25e68dr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dsvu05xjwic5g\" path=\"res://assets/effects/bdragon/purge_buff_target_195.png\" id=\"1_1evqn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s87oc\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7in64\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pvama\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r46kk\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p3sd2\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8ddrx\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k4l58\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rck5u\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_08xm7\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2ddlg\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v1x4h\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nar7x\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vanrr\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ev61\"]\natlas = ExtResource(\"1_1evqn\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_dwr8f\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s87oc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7in64\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pvama\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r46kk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p3sd2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8ddrx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k4l58\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rck5u\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_08xm7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2ddlg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v1x4h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nar7x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vanrr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ev61\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"PurgeBuffTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_dwr8f\")\n"
  },
  {
    "path": "src/effects/quillspray.tscn",
    "content": "[gd_scene load_steps=24 format=3 uid=\"uid://dp4rql26l53fd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cknypfqkfkgiq\" path=\"res://assets/effects/bdragon/quillspray_747.png\" id=\"1_44tgf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jswlu\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ev5c7\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i4jld\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ccx8m\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rujh4\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0fvcm\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nowa2\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4mptj\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n0rii\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y8j4g\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d043t\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ebk61\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fkp6e\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(768, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_llyyx\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(832, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7jy0g\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(896, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jtysy\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(960, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_si4vx\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(1024, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xfln0\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(1088, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6xmni\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(1152, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eudpo\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(1216, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_80gm8\"]\natlas = ExtResource(\"1_44tgf\")\nregion = Rect2(1280, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_06eur\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jswlu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ev5c7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i4jld\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ccx8m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rujh4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0fvcm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nowa2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4mptj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n0rii\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y8j4g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d043t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ebk61\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fkp6e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_llyyx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7jy0g\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jtysy\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_si4vx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xfln0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6xmni\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eudpo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_80gm8\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"Quillspray\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_06eur\")\n"
  },
  {
    "path": "src/effects/raise_skeleton.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://d2hmx2qgpc7st\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dfwypnwsg3p3u\" path=\"res://assets/effects/bdragon/raise_skeleton_624.png\" id=\"1_p58au\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0745r\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_etnuk\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aw88i\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vpb0x\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5eepb\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i53tw\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k6k8v\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3onr7\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0pp3v\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_akoid\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jsvhr\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rdtpk\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(704, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b0g7s\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(768, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ufkms\"]\natlas = ExtResource(\"1_p58au\")\nregion = Rect2(832, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_1fdgw\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0745r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_etnuk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aw88i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vpb0x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5eepb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i53tw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k6k8v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3onr7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0pp3v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_akoid\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jsvhr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rdtpk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b0g7s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ufkms\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"RaiseSkeleton\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_1fdgw\")\n"
  },
  {
    "path": "src/effects/replenish_mana.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://c6i4cmhc3c8my\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cwembk4judxy3\" path=\"res://assets/effects/bdragon/replenish_mana_334.png\" id=\"1_vnhmj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1rwl7\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a0v7q\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_un7s7\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lhbq1\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_is4yf\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_apxb1\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xresh\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0h8nl\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w6vi1\"]\natlas = ExtResource(\"1_vnhmj\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_suqpd\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1rwl7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a0v7q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_un7s7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lhbq1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_is4yf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_apxb1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xresh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0h8nl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w6vi1\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ReplenishMana\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_suqpd\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/effects/revive_human.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://drjxuxfw4ygny\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7ufux57uh5ua\" path=\"res://assets/effects/bdragon/revive_human_623.png\" id=\"1_kp0lo\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_po7ok\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xxiik\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h8b1o\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pkvwr\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gnvv1\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cygfb\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_o8b2j\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6knr2\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tmckn\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2255t\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oiuaj\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8cllg\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ouyty\"]\natlas = ExtResource(\"1_kp0lo\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_r4sjv\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_po7ok\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xxiik\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h8b1o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pkvwr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gnvv1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cygfb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_o8b2j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6knr2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tmckn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2255t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oiuaj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8cllg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ouyty\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ReviveHuman\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_r4sjv\")\n"
  },
  {
    "path": "src/effects/roar.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://uedbjov7gtur\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://un4kd4n5xqem\" path=\"res://assets/effects/bdragon/roar_506.png\" id=\"1_rwphs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4siiv\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(0, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oqxkb\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(64, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wui6q\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(128, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qf4al\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(192, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ybaac\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(256, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xwhiw\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(320, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_feyq6\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(384, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jgjry\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(448, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uqaip\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(512, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4hkuc\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(576, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_78m81\"]\natlas = ExtResource(\"1_rwphs\")\nregion = Rect2(640, 448, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_252lm\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4siiv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oqxkb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wui6q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qf4al\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ybaac\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xwhiw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_feyq6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jgjry\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uqaip\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4hkuc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_78m81\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"Roar\" type=\"AnimatedSprite2D\"]\nscale = Vector2(5, 5)\nsprite_frames = SubResource(\"SpriteFrames_252lm\")\nframe_progress = 0.506272\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/roots.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://cedj7k4jvh5ya\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ddh33dc161220\" path=\"res://assets/effects/bdragon/roots_235.png\" id=\"1_356b7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yaly8\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(512, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n4waa\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(448, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_talhc\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(384, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pnnho\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vgrlk\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y2vxf\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q80j8\"]\natlas = ExtResource(\"1_356b7\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ohfr5\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yaly8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n4waa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_talhc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pnnho\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vgrlk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y2vxf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q80j8\")\n}],\n\"loop\": false,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"Roots\" type=\"AnimatedSprite2D\"]\nmodulate = Color(0.621833, 0.91, 0, 0.788235)\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_ohfr5\")\n"
  },
  {
    "path": "src/effects/shackle.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://cp5uqi81yn7m7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cv8vncnltc5ta\" path=\"res://assets/effects/bdragon/shackle_439.png\" id=\"1_yevyk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4xxru\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y34wu\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7geo0\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pr268\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yyv7y\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uahmr\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vf04h\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rfw3a\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k6oy3\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wr5qa\"]\natlas = ExtResource(\"1_yevyk\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_1u6qh\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4xxru\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y34wu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7geo0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pr268\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yyv7y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uahmr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vf04h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rfw3a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_k6oy3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wr5qa\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"Shackle\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_1u6qh\")\nframe_progress = 0.168769\n"
  },
  {
    "path": "src/effects/shockwave_missile.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://xfwkgsuv57gr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://btlx0a8g4015b\" path=\"res://assets/effects/bdragon/shockwave_missile_440.png\" id=\"1_mdh2s\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ft0rd\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ggsov\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bxfqk\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fojbe\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jfgag\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tb8id\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2w44q\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a3k1r\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5tfn1\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_phok3\"]\natlas = ExtResource(\"1_mdh2s\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_be41r\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ft0rd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ggsov\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bxfqk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fojbe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jfgag\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tb8id\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2w44q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a3k1r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5tfn1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_phok3\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ShockwaveMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_be41r\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/silence_area.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://uh0ny0hofn0o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cetfk6yto1khh\" path=\"res://assets/effects/bdragon/silence_area_611.png\" id=\"1_4m5lt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2xcwp\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a8imd\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p3t61\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3r7hw\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_330bw\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1hrtn\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bbpiv\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0231q\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b0mpb\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v52m6\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6ggup\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b1xvb\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yajk0\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g1ae6\"]\natlas = ExtResource(\"1_4m5lt\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_c5ih8\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2xcwp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a8imd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p3t61\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3r7hw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_330bw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1hrtn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bbpiv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0231q\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b0mpb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v52m6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6ggup\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b1xvb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yajk0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g1ae6\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SilenceArea\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 4)\nsprite_frames = SubResource(\"SpriteFrames_c5ih8\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/effects/small_flame_spawn.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://busiae8sbe32o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://caisjfsu3fyap\" path=\"res://assets/effects/bdragon/small_flame_spawn_240.png\" id=\"1_gw2xe\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i0y6a\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(0, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_idga5\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(64, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b6j3d\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(128, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5txn2\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(192, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dwdt1\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(256, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_juv2b\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(320, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7a2g7\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(384, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y133k\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(448, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j35pc\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(512, 0, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8dton\"]\natlas = ExtResource(\"1_gw2xe\")\nregion = Rect2(576, 0, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_akq2p\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i0y6a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_idga5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b6j3d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5txn2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dwdt1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_juv2b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7a2g7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y133k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j35pc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8dton\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"SmallFlameSpawn\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_akq2p\")\noffset = Vector2(0, -25)\n"
  },
  {
    "path": "src/effects/spell_aiil.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://cot3flbqj8si1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dr841ukdn8762\" path=\"res://assets/effects/bdragon/spell_aiil_452.png\" id=\"1_j0yrm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cxqp4\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gwswq\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hj5gs\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ejvy7\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t1apr\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_071n7\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lmoip\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ppow4\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cu7q7\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p7i6t\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pff6o\"]\natlas = ExtResource(\"1_j0yrm\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_oymxr\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cxqp4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gwswq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hj5gs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ejvy7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t1apr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_071n7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lmoip\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ppow4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cu7q7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p7i6t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pff6o\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SpellAlil\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_oymxr\")\n"
  },
  {
    "path": "src/effects/spell_ailb.tscn",
    "content": "[gd_scene load_steps=26 format=3 uid=\"uid://dpin6kq1goxjp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://0152qy55d5hs\" path=\"res://assets/effects/bdragon/spell_ailb_723.png\" id=\"1_lsgsx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4mraq\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xdyb5\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y6i6h\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4g86h\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_65hbq\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_28v0m\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5v8bo\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_istsk\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kw8wj\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h66rw\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h5t6m\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0tvxx\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gj35c\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jxqni\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c5ums\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(896, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_otmab\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(960, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ekqaa\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1024, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yebi1\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1088, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_t1325\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1152, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sbmbk\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1216, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mwsf2\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1280, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_864lq\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1344, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ogen2\"]\natlas = ExtResource(\"1_lsgsx\")\nregion = Rect2(1408, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_qqdye\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4mraq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xdyb5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y6i6h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4g86h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_65hbq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_28v0m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5v8bo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_istsk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kw8wj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h66rw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h5t6m\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0tvxx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gj35c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jxqni\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c5ums\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_otmab\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ekqaa\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yebi1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_t1325\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sbmbk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mwsf2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_864lq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ogen2\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 40.0\n}]\n\n[node name=\"SpellAilb\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_qqdye\")\n"
  },
  {
    "path": "src/effects/spell_aima.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://k65fnntkfoas\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://csiqjph81rdq8\" path=\"res://assets/effects/bdragon/spell_aima_194.png\" id=\"1_tdyfe\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pbxrm\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wfm1a\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m2nyb\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vyhs7\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8u525\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_78ljt\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mrkim\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wyu2x\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hfpmn\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_px7dh\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_81x5x\"]\natlas = ExtResource(\"1_tdyfe\")\nregion = Rect2(704, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_q3fr7\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pbxrm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wfm1a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_m2nyb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vyhs7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8u525\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_78ljt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mrkim\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wyu2x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hfpmn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_px7dh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_81x5x\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SpellAlma\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_q3fr7\")\n"
  },
  {
    "path": "src/effects/spell_aire.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://b3g5avmjs6mxh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ne67yotbsow\" path=\"res://assets/effects/bdragon/spell_aire_174.png\" id=\"1_fai2d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uq4j7\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qwxds\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_do3h2\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ht5u5\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aawb4\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wdw1b\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cfj1k\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b4cuj\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_41wl1\"]\natlas = ExtResource(\"1_fai2d\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_vsbxm\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uq4j7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qwxds\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_do3h2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ht5u5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aawb4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wdw1b\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cfj1k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_b4cuj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_41wl1\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SpellAlre\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_vsbxm\")\n"
  },
  {
    "path": "src/effects/spell_aire_flat.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://bi67eqa114fqx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ne67yotbsow\" path=\"res://assets/effects/bdragon/spell_aire_174.png\" id=\"1_r160i\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_r1wma\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yftmt\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_scvon\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0uef0\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_85xpx\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x1hwc\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_locgo\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2if0k\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ft0eg\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8svuf\"]\natlas = ExtResource(\"1_r160i\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_qkg6m\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_r1wma\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yftmt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_scvon\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0uef0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_85xpx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x1hwc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_locgo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2if0k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ft0eg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8svuf\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"SpellAlreFlat\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 1.5)\nsprite_frames = SubResource(\"SpriteFrames_qkg6m\")\n"
  },
  {
    "path": "src/effects/spell_aiso.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://tofwa3vfsvni\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://carq8d0wtr1pl\" path=\"res://assets/effects/bdragon/spell_aiso_295.png\" id=\"1_w2ehe\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2ytw6\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6wphw\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bn4bx\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i4bxt\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8ye6h\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uo4od\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_j7c6e\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_38wle\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4hk7l\"]\natlas = ExtResource(\"1_w2ehe\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ebrdp\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2ytw6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6wphw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bn4bx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i4bxt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8ye6h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uo4od\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_j7c6e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_38wle\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4hk7l\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SpellAlso\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_ebrdp\")\nframe_progress = 0.275066\n"
  },
  {
    "path": "src/effects/spell_alim.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://clwe4ffen5bjf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cxr4c28mmw4nn\" path=\"res://assets/effects/bdragon/spell_alim_136.png\" id=\"1_vlsed\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8uxpu\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(0, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1slmi\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5a7er\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(128, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c1gem\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(192, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oigba\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(256, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ccu77\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(320, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5bif4\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(384, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3wkxn\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(448, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l3t4d\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(512, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_eceaj\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(576, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h7h42\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(640, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dpjx5\"]\natlas = ExtResource(\"1_vlsed\")\nregion = Rect2(704, 256, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_t4d0i\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8uxpu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1slmi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5a7er\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c1gem\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oigba\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ccu77\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5bif4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3wkxn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l3t4d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_eceaj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_h7h42\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dpjx5\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SpellAlim\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_t4d0i\")\n"
  },
  {
    "path": "src/effects/spell_breaker_target.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://c54yweacmq0q1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://gtoj6o1w8tv0\" path=\"res://assets/effects/bdragon/spell_breaker_target_613.png\" id=\"1_bt5ob\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aex67\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n4h3a\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_onqex\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3vdo7\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ei57j\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p5fu2\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_80cc2\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_np4d6\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2qifn\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s52wf\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rq5gl\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c40ts\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(704, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6qnls\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(768, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1kv6y\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(832, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w1myt\"]\natlas = ExtResource(\"1_bt5ob\")\nregion = Rect2(896, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_28uui\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aex67\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n4h3a\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_onqex\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3vdo7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ei57j\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p5fu2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_80cc2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_np4d6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2qifn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s52wf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rq5gl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c40ts\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_6qnls\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1kv6y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w1myt\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"SpellBreakerTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_28uui\")\n"
  },
  {
    "path": "src/effects/spirit_link_target.tscn",
    "content": "[gd_scene load_steps=13 format=3 uid=\"uid://lrcquuvk3v0q\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://terakoeeqruj\" path=\"res://assets/effects/bdragon/spirit_link_target_175.png\" id=\"1_6ci8a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sgn0k\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_txcn3\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vlwpb\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sq1kv\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vpeyk\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8m2mx\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yrayf\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nrnjp\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5o0vf\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_augcw\"]\natlas = ExtResource(\"1_6ci8a\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_7b2kk\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sgn0k\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_txcn3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vlwpb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sq1kv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vpeyk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8m2mx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yrayf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nrnjp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5o0vf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_augcw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"SpiritLinkTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_7b2kk\")\nframe_progress = 0.411772\n"
  },
  {
    "path": "src/effects/stampede_missile_death.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://5hsslpdsg4ih\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bbmm2xf32v0tx\" path=\"res://assets/effects/bdragon/stampede_missile_death_63.png\" id=\"1_37gi2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pqp0h\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(0, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3xwu0\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(64, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_71hw0\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(128, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cv7y0\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(192, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_610tc\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(256, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qda3v\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(320, 448, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gjjie\"]\natlas = ExtResource(\"1_37gi2\")\nregion = Rect2(384, 448, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_6ylhj\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pqp0h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3xwu0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_71hw0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_cv7y0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_610tc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qda3v\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gjjie\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"StampedeMissileDeath\" type=\"AnimatedSprite2D\"]\nsprite_frames = SubResource(\"SpriteFrames_6ylhj\")\n"
  },
  {
    "path": "src/effects/starfall_target.tscn",
    "content": "[gd_scene load_steps=9 format=3 uid=\"uid://dg7ufr7xju145\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b7swdbv14utxv\" path=\"res://assets/effects/bdragon/starfall_target_257.png\" id=\"1_hct40\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c4qyo\"]\natlas = ExtResource(\"1_hct40\")\nregion = Rect2(0, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pqrbi\"]\natlas = ExtResource(\"1_hct40\")\nregion = Rect2(64, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3s625\"]\natlas = ExtResource(\"1_hct40\")\nregion = Rect2(128, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ouo1w\"]\natlas = ExtResource(\"1_hct40\")\nregion = Rect2(192, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_w1k38\"]\natlas = ExtResource(\"1_hct40\")\nregion = Rect2(256, 192, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_32mrh\"]\natlas = ExtResource(\"1_hct40\")\nregion = Rect2(320, 192, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_qnbjh\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c4qyo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pqrbi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_3s625\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ouo1w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_w1k38\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_32mrh\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"StarfallTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_qnbjh\")\n"
  },
  {
    "path": "src/effects/stun_visual.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://cba2dbefq4uio\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bmtjm6qhm3rop\" path=\"res://assets/effects/stun.png\" id=\"1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 0, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 32, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"3\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 64, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"4\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 96, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"5\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 128, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"6\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 160, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"7\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 192, 32, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"8\"]\natlas = ExtResource(\"1\")\nregion = Rect2(0, 224, 32, 32)\n\n[sub_resource type=\"SpriteFrames\" id=\"9\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"8\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 5.0\n}]\n\n[node name=\"StunVisual\" type=\"AnimatedSprite2D\"]\nmodulate = Color(0.376471, 0.831373, 0.921569, 1)\nscale = Vector2(3, 2)\nsprite_frames = SubResource(\"9\")\n"
  },
  {
    "path": "src/effects/target_arrow.gd",
    "content": "extends AnimatedSprite2D\n\n\n# A bouncing arrow pointing down. Used to indicate a\n# targeted creep.\n\n\nconst BOUNCE_TIME: float = 0.3\nconst BOUNCE_HEIGHT: float = 30.0\n\n\nfunc _ready():\n\tvar pos_tween = create_tween()\n\tpos_tween.tween_property(self, \"offset\",\n\t\toffset - Vector2(0, BOUNCE_HEIGHT),\n\t\tBOUNCE_TIME).set_ease(Tween.EASE_IN)\n\tpos_tween.tween_property(self, \"offset\",\n\t\toffset,\n\t\tBOUNCE_TIME).set_delay(BOUNCE_TIME).set_ease(Tween.EASE_IN)\n\tpos_tween.set_loops()\n"
  },
  {
    "path": "src/effects/target_arrow.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://4s07c8mxro5e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djotx5jk18gc0\" path=\"res://assets/effects/arrow.png\" id=\"1_vgk2e\"]\n[ext_resource type=\"Script\" path=\"res://src/effects/target_arrow.gd\" id=\"2_80dmy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8hiko\"]\natlas = ExtResource(\"1_vgk2e\")\nregion = Rect2(0, 0, 128, 128)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_e22gq\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8hiko\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 5.0\n}]\n\n[node name=\"TargetArrow\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nsprite_frames = SubResource(\"SpriteFrames_e22gq\")\noffset = Vector2(0, -100)\nscript = ExtResource(\"2_80dmy\")\n"
  },
  {
    "path": "src/effects/thunder_clap.tscn",
    "content": "[gd_scene load_steps=14 format=3 uid=\"uid://b8p33d4fgjd0b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://2dquk1ppfku0\" path=\"res://assets/effects/bdragon/thunder_clap_466.png\" id=\"1_wmc7q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f6jgu\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s8vlr\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fkrkx\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ylcdl\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_16dq2\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nk2pc\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7yx2w\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hqvhb\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fksty\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xffd0\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g0bkp\"]\natlas = ExtResource(\"1_wmc7q\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_wuehe\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_f6jgu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s8vlr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fkrkx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ylcdl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_16dq2\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_nk2pc\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7yx2w\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hqvhb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_fksty\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xffd0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g0bkp\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"ThunderClap\" type=\"AnimatedSprite2D\"]\nscale = Vector2(5, 5)\nsprite_frames = SubResource(\"SpriteFrames_wuehe\")\noffset = Vector2(0, 5)\n"
  },
  {
    "path": "src/effects/undead_dissipate.tscn",
    "content": "[gd_scene load_steps=18 format=3 uid=\"uid://46wd7wksxr61\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://blekt36dlhmd2\" path=\"res://assets/effects/bdragon/undead_dissipate_633.png\" id=\"1_xooed\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mhr13\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(0, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lmu88\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(64, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jjrrt\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(128, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gpwls\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(192, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_g05tm\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(256, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_snig3\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(320, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ev0pm\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(384, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_knjrm\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(448, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dxtcl\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(512, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yg2q8\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(576, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_61q44\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(640, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1lmb4\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(704, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a1hm8\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(768, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i3ya0\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(832, 64, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_irkqr\"]\natlas = ExtResource(\"1_xooed\")\nregion = Rect2(896, 64, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_b324a\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mhr13\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lmu88\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jjrrt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gpwls\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_g05tm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_snig3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ev0pm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_knjrm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dxtcl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yg2q8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_61q44\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1lmb4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a1hm8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_i3ya0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_irkqr\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"UndeadDissipate\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_b324a\")\nframe = 1\nframe_progress = 0.5981\n"
  },
  {
    "path": "src/effects/upgrade_tower.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://cgi40xm7251x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cpuu4w0gghqoe\" path=\"res://assets/effects/bdragon/upgrade_tower_016.png\" id=\"1_nkeei\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qeukh\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1atdd\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c48o0\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_22fn6\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yqh2x\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hdjyx\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ue87c\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aqc6d\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d53ry\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_y0472\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1pusj\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dpk6n\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rifqg\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_a7vvb\"]\natlas = ExtResource(\"1_nkeei\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_7cwwu\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qeukh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1atdd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c48o0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_22fn6\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_yqh2x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hdjyx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ue87c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aqc6d\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d53ry\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_y0472\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1pusj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dpk6n\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rifqg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_a7vvb\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 30.0\n}]\n\n[node name=\"UpgradeTower\" type=\"AnimatedSprite2D\"]\nz_index = -1\ny_sort_enabled = true\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_7cwwu\")\nframe_progress = 0.83775\n"
  },
  {
    "path": "src/effects/vampiric_aura.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://djkt0t0jveoks\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b2nm17eb4jt7\" path=\"res://assets/effects/bdragon/vampiric_aura_199.png\" id=\"1_gexlj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iklf1\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_djwsp\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mvymw\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x0che\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7o34c\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wi1yn\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qqc4e\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0gyqi\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ub3l0\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_busr1\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lh30p\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1oakg\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_uqfkd\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_030uv\"]\natlas = ExtResource(\"1_gexlj\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_3ky65\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iklf1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_djwsp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_mvymw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x0che\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_7o34c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wi1yn\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qqc4e\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0gyqi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ub3l0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_busr1\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_lh30p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1oakg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_uqfkd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_030uv\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"VampiricAura\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_3ky65\")\nframe_progress = 0.51243\n"
  },
  {
    "path": "src/effects/voodoo_aura.tscn",
    "content": "[gd_scene load_steps=15 format=3 uid=\"uid://o2tead45rrea\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cktvui85usgvp\" path=\"res://assets/effects/bdragon/voodoo_aura_182.png\" id=\"1_3b14v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qc8tg\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d52x5\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ecciw\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_euong\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8h0tm\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_al8g0\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ykbhp\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rn20h\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ojq45\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oa2mo\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2l4qs\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jksv7\"]\natlas = ExtResource(\"1_3b14v\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_i8hdn\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qc8tg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d52x5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ecciw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_euong\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8h0tm\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_al8g0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ykbhp\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rn20h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ojq45\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_oa2mo\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2l4qs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jksv7\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"VoodooAura\" type=\"AnimatedSprite2D\"]\nmodulate = Color(1, 1, 1, 0.784314)\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_i8hdn\")\n"
  },
  {
    "path": "src/effects/warstomp_caster.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://bcre0h05xu5kc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://di3fq4jkhoq4y\" path=\"res://assets/effects/bdragon/warstomp_caster_536.png\" id=\"1_h7f5o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5fv5o\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dt2d4\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_meshf\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4kkls\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hf1s8\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8nltb\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gut25\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dx6xt\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ek0rx\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qi6w7\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hmxsi\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ih2n8\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_10yek\"]\natlas = ExtResource(\"1_h7f5o\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_ek7gu\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5fv5o\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dt2d4\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_meshf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4kkls\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hf1s8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_8nltb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gut25\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dx6xt\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ek0rx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_qi6w7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hmxsi\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ih2n8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_10yek\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"WarstompCaster\" type=\"AnimatedSprite2D\"]\nscale = Vector2(4, 2)\nsprite_frames = SubResource(\"SpriteFrames_ek7gu\")\n"
  },
  {
    "path": "src/effects/wind_shear.tscn",
    "content": "[gd_scene load_steps=17 format=3 uid=\"uid://djr2oy8i57ega\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://4vi0ba0hi12o\" path=\"res://assets/effects/bdragon/wind_shear_559.png\" id=\"1_bsx24\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tgcmv\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gbm0t\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bjusf\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aqs7s\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_31aak\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ogc3i\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_seoag\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c37lb\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p7sxu\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_42nry\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l778i\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1lmeq\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_etnem\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n1ueq\"]\natlas = ExtResource(\"1_bsx24\")\nregion = Rect2(832, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_webp7\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tgcmv\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_gbm0t\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bjusf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_aqs7s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_31aak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ogc3i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_seoag\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c37lb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p7sxu\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_42nry\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l778i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1lmeq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_etnem\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n1ueq\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"WindShear\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_webp7\")\n"
  },
  {
    "path": "src/effects/wisp_explode.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://b7ro7b6a4lmh3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://pb01lu85dqby\" path=\"res://assets/effects/bdragon/wisp_explode_003.png\" id=\"1_svy12\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tkrtr\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tkyy3\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d6srr\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ifryk\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ak4k0\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dspwl\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2vaaq\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1r7q7\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q1t3p\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_quwo3\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(576, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ljenx\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(640, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hqh0s\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(704, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_x3bld\"]\natlas = ExtResource(\"1_svy12\")\nregion = Rect2(768, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_odeen\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tkrtr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_tkyy3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_d6srr\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ifryk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ak4k0\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_dspwl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2vaaq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_1r7q7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q1t3p\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_quwo3\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ljenx\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hqh0s\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_x3bld\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[node name=\"WispExplode\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_odeen\")\n"
  },
  {
    "path": "src/effects/witch_doctor_ward.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://ufi3015bf8u5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_32o8l\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sefck\"]\natlas = ExtResource(\"1_32o8l\")\nregion = Rect2(768, 256, 256, 256)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_sfoew\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_sefck\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 5.0\n}]\n\n[node name=\"WitchDoctorWard\" type=\"AnimatedSprite2D\"]\nsprite_frames = SubResource(\"SpriteFrames_sfoew\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/effects/ziggurat_frost_missile.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://drjb6fsqipejn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bvvxqx0twqcdq\" path=\"res://assets/effects/bdragon/ziggurat_frost_missile_325.png\" id=\"1_ipaaq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_765wl\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_iio0c\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2xkyf\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_46okk\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4e5da\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vfj5h\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_surkj\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p7em8\"]\natlas = ExtResource(\"1_ipaaq\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_bl7gl\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_765wl\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_iio0c\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_2xkyf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_46okk\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_4e5da\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_vfj5h\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_surkj\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_p7em8\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ZigguratFrostMissile\" type=\"AnimatedSprite2D\"]\nscale = Vector2(3, 3)\nsprite_frames = SubResource(\"SpriteFrames_bl7gl\")\n"
  },
  {
    "path": "src/effects/zombify_target.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://bupns1xva102c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dtoev5csbiekv\" path=\"res://assets/effects/bdragon/zombify_target_274.png\" id=\"1_223i6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ohb5x\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(0, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_rgdls\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(64, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c43rg\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(128, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_myluh\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q24c7\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(256, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_brscb\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_v451y\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ykgiy\"]\natlas = ExtResource(\"1_223i6\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_goh3o\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ohb5x\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_rgdls\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_c43rg\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_myluh\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_q24c7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_brscb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_v451y\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ykgiy\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"ZombifyTarget\" type=\"AnimatedSprite2D\"]\nscale = Vector2(2, 2)\nsprite_frames = SubResource(\"SpriteFrames_goh3o\")\n"
  },
  {
    "path": "src/enums/README.md",
    "content": "This folder contains enums, implemented as singletons. These enums are implemented as singletons rather than \n\nNote that not all enums are grouped in this folder. Some enums are declared inside other classes.\n"
  },
  {
    "path": "src/enums/armor_type.gd",
    "content": "class_name ArmorType extends Node\n\nenum enm {\n\tHEL,\n\tMYT,\n\tLUA,\n\tSOL,\n\tSIF,\n\tZOD,\n}\n\nstatic var _list: Array[ArmorType.enm] = [\n\tArmorType.enm.HEL,\n\tArmorType.enm.MYT,\n\tArmorType.enm.LUA,\n\tArmorType.enm.SOL,\n\tArmorType.enm.SIF,\n\tArmorType.enm.ZOD,\n]\n\nstatic var _string_map: Dictionary = {\n\tArmorType.enm.HEL: \"hel\",\n\tArmorType.enm.MYT: \"myt\",\n\tArmorType.enm.LUA: \"lua\",\n\tArmorType.enm.SOL: \"sol\",\n\tArmorType.enm.SIF: \"sif\",\n\tArmorType.enm.ZOD: \"zod\",\n}\n\nstatic var _color_map: Dictionary = {\n\tArmorType.enm.HEL: Color.ORANGE_RED,\n\tArmorType.enm.MYT: Color.CORNFLOWER_BLUE,\n\tArmorType.enm.LUA: Color.LIME_GREEN,\n\tArmorType.enm.SOL: Color.GOLD,\n\tArmorType.enm.SIF: Color.MEDIUM_PURPLE,\n\tArmorType.enm.ZOD: Color.YELLOW,\n}\n\n\nstatic func from_string(string: String) -> ArmorType.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn ArmorType.enm.ZOD\n\n\nstatic func convert_to_string(type: ArmorType.enm) -> String:\n\treturn _string_map[type]\n\n\nstatic func get_display_string(type: ArmorType.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tArmorType.enm.HEL: string = Utils.tr(\"ARMOR_TYPE_HEL\")\n\t\tArmorType.enm.MYT: string = Utils.tr(\"ARMOR_TYPE_MYT\")\n\t\tArmorType.enm.LUA: string = Utils.tr(\"ARMOR_TYPE_LUA\")\n\t\tArmorType.enm.SOL: string = Utils.tr(\"ARMOR_TYPE_SOL\")\n\t\tArmorType.enm.SIF: string = Utils.tr(\"ARMOR_TYPE_SIF\")\n\t\tArmorType.enm.ZOD: string = Utils.tr(\"ARMOR_TYPE_ZOD\")\n\t\n\treturn string\n\n\nstatic func convert_to_colored_string(type: ArmorType.enm) -> String:\n\tvar string: String = get_display_string(type)\n\tvar color: Color = _color_map[type]\n\tvar out: String = Utils.get_colored_string(string, color)\n\n\treturn out\n\n\nstatic func get_list() -> Array[ArmorType.enm]:\n\treturn _list.duplicate()\n\n\n# Returns text which says how much damage this armor type\n# takes from each attack type.\nstatic func get_text_for_damage_taken(armor_type: ArmorType.enm) -> String:\n\tvar text: String = \"\"\n\n\tvar attack_type_list: Array[AttackType.enm] = AttackType.get_list()\n\n\tfor attack_type in attack_type_list:\n\t\tvar attack_type_name: String = AttackType.get_display_string(attack_type)\n\t\tvar damage_taken: float = AttackType.get_damage_against(attack_type, armor_type)\n\t\tvar damage_taken_string: String = Utils.format_percent(damage_taken, 2)\n\n\t\ttext += \"%s:\\t %s\\n\" % [attack_type_name, damage_taken_string]\n\n\tvar spell_damage_taken: float = ArmorType.get_spell_damage_taken(armor_type)\n\tvar spell_damage_taken_string: String = Utils.format_percent(spell_damage_taken, 2)\n\ttext += Utils.tr(\"ARMOR_SPELL_DAMAGE_TAKEN\") + \"\\t %s\\n\" % [spell_damage_taken_string]\n\n\treturn text\n\n\nstatic func get_rich_text_for_damage_taken(armor_type: ArmorType.enm) -> String:\n\tvar text: String = \"\"\n\n\tvar attack_type_list: Array[AttackType.enm] = AttackType.get_list()\n\n\tfor attack_type in attack_type_list:\n\t\tvar attack_type_name: String = AttackType.convert_to_colored_string(attack_type)\n\t\tvar damage_taken: float = AttackType.get_damage_against(attack_type, armor_type)\n\t\tvar damage_taken_string: String = Utils.format_percent(damage_taken, 2)\n\n\t\ttext += \"%s:\\t %s\\n\" % [attack_type_name, damage_taken_string]\n\n\tvar spell_damage_taken: float = ArmorType.get_spell_damage_taken(armor_type)\n\tvar spell_damage_taken_string: String = Utils.format_percent(spell_damage_taken, 2)\n\ttext += Utils.tr(\"ARMOR_SPELL_DAMAGE_TAKEN\") + \"\\t %s\\n\" % [spell_damage_taken_string]\n\n\ttext = RichTexts.add_color_to_numbers(text)\n\n\treturn text\n\n\nstatic func get_spell_damage_taken(armor_type: ArmorType.enm) -> float:\n\tvar value: float\n\n\tif armor_type == ArmorType.enm.SIF:\n\t\tvalue = Constants.SPELL_DAMAGE_RATIO_FOR_SIF\n\telse:\n\t\tvalue = Constants.SPELL_DAMAGE_RATIO\n\n\treturn value\n"
  },
  {
    "path": "src/enums/attack_type.gd",
    "content": "class_name AttackType extends Node\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] renamed \"Magic\"\n# attack type from original game to \"Arcane\". Original\n# \"Magic\" name for attack type was confusing because it\n# sounded like it was related to \"spell damage\".\n\nenum enm {\n\tPHYSICAL,\n\tDECAY,\n\tENERGY,\n\tESSENCE,\n\tELEMENTAL,\n\tARCANE,\n}\n\nstatic var _list: Array[AttackType.enm] = [\n\tAttackType.enm.PHYSICAL,\n\tAttackType.enm.DECAY,\n\tAttackType.enm.ENERGY,\n\tAttackType.enm.ESSENCE,\n\tAttackType.enm.ELEMENTAL,\n\tAttackType.enm.ARCANE,\n]\n\nstatic var _string_map: Dictionary = {\n\tAttackType.enm.PHYSICAL: \"physical\",\n\tAttackType.enm.DECAY: \"decay\",\n\tAttackType.enm.ENERGY: \"energy\",\n\tAttackType.enm.ESSENCE: \"essence\",\n\tAttackType.enm.ELEMENTAL: \"elemental\",\n\tAttackType.enm.ARCANE: \"arcane\",\n}\n\nstatic var _color_map: Dictionary = {\n\tAttackType.enm.PHYSICAL: Color.TAN,\n\tAttackType.enm.DECAY: Color.MEDIUM_PURPLE,\n\tAttackType.enm.ENERGY: Color.DODGER_BLUE,\n\tAttackType.enm.ESSENCE: Color.AQUAMARINE,\n\tAttackType.enm.ELEMENTAL: Color.CORNFLOWER_BLUE,\n\tAttackType.enm.ARCANE: Color.DEEP_SKY_BLUE,\n}\n\nstatic var _no_damage_to_immune_map: Dictionary = {\n\tAttackType.enm.PHYSICAL: false,\n\tAttackType.enm.DECAY: false,\n\tAttackType.enm.ENERGY: false,\n\tAttackType.enm.ESSENCE: false,\n\tAttackType.enm.ELEMENTAL: false,\n\tAttackType.enm.ARCANE: true,\n}\n\nstatic var _damage_to_armor_map: Dictionary = {\n\tAttackType.enm.PHYSICAL: {\n\t\tArmorType.enm.LUA: 1.8,\n\t\tArmorType.enm.SOL: 1.2,\n\t\tArmorType.enm.HEL: 0.9,\n\t\tArmorType.enm.MYT: 0.6,\n\t\tArmorType.enm.SIF: 0.4,\n\t\tArmorType.enm.ZOD: 1.0,\n\t},\n\tAttackType.enm.DECAY: {\n\t\tArmorType.enm.SOL: 1.8,\n\t\tArmorType.enm.HEL: 1.2,\n\t\tArmorType.enm.MYT: 0.9,\n\t\tArmorType.enm.LUA: 0.6,\n\t\tArmorType.enm.SIF: 0.4,\n\t\tArmorType.enm.ZOD: 1.0,\n\t},\n\tAttackType.enm.ENERGY: {\n\t\tArmorType.enm.HEL: 1.8,\n\t\tArmorType.enm.MYT: 1.2,\n\t\tArmorType.enm.LUA: 0.9,\n\t\tArmorType.enm.SOL: 0.6,\n\t\tArmorType.enm.SIF: 0.4,\n\t\tArmorType.enm.ZOD: 1.0,\n\t},\n\tAttackType.enm.ESSENCE: {\n\t\tArmorType.enm.HEL: 1.0,\n\t\tArmorType.enm.MYT: 1.0,\n\t\tArmorType.enm.LUA: 1.0,\n\t\tArmorType.enm.SOL: 1.0,\n\t\tArmorType.enm.SIF: 1.0,\n\t\tArmorType.enm.ZOD: 1.0,\n\t},\n\tAttackType.enm.ELEMENTAL: {\n\t\tArmorType.enm.MYT: 1.8,\n\t\tArmorType.enm.LUA: 1.2,\n\t\tArmorType.enm.SOL: 0.9,\n\t\tArmorType.enm.HEL: 0.6,\n\t\tArmorType.enm.SIF: 0.4,\n\t\tArmorType.enm.ZOD: 1.0,\n\t},\n\tAttackType.enm.ARCANE: {\n\t\tArmorType.enm.MYT: 1.5,\n\t\tArmorType.enm.LUA: 1.5,\n\t\tArmorType.enm.SOL: 1.5,\n\t\tArmorType.enm.HEL: 1.5,\n\t\tArmorType.enm.SIF: 0.4,\n\t\tArmorType.enm.ZOD: 1.0,\n\t},\n}\n\n\nstatic func convert_to_string(type: AttackType.enm):\n\treturn _string_map[type]\n\n\nstatic func from_string(string: String) -> AttackType.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid attack type string: \\\"%s\\\"\" % string)\n\n\t\treturn AttackType.enm.PHYSICAL\n\n\nstatic func get_display_string(type: AttackType.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tAttackType.enm.PHYSICAL: string = Utils.tr(\"ATTACK_TYPE_PHYSICAL\")\n\t\tAttackType.enm.DECAY: string = Utils.tr(\"ATTACK_TYPE_DECAY\")\n\t\tAttackType.enm.ENERGY: string = Utils.tr(\"ATTACK_TYPE_ENERGY\")\n\t\tAttackType.enm.ESSENCE: string = Utils.tr(\"ATTACK_TYPE_ESSENCE\")\n\t\tAttackType.enm.ELEMENTAL: string = Utils.tr(\"ATTACK_TYPE_ELEMENTAL\")\n\t\tAttackType.enm.ARCANE: string = Utils.tr(\"ATTACK_TYPE_ARCANE\")\n\t\n\treturn string\n\n\n# NOTE: AttackType.PHYSICAL.getDamageAgainst() in JASS\nstatic func get_damage_against(attack_type: AttackType.enm, armor_type: ArmorType.enm) -> float:\n\tvar damage: float = _damage_to_armor_map[attack_type][armor_type]\n\n\treturn damage\n\n\nstatic func deals_no_damage_to_immune(attack_type: AttackType.enm) -> bool:\n\treturn _no_damage_to_immune_map[attack_type]\n\n\nstatic func convert_to_colored_string(type: AttackType.enm) -> String:\n\tvar string: String = get_display_string(type)\n\tvar color: Color = _color_map[type]\n\tvar out: String = Utils.get_colored_string(string, color)\n\n\treturn out\n\n\nstatic func get_list() -> Array[AttackType.enm]:\n\treturn _list.duplicate()\n\n\n# Returns text which says how much damage this attack type\n# deals against each armor type.\n# NOTE: this is rich text\nstatic func get_rich_text_for_damage_dealt(attack_type: AttackType.enm) -> String:\n\tvar text: String = \"\"\n\n\tvar armor_type_list: Array[ArmorType.enm] = ArmorType.get_list()\n\n\tfor armor_type in armor_type_list:\n\t\tvar armor_type_name: String = ArmorType.convert_to_colored_string(armor_type)\n\t\tvar damage_dealt: float = AttackType.get_damage_against(attack_type, armor_type)\n\t\tvar damage_dealt_string: String = Utils.format_percent(damage_dealt, 2)\n\n\t\ttext += \"%s:\\t %s\\n\" % [armor_type_name, damage_dealt_string]\n\n\tif attack_type == AttackType.enm.ARCANE:\n\t\ttext += \"[color=RED]%s[/color]\\n\" % Utils.tr(\"ATTACK_TYPE_CANNOT_HIT_IMMUNE\")\n\n\ttext = RichTexts.add_color_to_numbers(text)\n\n\treturn text\n"
  },
  {
    "path": "src/enums/buff_group_mode.gd",
    "content": "class_name BuffGroupMode extends Node\n\nenum enm {\n\tNONE = 0,\n\tOUTGOING = 1,\n\tINCOMING = 2,\n\tBOTH = 3,\n}\n"
  },
  {
    "path": "src/enums/builder_tier.gd",
    "content": "class_name BuilderTier extends Node\n\n\nenum enm {\n\tBEGINNER,\n\tADVANCED,\n\tSPECIALIST,\n\tHARDCORE,\n}\n\n\nstatic var _string_map: Dictionary = {\n\tBuilderTier.enm.BEGINNER: \"beginner\",\n\tBuilderTier.enm.ADVANCED: \"advanced\",\n\tBuilderTier.enm.SPECIALIST: \"specialist\",\n\tBuilderTier.enm.HARDCORE: \"hardcore\",\n}\n\n\nstatic func convert_to_string(type: BuilderTier.enm):\n\treturn _string_map[type]\n\n\nstatic func from_string(string: String) -> BuilderTier.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn BuilderTier.enm.BEGINNER\n"
  },
  {
    "path": "src/enums/creep_category.gd",
    "content": "class_name CreepCategory extends Node\n\nenum enm {\n\tUNDEAD,\n\tMAGIC,\n\tNATURE,\n\tORC,\n\tHUMANOID,\n\tCHALLENGE,\n}\n\n\nstatic var _ordered_list: Array[CreepCategory.enm] = [\n\tCreepCategory.enm.UNDEAD,\n\tCreepCategory.enm.MAGIC,\n\tCreepCategory.enm.NATURE,\n\tCreepCategory.enm.ORC,\n\tCreepCategory.enm.HUMANOID,\n\tCreepCategory.enm.CHALLENGE,\n]\n\nstatic var _string_map: Dictionary = {\n\tCreepCategory.enm.UNDEAD: \"undead\",\n\tCreepCategory.enm.MAGIC: \"magic\",\n\tCreepCategory.enm.NATURE: \"nature\",\n\tCreepCategory.enm.ORC: \"orc\",\n\tCreepCategory.enm.HUMANOID: \"humanoid\",\n\tCreepCategory.enm.CHALLENGE: \"challenge\",\n}\n\nstatic var _color_map: Dictionary = {\n\tCreepCategory.enm.UNDEAD: Color.MEDIUM_PURPLE,\n\tCreepCategory.enm.MAGIC: Color.CORNFLOWER_BLUE,\n\tCreepCategory.enm.NATURE: Color.LIME_GREEN,\n\tCreepCategory.enm.ORC: Color.DARK_SEA_GREEN,\n\tCreepCategory.enm.HUMANOID: Color.TAN,\n\tCreepCategory.enm.CHALLENGE: Color.GOLD,\n}\n\n\nstatic func get_list() -> Array[CreepCategory.enm]:\n\treturn _ordered_list\n\n\nstatic func from_string(string: String) -> CreepCategory.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn CreepCategory.enm.UNDEAD\n\n\nstatic func convert_to_string(type: CreepCategory.enm) -> String:\n\treturn _string_map[type]\n\n\nstatic func get_display_string(type: CreepCategory.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tCreepCategory.enm.UNDEAD: string = Utils.tr(\"RACE_UNDEAD\")\n\t\tCreepCategory.enm.MAGIC: string = Utils.tr(\"RACE_MAGICAL\")\n\t\tCreepCategory.enm.NATURE: string = Utils.tr(\"RACE_NATURE\")\n\t\tCreepCategory.enm.ORC: string = Utils.tr(\"RACE_ORC\")\n\t\tCreepCategory.enm.HUMANOID: string = Utils.tr(\"RACE_HUMANOID\")\n\t\tCreepCategory.enm.CHALLENGE: string = Utils.tr(\"RACE_CHALLENGE\")\n\t\n\treturn string\n\n\nstatic func get_color(type: CreepCategory.enm) -> Color:\n\tvar color: Color = _color_map[type]\n\n\treturn color\n\n\nstatic func convert_to_colored_string(type: CreepCategory.enm) -> String:\n\tvar string: String = get_display_string(type)\n\tvar color: Color = _color_map[type]\n\tvar out: String = Utils.get_colored_string(string, color)\n\n\treturn out\n\n\nstatic func convert_to_mod_dmg_type(category: CreepCategory.enm) -> ModificationType.enm:\n\tconst creep_category_to_mod_map: Dictionary = {\n\t\tCreepCategory.enm.UNDEAD: ModificationType.enm.MOD_DMG_TO_MASS,\n\t\tCreepCategory.enm.MAGIC: ModificationType.enm.MOD_DMG_TO_MAGIC,\n\t\tCreepCategory.enm.NATURE: ModificationType.enm.MOD_DMG_TO_NATURE,\n\t\tCreepCategory.enm.ORC: ModificationType.enm.MOD_DMG_TO_ORC,\n\t\tCreepCategory.enm.HUMANOID: ModificationType.enm.MOD_DMG_TO_HUMANOID,\n\t\tCreepCategory.enm.CHALLENGE: ModificationType.enm.MOD_DMG_TO_CHALLENGE,\n\t}\n\n\tvar mod_type: ModificationType.enm = creep_category_to_mod_map[category]\n\n\treturn mod_type\n"
  },
  {
    "path": "src/enums/creep_size.gd",
    "content": "class_name CreepSize extends Node\n\n\n# NOTE: order is important to be able to compare\nenum enm {\n\tMASS,\n\tCHALLENGE_MASS,\n\tNORMAL,\n\tAIR,\n\tCHAMPION,\n\tBOSS,\n\tCHALLENGE_BOSS,\n}\n\n\nstatic var _ordered_list: Array[CreepSize.enm] = [\n\tCreepSize.enm.MASS,\n\tCreepSize.enm.CHALLENGE_MASS,\n\tCreepSize.enm.NORMAL,\n\tCreepSize.enm.AIR,\n\tCreepSize.enm.CHAMPION,\n\tCreepSize.enm.BOSS,\n\tCreepSize.enm.CHALLENGE_BOSS,\n]\n\n\nstatic var _string_map: Dictionary = {\n\tCreepSize.enm.MASS: \"mass\",\n\tCreepSize.enm.NORMAL: \"normal\",\n\tCreepSize.enm.AIR: \"air\",\n\tCreepSize.enm.CHAMPION: \"champion\",\n\tCreepSize.enm.BOSS: \"boss\",\n\tCreepSize.enm.CHALLENGE_MASS: \"challenge mass\",\n\tCreepSize.enm.CHALLENGE_BOSS: \"challenge boss\",\n}\n\n\nstatic var _color_map: Dictionary = {\n\tCreepSize.enm.MASS: Color.ORANGE,\n\tCreepSize.enm.NORMAL: Color.DARK_SEA_GREEN,\n\tCreepSize.enm.AIR: Color.CORNFLOWER_BLUE,\n\tCreepSize.enm.CHAMPION: Color.MEDIUM_PURPLE,\n\tCreepSize.enm.BOSS: Color.ORANGE_RED,\n\tCreepSize.enm.CHALLENGE_MASS: Color.GOLD,\n\tCreepSize.enm.CHALLENGE_BOSS: Color.GOLD,\n}\n\n\nstatic var _item_drop_roll_count: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.AIR: 4,\n\tCreepSize.enm.CHAMPION: 4,\n\tCreepSize.enm.BOSS: 20,\n#\tNOTE: these values were derived values from JASS code.\n# \tfor challenge mass: 4 = WU[1] * 10 / 5 = 2 * 10 / 5\n# \tfor challenge boss: 40 = WU[7] * 10 / 5 = 20 * 10 / 5\n\tCreepSize.enm.CHALLENGE_MASS: 4,\n\tCreepSize.enm.CHALLENGE_BOSS: 40,\n}\n\nstatic var _score_multiplier: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.AIR: 4,\n\tCreepSize.enm.CHAMPION: 4,\n\tCreepSize.enm.BOSS: 20,\n#\tNOTE: these values were derived values from JASS code.\n# \tfor challenge mass: 20 = WU[1] * 10 = 2 * 10\n# \tfor challenge boss: 200 = WU[7] * 10 = 20 * 10\n\tCreepSize.enm.CHALLENGE_MASS: 20,\n\tCreepSize.enm.CHALLENGE_BOSS: 200,\n}\n\nstatic var _experience_map: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.AIR: 4,\n\tCreepSize.enm.CHAMPION: 4,\n\tCreepSize.enm.BOSS: 20,\n#\tNOTE: these values were derived values from JASS code.\n# \tfor challenge mass: 4 = 2 * WU[1] = 2 * 2\n# \tfor challenge boss: 40 = 2 * WU[7] = 2 * 20\n\tCreepSize.enm.CHALLENGE_MASS: 4,\n\tCreepSize.enm.CHALLENGE_BOSS: 40,\n}\n\nstatic var _weight_map: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.AIR: 4,\n\tCreepSize.enm.CHAMPION: 4,\n\tCreepSize.enm.BOSS: 20,\n\tCreepSize.enm.CHALLENGE_MASS: 2,\n\tCreepSize.enm.CHALLENGE_BOSS: 20,\n}\n\nstatic var _portal_damage_multiplier_map: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.AIR: 4,\n\tCreepSize.enm.CHAMPION: 4,\n\tCreepSize.enm.BOSS: 20,\n\tCreepSize.enm.CHALLENGE_MASS: 0,\n\tCreepSize.enm.CHALLENGE_BOSS: 0,\n}\n\nstatic var _gold_multiplier_map: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.AIR: 2,\n\tCreepSize.enm.CHAMPION: 4,\n\tCreepSize.enm.BOSS: 4,\n\tCreepSize.enm.CHALLENGE_MASS: 0,\n\tCreepSize.enm.CHALLENGE_BOSS: 0,\n}\n\nstatic var health_multiplier_map: Dictionary = {\n\tCreepSize.enm.MASS: 0.3,\n\tCreepSize.enm.NORMAL: 1.0,\n\tCreepSize.enm.AIR: 1.0,\n\tCreepSize.enm.CHAMPION: 1.75,\n\tCreepSize.enm.BOSS: 6.0,\n\tCreepSize.enm.CHALLENGE_MASS: 1.6,\n\tCreepSize.enm.CHALLENGE_BOSS: 12.0,\n}\n\nstatic var _base_mana_map: Dictionary = {\n\tCreepSize.enm.MASS: 100,\n\tCreepSize.enm.NORMAL: 200,\n\tCreepSize.enm.AIR: 400,\n\tCreepSize.enm.CHAMPION: 300,\n\tCreepSize.enm.BOSS: 2000,\n\tCreepSize.enm.CHALLENGE_MASS: 100,\n\tCreepSize.enm.CHALLENGE_BOSS: 3000,\n}\n\n\nstatic func get_list() -> Array[CreepSize.enm]:\n\treturn _ordered_list\n\n\nstatic func from_string(string: String) -> CreepSize.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn CreepSize.enm.MASS\n\n\nstatic func convert_to_string(type: CreepSize.enm) -> String:\n\treturn _string_map[type]\n\n\nstatic func get_display_string(type: CreepSize.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tCreepSize.enm.MASS: string = Utils.tr(\"SIZE_MASS\")\n\t\tCreepSize.enm.NORMAL: string = Utils.tr(\"SIZE_NORMAL\")\n\t\tCreepSize.enm.AIR: string = Utils.tr(\"SIZE_AIR\")\n\t\tCreepSize.enm.CHAMPION: string = Utils.tr(\"SIZE_CHAMPION\")\n\t\tCreepSize.enm.BOSS: string = Utils.tr(\"SIZE_BOSS\")\n\t\tCreepSize.enm.CHALLENGE_MASS: string = Utils.tr(\"SIZE_CHALLENGE_MASS\")\n\t\tCreepSize.enm.CHALLENGE_BOSS: string = Utils.tr(\"SIZE_CHALLENGE_BOSS\")\n\n\treturn string\n\n\nstatic func convert_to_colored_string(type: CreepSize.enm) -> String:\n\tvar string: String = get_display_string(type)\n\tvar color: Color = _color_map[type]\n\tvar out: String = Utils.get_colored_string(string, color)\n\n\treturn out\n\n\nstatic func get_item_drop_roll_count(type: CreepSize.enm) -> int:\n\treturn _item_drop_roll_count[type]\n\n\nstatic func get_score_multiplier(type: CreepSize.enm) -> float:\n\treturn _score_multiplier[type]\n\n\nstatic func get_weight(type: CreepSize.enm) -> float:\n\treturn _weight_map[type]\n\n\nstatic func get_experience(type: CreepSize.enm) -> float:\n\treturn _experience_map[type]\n\n\nstatic func get_gold_multiplier(type: CreepSize.enm) -> float:\n\treturn _gold_multiplier_map[type]\n\n\nstatic func get_portal_damage_multiplier(type: CreepSize.enm) -> float:\n\treturn _portal_damage_multiplier_map[type]\n\n\nstatic func is_challenge(type: CreepSize.enm) -> bool:\n\tvar out: bool = type == CreepSize.enm.CHALLENGE_MASS || type == CreepSize.enm.CHALLENGE_BOSS\n\n\treturn out\n\n\nstatic func get_base_mana(type: CreepSize.enm) -> float:\n\treturn _base_mana_map[type]\n\n\nstatic func convert_to_mod_dmg_type(category: CreepSize.enm) -> ModificationType.enm:\n\tconst creep_size_to_mod_map: Dictionary = {\n\t\tCreepSize.enm.MASS: ModificationType.enm.MOD_DMG_TO_MASS,\n\t\tCreepSize.enm.NORMAL: ModificationType.enm.MOD_DMG_TO_NORMAL,\n\t\tCreepSize.enm.CHAMPION: ModificationType.enm.MOD_DMG_TO_CHAMPION,\n\t\tCreepSize.enm.BOSS: ModificationType.enm.MOD_DMG_TO_BOSS,\n\t\tCreepSize.enm.AIR: ModificationType.enm.MOD_DMG_TO_AIR,\n#\t\tNOTE: this code is actually redundant because\n#\t\tcreep.get_size() function already converts challenge\n#\t\tsizes to \"simple\" sizes. Keeping it for\n#\t\tcompleteness.\n\t\tCreepSize.enm.CHALLENGE_MASS: ModificationType.enm.MOD_DMG_TO_MASS,\n\t\tCreepSize.enm.CHALLENGE_BOSS: ModificationType.enm.MOD_DMG_TO_BOSS,\n\t}\n\n\tvar mod_type: ModificationType.enm = creep_size_to_mod_map[category]\n\n\treturn mod_type\n"
  },
  {
    "path": "src/enums/difficulty.gd",
    "content": "class_name Difficulty extends Node\n\n\nenum enm {\n\tBEGINNER,\n\tEASY,\n\tMEDIUM,\n\tHARD,\n\tEXTREME,\n}\n\n\nstatic var _string_map: Dictionary = {\n\tDifficulty.enm.BEGINNER: \"beginner\",\n\tDifficulty.enm.EASY: \"easy\",\n\tDifficulty.enm.MEDIUM: \"medium\",\n\tDifficulty.enm.HARD: \"hard\",\n\tDifficulty.enm.EXTREME: \"extreme\",\n}\n\nstatic var _color_map: Dictionary = {\n\tDifficulty.enm.BEGINNER: Color.ROYAL_BLUE,\n\tDifficulty.enm.EASY: Color.LIME_GREEN,\n\tDifficulty.enm.MEDIUM: Color.YELLOW,\n\tDifficulty.enm.HARD: Color.RED,\n\tDifficulty.enm.EXTREME: Color.WEB_PURPLE,\n}\n\n\nstatic func convert_to_string(type: Difficulty.enm):\n\treturn _string_map[type]\n\n\nstatic func get_display_string(type: Difficulty.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tDifficulty.enm.BEGINNER: string = Utils.tr(\"DIFFICULTY_BEGINNER\")\n\t\tDifficulty.enm.EASY: string = Utils.tr(\"DIFFICULTY_EASY\")\n\t\tDifficulty.enm.MEDIUM: string = Utils.tr(\"DIFFICULTY_MEDIUM\")\n\t\tDifficulty.enm.HARD: string = Utils.tr(\"DIFFICULTY_HARD\")\n\t\tDifficulty.enm.EXTREME: string = Utils.tr(\"DIFFICULTY_EXTREME\")\n\n\treturn string\n\n\nstatic func from_string(string: String) -> Difficulty.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn Difficulty.enm.BEGINNER\n\n\nstatic func get_color(difficulty: Difficulty.enm) -> Color:\n\tvar color: Color = _color_map[difficulty]\n\n\treturn color\n\n\nstatic func convert_to_colored_string(type: Difficulty.enm) -> String:\n\tvar string: String = get_display_string(type)\n\tvar color: Color = get_color(type)\n\tvar out: String = Utils.get_colored_string(string, color)\n\n\treturn out\n"
  },
  {
    "path": "src/enums/display_mode.gd",
    "content": "class_name DisplayMode extends Node\n\n# NOTE: there is already a Window.Mode enum but it contains\n# all possible values in a specific order. This enum is\n# needed to represent indexes in the \"Display mode\" setting\n# in settings menu. For settings, we need only some of the\n# values and in a different order than Window.Mode.\n\nenum enm {\n\tFULLSCREEN,\n\tBORDERLESS,\n\tWINDOWED,\n}\n\nstatic var _window_mode_map: Dictionary = {\n\tDisplayMode.enm.FULLSCREEN: Window.Mode.MODE_EXCLUSIVE_FULLSCREEN,\n\tDisplayMode.enm.BORDERLESS: Window.Mode.MODE_FULLSCREEN,\n\tDisplayMode.enm.WINDOWED: Window.Mode.MODE_WINDOWED,\n}\n\n\nstatic func convert_to_window_mode(type: DisplayMode.enm) -> Window.Mode:\n\treturn _window_mode_map[type]\n"
  },
  {
    "path": "src/enums/element.gd",
    "content": "class_name Element extends Node\n\nenum enm {\n\tICE ,\n\tNATURE,\n\tFIRE,\n\tASTRAL,\n\tDARKNESS,\n\tIRON,\n\tSTORM,\n\tNONE,\n}\n\n\nstatic var _string_map: Dictionary = {\n\tElement.enm.ICE: \"ice\",\n\tElement.enm.NATURE: \"nature\",\n\tElement.enm.FIRE: \"fire\",\n\tElement.enm.ASTRAL: \"astral\",\n\tElement.enm.DARKNESS: \"darkness\",\n\tElement.enm.IRON: \"iron\",\n\tElement.enm.STORM: \"storm\",\n\tElement.enm.NONE: \"none\",\n}\n\nstatic var _main_attack_types_map: Dictionary = {\n\tElement.enm.ICE: [AttackType.enm.ELEMENTAL, AttackType.enm.ENERGY],\n\tElement.enm.NATURE: [AttackType.enm.PHYSICAL, AttackType.enm.DECAY, AttackType.enm.ESSENCE],\n\tElement.enm.FIRE: [AttackType.enm.ELEMENTAL, AttackType.enm.DECAY],\n\tElement.enm.ASTRAL: [AttackType.enm.ENERGY, AttackType.enm.ELEMENTAL, AttackType.enm.ARCANE],\n\tElement.enm.DARKNESS: [AttackType.enm.DECAY, AttackType.enm.PHYSICAL],\n\tElement.enm.IRON: [AttackType.enm.PHYSICAL, AttackType.enm.DECAY],\n\tElement.enm.STORM: [AttackType.enm.ENERGY, AttackType.enm.PHYSICAL],\n\tElement.enm.NONE: [AttackType.enm.PHYSICAL, AttackType.enm.PHYSICAL],\n}\n\n\nstatic var _dmg_from_element_map: Dictionary = {\n\tElement.enm.ICE: ModificationType.enm.MOD_DMG_FROM_ICE,\n\tElement.enm.NATURE: ModificationType.enm.MOD_DMG_FROM_NATURE,\n\tElement.enm.FIRE: ModificationType.enm.MOD_DMG_FROM_FIRE,\n\tElement.enm.ASTRAL: ModificationType.enm.MOD_DMG_FROM_ASTRAL,\n\tElement.enm.DARKNESS: ModificationType.enm.MOD_DMG_FROM_DARKNESS,\n\tElement.enm.IRON: ModificationType.enm.MOD_DMG_FROM_IRON,\n\tElement.enm.STORM: ModificationType.enm.MOD_DMG_FROM_STORM,\n\tElement.enm.NONE: ModificationType.enm.MOD_DMG_FROM_ICE,\n}\n\nstatic var _color_map: Dictionary = {\n\tElement.enm.ICE: Color.CORNFLOWER_BLUE,\n\tElement.enm.NATURE: Color.LIME_GREEN,\n\tElement.enm.FIRE: Color.ORANGE_RED,\n\tElement.enm.ASTRAL: Color.MEDIUM_AQUAMARINE,\n\tElement.enm.DARKNESS: Color.MEDIUM_PURPLE,\n\tElement.enm.IRON: Color.TAN,\n\tElement.enm.STORM: Color.LIGHT_YELLOW,\n\tElement.enm.NONE: Color.WHITE,\n}\n\n\nstatic func is_valid_string(string: String) -> bool:\n\tvar key = _string_map.find_key(string)\n\tvar is_valid: bool = key != null\n\n\treturn is_valid\n\n\nstatic func from_string(string: String) -> Element.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn Element.enm.ICE\n\n\nstatic func convert_to_string(element: Element.enm) -> String:\n\treturn _string_map[element]\n\n\nstatic func get_display_string(element: Element.enm) -> String:\n\tvar string: String\n\tmatch element:\n\t\tElement.enm.ICE: string = Utils.tr(\"ELEMENT_ICE\")\n\t\tElement.enm.NATURE: string = Utils.tr(\"ELEMENT_NATURE\")\n\t\tElement.enm.FIRE: string = Utils.tr(\"ELEMENT_FIRE\")\n\t\tElement.enm.ASTRAL: string = Utils.tr(\"ELEMENT_ASTRAL\")\n\t\tElement.enm.DARKNESS: string = Utils.tr(\"ELEMENT_DARKNESS\")\n\t\tElement.enm.IRON: string = Utils.tr(\"ELEMENT_IRON\")\n\t\tElement.enm.STORM: string = Utils.tr(\"ELEMENT_STORM\")\n\t\tElement.enm.NONE: string = \"none\"\n\n\treturn string\n\n\nstatic func convert_to_dmg_from_element_mod(element: Element.enm) -> ModificationType.enm:\n\treturn _dmg_from_element_map[element]\n\n\nstatic func convert_to_colored_string(type: Element.enm) -> String:\n\tvar string: String = get_display_string(type)\n\tvar color: Color = get_color(type)\n\tvar out: String = Utils.get_colored_string(string, color)\n\n\treturn out\n\n\nstatic func get_list() -> Array[Element.enm]:\n\treturn [\n\t\tElement.enm.ICE,\n\t\tElement.enm.NATURE,\n\t\tElement.enm.FIRE,\n\t\tElement.enm.ASTRAL,\n\t\tElement.enm.DARKNESS,\n\t\tElement.enm.IRON,\n\t\tElement.enm.STORM,\n\t]\n\n\nstatic func get_color(element: Element.enm) -> Color:\n\tvar color: Color = _color_map[element]\n\n\treturn color\n\n\nstatic func get_flavor_text(element: Element.enm) -> String:\n\tvar string: String\n\tmatch element:\n\t\tElement.enm.ICE: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_ICE\")\n\t\tElement.enm.NATURE: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_NATURE\")\n\t\tElement.enm.FIRE: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_FIRE\")\n\t\tElement.enm.ASTRAL: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_ASTRAL\")\n\t\tElement.enm.DARKNESS: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_DARKNESS\")\n\t\tElement.enm.IRON: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_IRON\")\n\t\tElement.enm.STORM: string = Utils.tr(\"ELEMENT_FLAVOR_TEXT_STORM\")\n\t\tElement.enm.NONE: string = \"none\"\n\n\treturn string\n\n\nstatic func get_main_attack_types(element: Element.enm) -> String:\n\tvar attack_enum_list: Array = _main_attack_types_map[element]\n\tvar attack_string_list: Array[String] = []\n\n\tfor attack_enum in attack_enum_list:\n\t\tvar attack_string: String = AttackType.convert_to_colored_string(attack_enum)\n\t\tattack_string_list.append(attack_string)\n\n\tvar combined_string: String = \", \".join(attack_string_list)\n\n\treturn combined_string\n"
  },
  {
    "path": "src/enums/game_mode.gd",
    "content": "class_name GameMode extends Node\n\n\nenum enm {\n\tBUILD,\n\tRANDOM_WITH_UPGRADES,\n\tTOTALLY_RANDOM,\n}\n\n\nstatic var _string_map: Dictionary = {\n\tGameMode.enm.BUILD: \"build\",\n\tGameMode.enm.RANDOM_WITH_UPGRADES: \"random_with_upgrades\",\n\tGameMode.enm.TOTALLY_RANDOM: \"totally_random\",\n}\n\nstatic var _sell_ratio_map: Dictionary = {\n\tGameMode.enm.BUILD: 0.5,\n\tGameMode.enm.RANDOM_WITH_UPGRADES: 0.75,\n\tGameMode.enm.TOTALLY_RANDOM: 0.75,\n}\n\n\nstatic func convert_to_string(type: GameMode.enm):\n\treturn _string_map[type]\n\n\nstatic func convert_to_display_string(type: GameMode.enm):\n\tvar string: String\n\tmatch type:\n\t\tGameMode.enm.BUILD: string = Utils.tr(\"GAME_MODE_BUILD\")\n\t\tGameMode.enm.RANDOM_WITH_UPGRADES: string = Utils.tr(\"GAME_MODE_RANDOM_WITH_UPGRADES\")\n\t\tGameMode.enm.TOTALLY_RANDOM: string = Utils.tr(\"GAME_MODE_TOTALLY_RANDOM\")\n\t\n\treturn string\n\n\nstatic func convert_to_long_display_string(type: GameMode.enm):\n\tvar string: String\n\tmatch type:\n\t\tGameMode.enm.BUILD: string = Utils.tr(\"GAME_MODE_LONG_BUILD\")\n\t\tGameMode.enm.RANDOM_WITH_UPGRADES: string = Utils.tr(\"GAME_MODE_LONG_RANDOM_WITH_UPGRADES\")\n\t\tGameMode.enm.TOTALLY_RANDOM: string = Utils.tr(\"GAME_MODE_LONG_TOTALLY_RANDOM\")\n\t\n\treturn string\n\n\nstatic func from_string(string: String) -> GameMode.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn GameMode.enm.BUILD\n\n\nstatic func get_sell_ratio(game_mode: GameMode.enm) -> float:\n\treturn _sell_ratio_map[game_mode]\n"
  },
  {
    "path": "src/enums/item_type.gd",
    "content": "class_name ItemType extends Node\n\nenum enm {\n\tREGULAR,\n\tOIL,\n\tCONSUMABLE,\n}\n\nconst LIST: Array[ItemType.enm] = [\n\t\tItemType.enm.REGULAR,\n\t\tItemType.enm.OIL,\n\t\tItemType.enm.CONSUMABLE,\n\t]\n\nstatic var _string_map: Dictionary = {\n\tItemType.enm.REGULAR: \"regular\",\n\tItemType.enm.OIL: \"oil\",\n\tItemType.enm.CONSUMABLE: \"consumable\",\n}\n\n\nstatic func get_list() -> Array[ItemType.enm]:\n\treturn LIST.duplicate()\n\n\nstatic func convert_to_string(type: ItemType.enm) -> String:\n\treturn _string_map[type]\n\n\nstatic func from_string(string: String) -> ItemType.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid item type string: \\\"%s\\\"\" % string)\n\n\t\treturn ItemType.enm.REGULAR\n"
  },
  {
    "path": "src/enums/language.gd",
    "content": "class_name Language extends Node\n\nenum enm {\n\tENGLISH,\n\tCHINESE,\n\tITALIAN,\n}\n\nstatic var language_map: Dictionary = {\n\tLanguage.enm.ENGLISH: \"en\",\n\tLanguage.enm.CHINESE: \"zh\",\n\tLanguage.enm.ITALIAN: \"it\",\n}\n\nstatic var language_option_map: Dictionary = {\n\tLanguage.enm.ENGLISH: 0,\n\tLanguage.enm.CHINESE: 1,\n\tLanguage.enm.ITALIAN: 2,\n}\n\nstatic var language_option_locale_map: Dictionary = {\n\t0:\"en\",\n\t1:\"zh\",\n\t2:\"it\",\n}\n\nstatic var default_language: String = \"en\"\n\nstatic func get_locale_from_enum (lan: Language.enm) -> String:\n\treturn language_map[lan]\n\nstatic func get_enum_from_option (opt: int) -> Language.enm:\n\treturn language_option_map[opt]\n\nstatic func get_option_from_locale (lan: String) -> int:\n\tvar language_option: Variant = language_option_locale_map.find_key(lan)\n\tif language_option == null:\n\t\treturn language_option_locale_map.find_key(default_language)\n\treturn int(language_option)\n\nstatic func get_locale_from_option (opt: int) -> String:\n\treturn language_option_locale_map[opt]\n"
  },
  {
    "path": "src/enums/modification_type.gd",
    "content": "class_name ModificationType extends Node\n\n# This is an enum which represents a \"modification\" on a\n# tower or creep. For example, attack crit chance, attack\n# speed, move speed, etc. Note that it is also used to\n# represent the based stat values, so the naming of\n# \"modification\" is a bit misleading.\n\n# NOTE: this enum is a bit convoluted because it lumps\n# modifications for towers and creeps together. This was\n# necessary because some modifications are shared and it is\n# more convenient to use the enum this way.\n\nenum enm {\n#\t-----------------------\n#\tTower modifications\n#\t-----------------------\n#\tModifications below only make sense when applied to\n#\ttowers\n\n#\t\"Damage to X creep size\" modifications\n\tMOD_DMG_TO_MASS,\n\tMOD_DMG_TO_NORMAL,\n\tMOD_DMG_TO_CHAMPION,\n\tMOD_DMG_TO_BOSS,\n\tMOD_DMG_TO_AIR,\n\n#\t\"Damage to X creep race\" modifications\n\tMOD_DMG_TO_UNDEAD,\n\tMOD_DMG_TO_MAGIC,\n\tMOD_DMG_TO_NATURE,\n\tMOD_DMG_TO_ORC,\n\tMOD_DMG_TO_HUMANOID,\n\tMOD_DMG_TO_CHALLENGE,\n\n# \tCrit modifications\n\n#\tModifies the chance that attacks of this unit will be\n#\tcritical\n#\t+0.01 = +1% crit chance\n# \tNote that initial value is equal to\n# \tConstants.INNATE_MOD_ATK_CRIT_CHANCE\n\tMOD_ATK_CRIT_CHANCE,\n\n#\tModifies the multiplier applied to critical attack\n#\tdamage.\n#\t+0.01 = +1% crit damage\n# \tNote that initial value is equal to\n# \tConstants.INNATE_MOD_ATK_CRIT_DAMAGE\n\tMOD_ATK_CRIT_DAMAGE,\n\n#\tModifies the multicrit value of this unit. Multicrit\n#\tdetermines the amount of types a single attack can crit.\n#\tNormally, attacks either don't crit or crit one time.\n#\tSome tower and item effects increase this value, making\n#\tit possible for an attack to crit 2 or more times. When\n#\tattack crits multiple times, the multiplier for crit\n#\tdamage is added multiple times.\n# \n#\t2 crits with x1.25 crit damage multiplier =\n# \t1.0 + 0.25 + 0.25 = x1.5 total multiplier\n\tMOD_MULTICRIT_COUNT,\n\n#\tModifies the chance that spells of this unit will be\n#\tcritical\n#\t+0.01 = +1% crit chance\n# \tNote that initial value is equal to\n# \tConstants.INNATE_MOD_SPELL_CRIT_CHANCE\n\tMOD_SPELL_CRIT_CHANCE,\n\n#\tModifies the damage multiplier for critical spell\n#\tdamage.\n#\t+0.01 = +1% crit damage\n# \tNote that initial value is equal to\n# \tConstants.INNATE_MOD_SPELL_CRIT_DAMAGE\n\tMOD_SPELL_CRIT_DAMAGE,\n\n# \tDamage modifications\n\n#\tModifies spell damage of this unit\n#\t+0.01 = +1% spell damage\n\tMOD_SPELL_DAMAGE_DEALT,\n\n#\tModifies the attack speed of this unit. Note that this\n#\tvalue divides the attack speed, so higher = faster\n#\t1s base attack speed with 150% MOD_ATTACKSPEED would be\n#\t1s / 1.5 = 0.66s\n#\t+0.01 = +1% attack speed\n\tMOD_ATTACKSPEED,\n\n#\tModifies the base damage of this unit. \"White\" numbers in WC3.\n#\t+1.0 = +1 to base damage\n\tMOD_DAMAGE_BASE,\n\n#\tModifies the base damage of this unit. \"White\" numbers\n#\tin WC3. Applied on top of MOD_DAMAGE_BASE.\n#\t0.01 = 1% damage increase\n\tMOD_DAMAGE_BASE_PERC,\n\n#\tModifies the add damage of this unit. \"Green\" numbers in WC3.\n#\tApplied on top of bonuses to base damage.\n#\t+1.0 = +1 to add damage\n\tMOD_DAMAGE_ADD,\n\n#\tModifies the add damage of this unit. \"Green\" numbers in\n#\tWC3. Applied on top of MOD_DAMAGE_ADD and bonuses to\n#\tbase damage.\n#\t+0.01 = +1% damage increase\n\tMOD_DAMAGE_ADD_PERC,\n\n#\tModifies the DPS of this unit. Applied after base damage\n#\tbonuses and add damage bonuses.\n#\t+1.0 = +1 DPS\n\tMOD_DPS_ADD,\n\n#\tAn extra modifier that\n#\tincreases total damage dealt after crit and other regular % modifiers.\n#\tIt is not included in DPS or DPS with crit calculations.\n\tMOD_DMG_TOTAL_MULTIPLIER,\n\n# \tMisc modifications\n\n#\tModifies the chance of item drops when this tower kills\n#\ta creep.\n#\t+0.01 = +1% chance\n\tMOD_ITEM_CHANCE_ON_KILL,\n\n#\tModifies the quality of item drops when this tower kills\n#\ta creep.\n#\t+0.01 = +1% quality\n\tMOD_ITEM_QUALITY_ON_KILL,\n\n#\tModifies the amount of experience this tower receives\n#\tfrom kills.\n#\t+0.01 = +1% experience change\n\tMOD_EXP_RECEIVED,\n\n#\tModifies the amount of bounty this tower receives\n#\tfrom kills.\n#\t+0.01 = +1% bounty change\n\tMOD_BOUNTY_RECEIVED,\n\n#\t-----------------------\n#\tCreep modifications\n#\t-----------------------\n#\tModifications below only make sense when applied to\n#\tcreeps\n\n#\tModifies the amount of experience given by this creep\n#\twhen killed.\n#\t+0.01 = +1% exp change\n\tMOD_EXP_GRANTED,\n\n#\tModifies the amount of bounty given by this creep\n#\twhen killed.\n#\t+0.01 = +1% bounty change\n\tMOD_BOUNTY_GRANTED,\n\n#\tModifies the amount of attack damage taken by this creep.\n#\t+0.01 = +1% attack damage\n\tMOD_ATK_DAMAGE_RECEIVED,\n\n#\tModifies the amount of spell damage taken by this creep.\n#\t+0.01 = +1% spell damage\n\tMOD_SPELL_DAMAGE_RECEIVED,\n\n#\tModifies the chance of item drops when this creep is\n#\tkilled.\n#\t+0.01 = +1% chance\n\tMOD_ITEM_CHANCE_ON_DEATH,\n\n#\tModifies the quality of item drops when this creep is\n#\tkilled.\n#\t+0.01 = +1% quality\n\tMOD_ITEM_QUALITY_ON_DEATH,\n\n#\tModifies health of this creep\n#\t+1.0 = +1 health\n\tMOD_HP,\n\n#\tModifies health of this creep. Applied on top of MOD_HP.\n#\t+0.01 = +1% health\n\tMOD_HP_PERC,\n\n#\tModifies health regeneration of this creep.\n#\t+1.0 = +1 health / sec regeneration\n\tMOD_HP_REGEN,\n\n#\tModifies health regeneration of this creep. Applied on\n#\ttop of MOD_HP_REGEN.\n#\t+0.01 = +1% health regeneration\n\tMOD_HP_REGEN_PERC,\n\n#\tModifies armor.\n#\t+1.0 = +1 armor\n\tMOD_ARMOR,\n\n#\tModifies armor. Applied on top of MOD_ARMOR.\n#\t+0.01 = +1% armor\n\tMOD_ARMOR_PERC,\n\n#\tChanges movement speed of this creep.\n#\t+0.01 = +1% movement speed\n\tMOD_MOVESPEED,\n\n#\tChanges movement speed of this creep.\n#\t+1.0 = +1 movement speed (speed varies between 100 and 500)\n\tMOD_MOVESPEED_ABSOLUTE,\n\n#\t\"Damage from X element\" modifications. Modifies damage\n#\tby multiplying\n\tMOD_DMG_FROM_ASTRAL,\n\tMOD_DMG_FROM_DARKNESS,\n\tMOD_DMG_FROM_NATURE,\n\tMOD_DMG_FROM_FIRE,\n\tMOD_DMG_FROM_ICE,\n\tMOD_DMG_FROM_STORM,\n\tMOD_DMG_FROM_IRON,\n\n#\t-----------------------\n#\tGeneral modifications\n#\t-----------------------\n#\tModifications below can be applied to both towers and\n#\tcreeps.\n\n#\tModifies trigger chances of this unit, whenever\n#\tcalc_chance() is called.\n#\t+0.01 = +1% trigger chances.\n\tMOD_TRIGGER_CHANCES,\n\n#\tModifies the duration of buffs applied by this unit on\n#\tother units.\n#\t+0.01 = +1% buff duration\n\tMOD_BUFF_DURATION,\n\n#\tModifies the duration of debuffs (negative buffs)\n#\tapplied on this unit by other units. Common scenario is\n#\twhere a creep stuns a tower for 3s. This modification\n#\twould reduce the stun duration.\n#\t+0.01 = +1% debuff duration\n\tMOD_DEBUFF_DURATION,\n\t\n#\tModifies mana of this unit.\n#\t+1.0 = +1 mana\n\tMOD_MANA,\n\n#\tModifies mana of this unit. Applied on top of MOD_MANA.\n#\t+0.01 = +1% mana\n\tMOD_MANA_PERC,\n\n#\tModifies mana regen of this unit.\n#\t+1.0 = +1 mana regen / second\n\tMOD_MANA_REGEN,\n\n#\tModifies mana of this unit. Applied on top of MOD_MANA_REGEN.\n#\t+0.01 = +1% mana regen\n\tMOD_MANA_REGEN_PERC,\n}\n\nconst _types_without_percent: Array[ModificationType.enm] = [\n\tModificationType.enm.MOD_ARMOR,\n\tModificationType.enm.MOD_MOVESPEED_ABSOLUTE,\n\tModificationType.enm.MOD_DAMAGE_BASE,\n\tModificationType.enm.MOD_DAMAGE_ADD,\n\tModificationType.enm.MOD_DPS_ADD,\n\tModificationType.enm.MOD_HP,\n\tModificationType.enm.MOD_HP_REGEN,\n\tModificationType.enm.MOD_MANA,\n\tModificationType.enm.MOD_MANA_REGEN,\n\tModificationType.enm.MOD_MULTICRIT_COUNT,\n]\n\n\nconst _mod_to_string_map: Dictionary = {\n\tModificationType.enm.MOD_DMG_TO_MASS: \"MOD_DMG_TO_MASS\",\n\tModificationType.enm.MOD_DMG_TO_NORMAL: \"MOD_DMG_TO_NORMAL\",\n\tModificationType.enm.MOD_DMG_TO_CHAMPION: \"MOD_DMG_TO_CHAMPION\",\n\tModificationType.enm.MOD_DMG_TO_BOSS: \"MOD_DMG_TO_BOSS\",\n\tModificationType.enm.MOD_DMG_TO_AIR: \"MOD_DMG_TO_AIR\",\n\tModificationType.enm.MOD_DMG_TO_UNDEAD: \"MOD_DMG_TO_UNDEAD\",\n\tModificationType.enm.MOD_DMG_TO_MAGIC: \"MOD_DMG_TO_MAGIC\",\n\tModificationType.enm.MOD_DMG_TO_NATURE: \"MOD_DMG_TO_NATURE\",\n\tModificationType.enm.MOD_DMG_TO_ORC: \"MOD_DMG_TO_ORC\",\n\tModificationType.enm.MOD_DMG_TO_HUMANOID: \"MOD_DMG_TO_HUMANOID\",\n\tModificationType.enm.MOD_DMG_TO_CHALLENGE: \"MOD_DMG_TO_CHALLENGE\",\n\tModificationType.enm.MOD_ATK_CRIT_CHANCE: \"MOD_ATK_CRIT_CHANCE\",\n\tModificationType.enm.MOD_ATK_CRIT_DAMAGE: \"MOD_ATK_CRIT_DAMAGE\",\n\tModificationType.enm.MOD_MULTICRIT_COUNT: \"MOD_MULTICRIT_COUNT\",\n\tModificationType.enm.MOD_SPELL_CRIT_CHANCE: \"MOD_SPELL_CRIT_CHANCE\",\n\tModificationType.enm.MOD_SPELL_CRIT_DAMAGE: \"MOD_SPELL_CRIT_DAMAGE\",\n\tModificationType.enm.MOD_SPELL_DAMAGE_DEALT: \"MOD_SPELL_DAMAGE_DEALT\",\n\tModificationType.enm.MOD_ATTACKSPEED: \"MOD_ATTACKSPEED\",\n\tModificationType.enm.MOD_DAMAGE_BASE: \"MOD_DAMAGE_BASE\",\n\tModificationType.enm.MOD_DAMAGE_BASE_PERC: \"MOD_DAMAGE_BASE_PERC\",\n\tModificationType.enm.MOD_DAMAGE_ADD: \"MOD_DAMAGE_ADD\",\n\tModificationType.enm.MOD_DAMAGE_ADD_PERC: \"MOD_DAMAGE_ADD_PERC\",\n\tModificationType.enm.MOD_DPS_ADD: \"MOD_DPS_ADD\",\n\tModificationType.enm.MOD_DMG_TOTAL_MULTIPLIER: \"MOD_DMG_TOTAL_MULTIPLIER\",\n\tModificationType.enm.MOD_ITEM_CHANCE_ON_KILL: \"MOD_ITEM_CHANCE_ON_KILL\",\n\tModificationType.enm.MOD_ITEM_QUALITY_ON_KILL: \"MOD_ITEM_QUALITY_ON_KILL\",\n\tModificationType.enm.MOD_EXP_RECEIVED: \"MOD_EXP_RECEIVED\",\n\tModificationType.enm.MOD_BOUNTY_RECEIVED: \"MOD_BOUNTY_RECEIVED\",\n\tModificationType.enm.MOD_EXP_GRANTED: \"MOD_EXP_GRANTED\",\n\tModificationType.enm.MOD_BOUNTY_GRANTED: \"MOD_BOUNTY_GRANTED\",\n\tModificationType.enm.MOD_ATK_DAMAGE_RECEIVED: \"MOD_ATK_DAMAGE_RECEIVED\",\n\tModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED: \"MOD_SPELL_DAMAGE_RECEIVED\",\n\tModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH: \"MOD_ITEM_CHANCE_ON_DEATH\",\n\tModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH: \"MOD_ITEM_QUALITY_ON_DEATH\",\n\tModificationType.enm.MOD_HP: \"MOD_HP\",\n\tModificationType.enm.MOD_HP_PERC: \"MOD_HP_PERC\",\n\tModificationType.enm.MOD_HP_REGEN: \"MOD_HP_REGEN\",\n\tModificationType.enm.MOD_HP_REGEN_PERC: \"MOD_HP_REGEN_PERC\",\n\tModificationType.enm.MOD_ARMOR: \"MOD_ARMOR\",\n\tModificationType.enm.MOD_ARMOR_PERC: \"MOD_ARMOR_PERC\",\n\tModificationType.enm.MOD_MOVESPEED: \"MOD_MOVESPEED\",\n\tModificationType.enm.MOD_MOVESPEED_ABSOLUTE: \"MOD_MOVESPEED_ABSOLUTE\",\n\tModificationType.enm.MOD_DMG_FROM_ASTRAL: \"MOD_DMG_FROM_ASTRAL\",\n\tModificationType.enm.MOD_DMG_FROM_DARKNESS: \"MOD_DMG_FROM_DARKNESS\",\n\tModificationType.enm.MOD_DMG_FROM_NATURE: \"MOD_DMG_FROM_NATURE\",\n\tModificationType.enm.MOD_DMG_FROM_FIRE: \"MOD_DMG_FROM_FIRE\",\n\tModificationType.enm.MOD_DMG_FROM_ICE: \"MOD_DMG_FROM_ICE\",\n\tModificationType.enm.MOD_DMG_FROM_STORM: \"MOD_DMG_FROM_STORM\",\n\tModificationType.enm.MOD_DMG_FROM_IRON: \"MOD_DMG_FROM_IRON\",\n\tModificationType.enm.MOD_TRIGGER_CHANCES: \"MOD_TRIGGER_CHANCES\",\n\tModificationType.enm.MOD_BUFF_DURATION: \"MOD_BUFF_DURATION\",\n\tModificationType.enm.MOD_DEBUFF_DURATION: \"MOD_DEBUFF_DURATION\",\n\tModificationType.enm.MOD_MANA: \"MOD_MANA\",\n\tModificationType.enm.MOD_MANA_PERC: \"MOD_MANA_PERC\",\n\tModificationType.enm.MOD_MANA_REGEN: \"MOD_MANA_REGEN\",\n\tModificationType.enm.MOD_MANA_REGEN_PERC: \"MOD_MANA_REGEN_PERC\",\n}\n\n\nconst _string_to_mod_map: Dictionary = {\n\t\"MOD_DMG_TO_MASS\": ModificationType.enm.MOD_DMG_TO_MASS,\n\t\"MOD_DMG_TO_NORMAL\": ModificationType.enm.MOD_DMG_TO_NORMAL,\n\t\"MOD_DMG_TO_CHAMPION\": ModificationType.enm.MOD_DMG_TO_CHAMPION,\n\t\"MOD_DMG_TO_BOSS\": ModificationType.enm.MOD_DMG_TO_BOSS,\n\t\"MOD_DMG_TO_AIR\": ModificationType.enm.MOD_DMG_TO_AIR,\n\t\"MOD_DMG_TO_UNDEAD\": ModificationType.enm.MOD_DMG_TO_UNDEAD,\n\t\"MOD_DMG_TO_MAGIC\": ModificationType.enm.MOD_DMG_TO_MAGIC,\n\t\"MOD_DMG_TO_NATURE\": ModificationType.enm.MOD_DMG_TO_NATURE,\n\t\"MOD_DMG_TO_ORC\": ModificationType.enm.MOD_DMG_TO_ORC,\n\t\"MOD_DMG_TO_HUMANOID\": ModificationType.enm.MOD_DMG_TO_HUMANOID,\n\t\"MOD_DMG_TO_CHALLENGE\": ModificationType.enm.MOD_DMG_TO_CHALLENGE,\n\t\"MOD_ATK_CRIT_CHANCE\": ModificationType.enm.MOD_ATK_CRIT_CHANCE,\n\t\"MOD_ATK_CRIT_DAMAGE\": ModificationType.enm.MOD_ATK_CRIT_DAMAGE,\n\t\"MOD_MULTICRIT_COUNT\": ModificationType.enm.MOD_MULTICRIT_COUNT,\n\t\"MOD_SPELL_CRIT_CHANCE\": ModificationType.enm.MOD_SPELL_CRIT_CHANCE,\n\t\"MOD_SPELL_CRIT_DAMAGE\": ModificationType.enm.MOD_SPELL_CRIT_DAMAGE,\n\t\"MOD_SPELL_DAMAGE_DEALT\": ModificationType.enm.MOD_SPELL_DAMAGE_DEALT,\n\t\"MOD_ATTACKSPEED\": ModificationType.enm.MOD_ATTACKSPEED,\n\t\"MOD_DAMAGE_BASE\": ModificationType.enm.MOD_DAMAGE_BASE,\n\t\"MOD_DAMAGE_BASE_PERC\": ModificationType.enm.MOD_DAMAGE_BASE_PERC,\n\t\"MOD_DAMAGE_ADD\": ModificationType.enm.MOD_DAMAGE_ADD,\n\t\"MOD_DAMAGE_ADD_PERC\": ModificationType.enm.MOD_DAMAGE_ADD_PERC,\n\t\"MOD_DPS_ADD\": ModificationType.enm.MOD_DPS_ADD,\n\t\"MOD_DMG_TOTAL_MULTIPLIER\": ModificationType.enm.MOD_DMG_TOTAL_MULTIPLIER,\n\t\"MOD_ITEM_CHANCE_ON_KILL\": ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL,\n\t\"MOD_ITEM_QUALITY_ON_KILL\": ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL,\n\t\"MOD_EXP_RECEIVED\": ModificationType.enm.MOD_EXP_RECEIVED,\n\t\"MOD_BOUNTY_RECEIVED\": ModificationType.enm.MOD_BOUNTY_RECEIVED,\n\t\"MOD_EXP_GRANTED\": ModificationType.enm.MOD_EXP_GRANTED,\n\t\"MOD_BOUNTY_GRANTED\": ModificationType.enm.MOD_BOUNTY_GRANTED,\n\t\"MOD_ATK_DAMAGE_RECEIVED\": ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED,\n\t\"MOD_SPELL_DAMAGE_RECEIVED\": ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED,\n\t\"MOD_ITEM_CHANCE_ON_DEATH\": ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH,\n\t\"MOD_ITEM_QUALITY_ON_DEATH\": ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH,\n\t\"MOD_HP\": ModificationType.enm.MOD_HP,\n\t\"MOD_HP_PERC\": ModificationType.enm.MOD_HP_PERC,\n\t\"MOD_HP_REGEN\": ModificationType.enm.MOD_HP_REGEN,\n\t\"MOD_HP_REGEN_PERC\": ModificationType.enm.MOD_HP_REGEN_PERC,\n\t\"MOD_ARMOR\": ModificationType.enm.MOD_ARMOR,\n\t\"MOD_ARMOR_PERC\": ModificationType.enm.MOD_ARMOR_PERC,\n\t\"MOD_MOVESPEED\": ModificationType.enm.MOD_MOVESPEED,\n\t\"MOD_MOVESPEED_ABSOLUTE\": ModificationType.enm.MOD_MOVESPEED_ABSOLUTE,\n\t\"MOD_DMG_FROM_ASTRAL\": ModificationType.enm.MOD_DMG_FROM_ASTRAL,\n\t\"MOD_DMG_FROM_DARKNESS\": ModificationType.enm.MOD_DMG_FROM_DARKNESS,\n\t\"MOD_DMG_FROM_NATURE\": ModificationType.enm.MOD_DMG_FROM_NATURE,\n\t\"MOD_DMG_FROM_FIRE\": ModificationType.enm.MOD_DMG_FROM_FIRE,\n\t\"MOD_DMG_FROM_ICE\": ModificationType.enm.MOD_DMG_FROM_ICE,\n\t\"MOD_DMG_FROM_STORM\": ModificationType.enm.MOD_DMG_FROM_STORM,\n\t\"MOD_DMG_FROM_IRON\": ModificationType.enm.MOD_DMG_FROM_IRON,\n\t\"MOD_TRIGGER_CHANCES\": ModificationType.enm.MOD_TRIGGER_CHANCES,\n\t\"MOD_BUFF_DURATION\": ModificationType.enm.MOD_BUFF_DURATION,\n\t\"MOD_DEBUFF_DURATION\": ModificationType.enm.MOD_DEBUFF_DURATION,\n\t\"MOD_MANA\": ModificationType.enm.MOD_MANA,\n\t\"MOD_MANA_PERC\": ModificationType.enm.MOD_MANA_PERC,\n\t\"MOD_MANA_REGEN\": ModificationType.enm.MOD_MANA_REGEN,\n\t\"MOD_MANA_REGEN_PERC\": ModificationType.enm.MOD_MANA_REGEN_PERC,\n}\n\n\nstatic func from_string(string: String) -> ModificationType.enm:\n\tif _string_to_mod_map.has(string):\n\t\treturn _string_to_mod_map[string]\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_to_mod_map.values()])\n\n\t\treturn ModificationType.enm.MOD_ARMOR\n\n\nstatic func convert_to_string(type: ModificationType.enm) -> String:\n\treturn _mod_to_string_map[type]\n\n\nstatic func get_display_string(type: ModificationType.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tModificationType.enm.MOD_ARMOR: string = Utils.tr(\"MOD_ARMOR_TEXT\")\n\t\tModificationType.enm.MOD_ARMOR_PERC: string = Utils.tr(\"MOD_ARMOR_PERC_TEXT\")\n\t\tModificationType.enm.MOD_EXP_GRANTED: string = Utils.tr(\"MOD_EXP_GRANTED_TEXT\")\n\t\tModificationType.enm.MOD_EXP_RECEIVED: string = Utils.tr(\"MOD_EXP_RECEIVED_TEXT\")\n\t\tModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED: string = Utils.tr(\"MOD_SPELL_DAMAGE_RECEIVED_TEXT\")\n\t\tModificationType.enm.MOD_SPELL_DAMAGE_DEALT: string = Utils.tr(\"MOD_SPELL_DAMAGE_DEALT_TEXT\")\n\t\tModificationType.enm.MOD_SPELL_CRIT_DAMAGE: string = Utils.tr(\"MOD_SPELL_CRIT_DAMAGE_TEXT\")\n\t\tModificationType.enm.MOD_SPELL_CRIT_CHANCE: string = Utils.tr(\"MOD_SPELL_CRIT_CHANCE_TEXT\")\n\t\tModificationType.enm.MOD_BOUNTY_GRANTED: string = Utils.tr(\"MOD_BOUNTY_GRANTED_TEXT\")\n\t\tModificationType.enm.MOD_BOUNTY_RECEIVED: string = Utils.tr(\"MOD_BOUNTY_RECEIVED_TEXT\")\n\t\tModificationType.enm.MOD_ATK_CRIT_CHANCE: string = Utils.tr(\"MOD_ATK_CRIT_CHANCE_TEXT\")\n\t\tModificationType.enm.MOD_ATK_CRIT_DAMAGE: string = Utils.tr(\"MOD_ATK_CRIT_DAMAGE_TEXT\")\n\t\tModificationType.enm.MOD_ATK_DAMAGE_RECEIVED: string = Utils.tr(\"MOD_ATK_DAMAGE_RECEIVED_TEXT\")\n\t\tModificationType.enm.MOD_ATTACKSPEED: string = Utils.tr(\"MOD_ATTACKSPEED_TEXT\")\n\t\tModificationType.enm.MOD_MULTICRIT_COUNT: string = Utils.tr(\"MOD_MULTICRIT_COUNT_TEXT\")\n\t\tModificationType.enm.MOD_ITEM_CHANCE_ON_KILL: string = Utils.tr(\"MOD_ITEM_CHANCE_ON_KILL_TEXT\")\n\t\tModificationType.enm.MOD_ITEM_QUALITY_ON_KILL: string = Utils.tr(\"MOD_ITEM_QUALITY_ON_KILL_TEXT\")\n\t\tModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH: string = Utils.tr(\"MOD_ITEM_CHANCE_ON_DEATH_TEXT\")\n\t\tModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH: string = Utils.tr(\"MOD_ITEM_QUALITY_ON_DEATH_TEXT\")\n\t\tModificationType.enm.MOD_BUFF_DURATION: string = Utils.tr(\"MOD_BUFF_DURATION_TEXT\")\n\t\tModificationType.enm.MOD_DEBUFF_DURATION: string = Utils.tr(\"MOD_DEBUFF_DURATION_TEXT\")\n\t\tModificationType.enm.MOD_TRIGGER_CHANCES: string = Utils.tr(\"MOD_TRIGGER_CHANCES_TEXT\")\n\t\tModificationType.enm.MOD_MOVESPEED: string = Utils.tr(\"MOD_MOVESPEED_TEXT\")\n\t\tModificationType.enm.MOD_MOVESPEED_ABSOLUTE: string = Utils.tr(\"MOD_MOVESPEED_ABSOLUTE_TEXT\")\n\t\tModificationType.enm.MOD_DAMAGE_BASE: string = Utils.tr(\"MOD_DAMAGE_BASE_TEXT\")\n\t\tModificationType.enm.MOD_DAMAGE_BASE_PERC: string = Utils.tr(\"MOD_DAMAGE_BASE_PERC_TEXT\")\n\t\tModificationType.enm.MOD_DAMAGE_ADD: string = Utils.tr(\"MOD_DAMAGE_ADD_TEXT\")\n\t\tModificationType.enm.MOD_DAMAGE_ADD_PERC: string = Utils.tr(\"MOD_DAMAGE_ADD_PERC_TEXT\")\n\t\tModificationType.enm.MOD_DPS_ADD: string = Utils.tr(\"MOD_DPS_ADD_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TOTAL_MULTIPLIER: string = Utils.tr(\"MOD_DMG_TOTAL_MULTIPLIER\")\n\t\tModificationType.enm.MOD_HP: string = Utils.tr(\"MOD_HP_TEXT\")\n\t\tModificationType.enm.MOD_HP_PERC: string = Utils.tr(\"MOD_HP_PERC_TEXT\")\n\t\tModificationType.enm.MOD_HP_REGEN: string = Utils.tr(\"MOD_HP_REGEN_TEXT\")\n\t\tModificationType.enm.MOD_HP_REGEN_PERC: string = Utils.tr(\"MOD_HP_REGEN_PERC_TEXT\")\n\t\tModificationType.enm.MOD_MANA: string = Utils.tr(\"MOD_MANA_TEXT\")\n\t\tModificationType.enm.MOD_MANA_PERC: string = Utils.tr(\"MOD_MANA_PERC_TEXT\")\n\t\tModificationType.enm.MOD_MANA_REGEN: string = Utils.tr(\"MOD_MANA_REGEN_TEXT\")\n\t\tModificationType.enm.MOD_MANA_REGEN_PERC: string = Utils.tr(\"MOD_MANA_REGEN_PERC_TEXT\")\n\n\t\tModificationType.enm.MOD_DMG_TO_MASS: string = Utils.tr(\"MOD_DMG_TO_MASS_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_NORMAL: string = Utils.tr(\"MOD_DMG_TO_NORMAL_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_CHAMPION: string = Utils.tr(\"MOD_DMG_TO_CHAMPION_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_BOSS: string = Utils.tr(\"MOD_DMG_TO_BOSS_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_AIR: string = Utils.tr(\"MOD_DMG_TO_AIR_TEXT\")\n\n\t\tModificationType.enm.MOD_DMG_TO_UNDEAD: string = Utils.tr(\"MOD_DMG_TO_UNDEAD_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_MAGIC: string = Utils.tr(\"MOD_DMG_TO_MAGIC_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_NATURE: string = Utils.tr(\"MOD_DMG_TO_NATURE_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_ORC: string = Utils.tr(\"MOD_DMG_TO_ORC_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_HUMANOID: string = Utils.tr(\"MOD_DMG_TO_HUMANOID_TEXT\")\n\t\tModificationType.enm.MOD_DMG_TO_CHALLENGE: string = Utils.tr(\"MOD_DMG_TO_CHALLENGE_TEXT\")\n\n\t\tModificationType.enm.MOD_DMG_FROM_ASTRAL: string = Utils.tr(\"MOD_DMG_FROM_ASTRAL_TEXT\")\n\t\tModificationType.enm.MOD_DMG_FROM_DARKNESS: string = Utils.tr(\"MOD_DMG_FROM_DARKNESS_TEXT\")\n\t\tModificationType.enm.MOD_DMG_FROM_NATURE: string = Utils.tr(\"MOD_DMG_FROM_NATURE_TEXT\")\n\t\tModificationType.enm.MOD_DMG_FROM_FIRE: string = Utils.tr(\"MOD_DMG_FROM_FIRE_TEXT\")\n\t\tModificationType.enm.MOD_DMG_FROM_ICE: string = Utils.tr(\"MOD_DMG_FROM_ICE_TEXT\")\n\t\tModificationType.enm.MOD_DMG_FROM_STORM: string = Utils.tr(\"MOD_DMG_FROM_STORM_TEXT\")\n\t\tModificationType.enm.MOD_DMG_FROM_IRON: string = Utils.tr(\"MOD_DMG_FROM_IRON_TEXT\")\n\t\t_: push_error(\"Unhandled type: \", type)\n\t\n\treturn string\n\n\n# Returns true for values like MOD_ARMOR_PERC \"+10% armor\"\n# Returns false for values like MOD_ARMOR \"+10 armor\"\nstatic func get_is_percentage(type: ModificationType.enm) -> bool:\n\treturn !_types_without_percent.has(type)\n"
  },
  {
    "path": "src/enums/player_mode.gd",
    "content": "class_name PlayerMode extends Node\n\n\nenum enm {\n\tSINGLEPLAYER,\n\tMULTIPLAYER,\n}\n"
  },
  {
    "path": "src/enums/rarity.gd",
    "content": "class_name Rarity extends Node\n\n\nenum enm {\n\tCOMMON,\n\tUNCOMMON,\n\tRARE,\n\tUNIQUE,\n}\n\n\nstatic var _string_map: Dictionary = {\n\tRarity.enm.COMMON: \"common\",\n\tRarity.enm.UNCOMMON: \"uncommon\",\n\tRarity.enm.RARE: \"rare\",\n\tRarity.enm.UNIQUE: \"unique\",\n}\n\nstatic var _color_map: Dictionary = {\n\tRarity.enm.COMMON: Color.GREEN,\n\tRarity.enm.UNCOMMON: Color.ROYAL_BLUE,\n\tRarity.enm.RARE: Color.MEDIUM_PURPLE,\n\tRarity.enm.UNIQUE: Color.GOLD,\n}\n\n\nstatic func convert_from_string(string: String) -> Rarity.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn Rarity.enm.COMMON\n\n\nstatic func convert_to_string(rarity: Rarity.enm) -> String:\n\treturn _string_map[rarity]\n\n\nstatic func get_display_string(type: Rarity.enm) -> String:\n\tvar string: String\n\tmatch type:\n\t\tRarity.enm.COMMON: string = Utils.tr(\"RARITY_COMMON\")\n\t\tRarity.enm.UNCOMMON: string = Utils.tr(\"RARITY_UNCOMMON\")\n\t\tRarity.enm.RARE: string = Utils.tr(\"RARITY_RARE\")\n\t\tRarity.enm.UNIQUE: string = Utils.tr(\"RARITY_UNIQUE\")\n\t\n\treturn string\n\n\nstatic func get_color(rarity: Rarity.enm) -> Color:\n\treturn _color_map[rarity]\n\n\nstatic func get_list() -> Array[Rarity.enm]:\n\treturn [\n\t\tRarity.enm.COMMON,\n\t\tRarity.enm.UNCOMMON,\n\t\tRarity.enm.RARE,\n\t\tRarity.enm.UNIQUE,\n\t]\n"
  },
  {
    "path": "src/enums/team_mode.gd",
    "content": "class_name TeamMode extends Node\n\n\n# This enum defines how players are placed into teams.\n\n\nenum enm {\n\tONE_PLAYER_PER_TEAM,\n\tTWO_PLAYERS_PER_TEAM,\n}\n\nstatic var _string_map: Dictionary = {\n\tTeamMode.enm.ONE_PLAYER_PER_TEAM: \"ffa\",\n\tTeamMode.enm.TWO_PLAYERS_PER_TEAM: \"coop\",\n}\n\n\nstatic var _player_count_max_map: Dictionary = {\n\tTeamMode.enm.ONE_PLAYER_PER_TEAM: 4,\n\tTeamMode.enm.TWO_PLAYERS_PER_TEAM: 8,\n}\n\n\nstatic var _player_count_per_team_map: Dictionary = {\n\tTeamMode.enm.ONE_PLAYER_PER_TEAM: 1,\n\tTeamMode.enm.TWO_PLAYERS_PER_TEAM: 2,\n}\n\n\nstatic func convert_to_string(type: TeamMode.enm):\n\treturn _string_map[type]\n\n\nstatic func from_string(string: String) -> TeamMode.enm:\n\tvar key = _string_map.find_key(string)\n\t\n\tif key != null:\n\t\treturn key\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_map.values()])\n\n\t\treturn TeamMode.enm.ONE_PLAYER_PER_TEAM\n\n\nstatic func convert_to_display_string(type: TeamMode.enm):\n\tvar string: String\n\tmatch type:\n\t\tTeamMode.enm.ONE_PLAYER_PER_TEAM: string = Utils.tr(\"TEAM_MODE_FFA\")\n\t\tTeamMode.enm.TWO_PLAYERS_PER_TEAM: string = Utils.tr(\"TEAM_MODE_COOP\")\n\n\treturn string\n\n\nstatic func get_player_count_max(type: TeamMode.enm):\n\treturn _player_count_max_map[type]\n\n\nstatic func get_player_count_per_team(type: TeamMode.enm):\n\treturn _player_count_per_team_map[type]\n"
  },
  {
    "path": "src/game_scene/build_space.gd",
    "content": "class_name BuildSpace extends Node\n\n\n# Keeps track of spaces which are occupied by towers.\n\n\n# List of offsets for getting 4 quarter tiles around a\n# position at an intersection. These positions use the\n# rotated top-down coordinate system, where tile origin is\n# at the bottom left corner of the tile.\n# NOTE: order is important because get_build_info_for_pos()\n# depens on it.\nconst QUARTER_OFFSET_LIST_NORMAL: Array[Vector2i] = [\n#\tx.\n#\t..\n\tVector2i(-1, 0),\n#\t.x\n#\t..\n\tVector2i(0, 0),\n#\t..\n#\t.x\n\tVector2i(0, 1),\n#\t..\n#\tx.\n\tVector2i(-1, 1),\n]\n\n# Alternative list for Maverick builder which doesn't allow\n# adjacent towers.\nconst QUARTER_OFFSET_LIST_BIG: Array[Vector2i] = [\n#\tUp-left\n\tVector2i(-1, 0),\n\tVector2i(-2, 0),\n\tVector2i(-2, -1),\n\tVector2i(-1, -1),\n\n#\tUp-right\n\tVector2i(0, 0),\n\tVector2i(0, -1),\n\tVector2i(1, -1),\n\tVector2i(1, 0),\n\t\n#\tBottom-left\n\tVector2i(0, 1),\n\tVector2i(1, 1),\n\tVector2i(1, 2),\n\tVector2i(0, 2),\n\t\n#\tBottom-right\n\tVector2i(-1, 1),\n\tVector2i(-1, 2),\n\tVector2i(-2, 2),\n\tVector2i(-2, 1),\n]\n\nvar _occupied_map: Dictionary = {}\n# Map of {Vector2i pos => player id}\n# If a position is buildable for player X then this map will\n# contain position mapped to \"X\" id.\nvar _buildable_cells: Dictionary = {}\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_buildable_cells(player: Player, buildable_cells: Array[Vector2i]):\n\tvar player_id: int = player.get_id()\n\n\tfor cell in buildable_cells:\n\t\t_buildable_cells[cell] = player_id\n\n\n# NOTE: must be called while tower is in scene tree\nfunc set_occupied_by_tower(tower: Tower, value: bool):\n\tvar occupied_list: Array[Vector2i] = _get_positions_occupied_by_tower(tower)\n\n\tfor pos in occupied_list:\n\t\t_occupied_map[pos] = value\n\n\n# Returns an array of 4 bools, one per quarter tile. True if\n# the quarter is buildable tile and is not occupied by a\n# tower. Order: [up, right, down, left]\nfunc get_build_info_for_pos(player: Player, pos_canvas: Vector2) -> Array:\n\tvar player_id: int = player.get_id()\n\tvar pos_map: Vector2i = _convert_pos_canvas_to_map(pos_canvas)\n\tvar quarter_list: Array[Vector2i] = []\n\n\tfor offset in QUARTER_OFFSET_LIST_NORMAL:\n\t\tvar quarter_pos: Vector2i = pos_map + offset\n\t\tquarter_list.append(quarter_pos)\n\n\tvar team: Team = player.get_team()\n\tvar allow_shared_build_space: bool = team.get_allow_shared_build_space()\n\n# \tNOTE: normally players can only build in their own areas\n# \tbut if this option is enabled, then players can build in\n# \tteammate areas as well\n\tvar matching_player_id_list: Array[int] = []\n\tif allow_shared_build_space:\n\t\tvar player_list: Array[Player] = team.get_players()\n\n\t\tfor team_player in player_list:\n\t\t\tvar team_player_id: int = team_player.get_id()\n\t\t\tmatching_player_id_list.append(team_player_id)\n\telse:\n\t\tmatching_player_id_list.append(player_id)\n\n\tvar build_info: Array = [false, false, false, false]\n\n\tfor i in range(0, 4):\n\t\tvar quarter_pos: Vector2i = quarter_list[i]\n\t\tvar quarter_pos_is_occupied: bool = _occupied_map.get(quarter_pos, false)\n\t\tvar player_id_at_quarter_pos: int = _buildable_cells.get(quarter_pos, -1)\n\t\tvar quarter_is_buildable: bool = matching_player_id_list.has(player_id_at_quarter_pos)\n\n\t\tbuild_info[i] = !quarter_pos_is_occupied && quarter_is_buildable\n\n\treturn build_info\n\n\nfunc can_build_at_pos(player: Player, global_pos: Vector2) -> bool:\n\tvar build_info: Array = get_build_info_for_pos(player, global_pos)\n\tvar can_build: bool = !build_info.has(false)\n\n\treturn can_build\n\n\nfunc can_transform_at_pos(pos_mouse: Vector2) -> bool:\n\tvar transform_is_allowed: bool = Globals.game_mode_allows_transform()\n\tvar tower_under_mouse: Tower = Utils.get_tower_at_canvas_pos(pos_mouse)\n\tvar belongs_to_local_player: bool = tower_under_mouse != null && tower_under_mouse.belongs_to_local_player()\n\tvar attempting_to_transform: bool = tower_under_mouse != null\n\tvar can_transform: bool = attempting_to_transform && transform_is_allowed && belongs_to_local_player\n\n\treturn can_transform\n\n\nfunc buildable_cell_exists_at_pos(player: Player, pos_map: Vector2i) -> bool:\n\tvar player_id: int = player.get_id()\n\tvar player_id_at_pos: int = _buildable_cells.get(pos_map, -1)\n\tvar result: bool = player_id_at_pos == player_id\n\n\treturn result\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _convert_pos_canvas_to_map(pos_canvas: Vector2) -> Vector2i:\n\tvar pos_top_down: Vector2 = VectorUtils.canvas_to_top_down(pos_canvas)\n\tvar pos_top_down_rotated: Vector2 = pos_top_down.rotated(deg_to_rad(-45))\n\tvar pos_top_down_rotated_snapped: Vector2 = pos_top_down_rotated.snapped(Vector2(Constants.TILE_SIZE_PIXELS_HALF, Constants.TILE_SIZE_PIXELS_HALF))\n\tvar pos_map_float: Vector2 = (pos_top_down_rotated_snapped / Constants.TILE_SIZE_PIXELS_HALF).round()\n\tvar pos_map: Vector2i = Vector2i(pos_map_float)\n\n\treturn pos_map\n\n\nfunc _get_positions_occupied_by_tower(tower: Tower) -> Array[Vector2i]:\n\tvar pos_canvas: Vector2 = tower.get_visual_position()\n\tvar player: Player = tower.get_player()\n\tvar builder: Builder = player.get_builder()\n\tvar pos_map: Vector2i = _convert_pos_canvas_to_map(pos_canvas)\n\t\n\tvar pos_list: Array[Vector2i] = []\n\tfor offset in _get_quarter_offset_list(builder):\n\t\tvar pos: Vector2i = pos_map + offset\n\t\tpos_list.append(pos)\n\t\n\treturn pos_list\n\n\nfunc _get_quarter_offset_list(builder: Builder) -> Array[Vector2i]:\n\tif builder.get_allow_adjacent_towers():\n\t\treturn QUARTER_OFFSET_LIST_NORMAL\n\telse:\n\t\treturn QUARTER_OFFSET_LIST_BIG\n"
  },
  {
    "path": "src/game_scene/build_tower.gd",
    "content": "class_name BuildTower extends Node\n\n# Contains functions which are called by GameScene to\n# implement the process of building towers.\n\n@export var _mouse_state: MouseState\n@export var _build_space: BuildSpace\n@export var _tower_preview: TowerPreview\n@export var _game_client: GameClient\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc start(tower_id: int, player: Player):\n#\tNOTE: check only gold and tomes before starting to build\n#\ttower. Ignore food, so that it's possible to transform a\n#\ttower in cases where player is already at food cap.\n#\tTransforming removes preceding tower so if final food\n#\tusage is under cap, it's acceptable.\n\tvar enough_resources: bool = BuildTower.enough_resources_for_tower_only_gold_and_tomes(tower_id, player)\n\n\tif !enough_resources:\n\t\tBuildTower.add_error_about_tower_only_gold_and_tomes(tower_id, player)\n\n\t\treturn\n\n\tvar can_start_building: bool = _mouse_state.get_state() != MouseState.enm.NONE && _mouse_state.get_state() != MouseState.enm.BUILD_TOWER\n\tif can_start_building:\n\t\treturn\n\n\t_mouse_state.set_state(MouseState.enm.BUILD_TOWER)\n\n\t_tower_preview.set_tower(tower_id)\n\t_tower_preview.show()\n\n\tEventBus.player_started_build_process.emit()\n\n\n# NOTE: it would've been better to use Action verify() f-ns\n# here but it doesn't work well. Need special checking\n# logic.\nfunc try_to_finish(player: Player):\n\tvar tower_id: int = _tower_preview.get_tower_id()\n\tvar mouse_pos: Vector2 = _tower_preview.get_global_mouse_position()\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar can_build: bool = _build_space.can_build_at_pos(local_player, mouse_pos)\n\tvar tower_under_mouse: Tower = Utils.get_tower_at_canvas_pos(mouse_pos)\n\tvar attempting_to_transform: bool = tower_under_mouse != null\n\tvar transform_is_allowed: bool = Globals.game_mode_allows_transform()\n\tvar can_transform: bool = attempting_to_transform && transform_is_allowed\n\tvar enough_resources_for_build: bool = BuildTower.enough_resources_for_tower(tower_id, player)\n\n\tvar preceding_tower_id: int\n\tif tower_under_mouse != null:\n\t\tpreceding_tower_id = tower_under_mouse.get_id()\n\telse:\n\t\tpreceding_tower_id = -1\n\tvar enough_resources_for_transform: bool = BuildTower.enough_resources_for_tower(tower_id, player, preceding_tower_id)\n\n\tif !can_build && !can_transform:\n\t\tvar error: String\n\t\tif attempting_to_transform && !transform_is_allowed:\n\t\t\terror = tr(\"MESSAGE_CANT_TRANSFORM_IN_BUILD_MODE\")\n\t\telse:\n\t\t\terror = tr(\"MESSAGE_CANT_BUILD_HERE\")\n\n\t\tUtils.add_ui_error(player, error)\n\telif can_transform:\n\t\tif enough_resources_for_transform:\n\t\t\t_transform_tower(tower_under_mouse, tower_id)\n\t\t\tcancel()\n\t\telse:\n\t\t\tBuildTower.add_error_about_building_tower(tower_id, player, preceding_tower_id)\n\telse:\n\t\tif enough_resources_for_build:\n\t\t\t_build_tower(tower_id)\n\t\t\tcancel()\n\t\telse:\n\t\t\tBuildTower.add_error_about_building_tower(tower_id, player)\n\n\nfunc cancel():\n\tif _mouse_state.get_state() != MouseState.enm.BUILD_TOWER:\n\t\treturn\n\n\t_mouse_state.set_state(MouseState.enm.NONE)\n\t_tower_preview.hide()\n\tEventBus.player_stopped_build_process.emit()\n\n\nstatic func enough_resources_for_tower_only_gold_and_tomes(tower_id: int, player: Player) -> bool:\n\tvar enough_gold: bool = player.enough_gold_for_tower(tower_id)\n\tvar enough_tomes: bool = player.enough_tomes_for_tower(tower_id)\n\tvar enough_resources: bool = enough_gold && enough_tomes\n\n\treturn enough_resources\n\n\n# NOTE: if preceding_tower_id is given, then this f-n will\n# consider the food cost of the preceding tower. For\n# example, if player is 1 away from food cap (54/55) and is\n# transforming tower which costs 4 food into another tower\n# which also costs 4 food, then food check will be okay\n# because end result will still be under food cap.\nstatic func enough_resources_for_tower(tower_id: int, player: Player, preceding_tower_id: int = -1) -> bool:\n\tvar enough_gold: bool = player.enough_gold_for_tower(tower_id)\n\tvar enough_tomes: bool = player.enough_tomes_for_tower(tower_id)\n\tvar enough_food: bool = player.enough_food_for_tower(tower_id, preceding_tower_id)\n\tvar enough_resources: bool = enough_gold && enough_tomes && enough_food\n\n\treturn enough_resources\n\n\nstatic func add_error_about_tower_only_gold_and_tomes(tower_id: int, player: Player):\n\tvar enough_gold: bool = player.enough_gold_for_tower(tower_id)\n\tvar enough_tomes: bool = player.enough_tomes_for_tower(tower_id)\n\n\tif !enough_gold:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_ENOUGH_GOLD\"))\n\telif !enough_tomes:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_ENOUGH_TOMES_FOR_BUILD\"))\n\n\nstatic func add_error_about_building_tower(tower_id: int, player: Player, preceding_tower_id: int = -1):\n\tvar enough_gold: bool = player.enough_gold_for_tower(tower_id)\n\tvar enough_tomes: bool = player.enough_tomes_for_tower(tower_id)\n\tvar enough_food: bool = player.enough_food_for_tower(tower_id, preceding_tower_id)\n\n\tif !enough_gold:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_ENOUGH_GOLD\"))\n\telif !enough_tomes:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_ENOUGH_TOMES_FOR_BUILD\"))\n\telif !enough_food:\n\t\tUtils.add_ui_error(player, Utils.tr(\"MESSAGE_NOT_ENOUGH_FOOD\"))\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _build_tower(tower_id: int):\n\tvar mouse_pos: Vector2 = _tower_preview.get_global_mouse_position()\n\t\n\tvar random_pitch: float = Globals.local_rng.randf_range(1.0, 1.1)\n\tSFX.sfx_at_pos(SfxPaths.BUILD_TOWER, mouse_pos, 0.0, random_pitch)\n\t\n\tvar action: Action = ActionBuildTower.make(tower_id, mouse_pos)\n\t_game_client.add_action(action)\n\n\nfunc _transform_tower(prev_tower: Tower, new_tower_id: int):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar verify_ok: bool = ActionTransformTower.verify(local_player, prev_tower, new_tower_id)\n\tif !verify_ok:\n\t\treturn\n\n\tvar global_pos: Vector2 = _tower_preview.get_global_mouse_position()\n\tvar random_pitch: float = Globals.local_rng.randf_range(1.0, 1.1)\n\tSFX.sfx_at_pos(SfxPaths.BUILD_TOWER, global_pos, 0.0, random_pitch)\n\t\n\tvar prev_tower_uid: int = prev_tower.get_uid()\n\tvar action: Action = ActionTransformTower.make(prev_tower_uid, new_tower_id)\n\t_game_client.add_action(action)\n"
  },
  {
    "path": "src/game_scene/camera_controller.gd",
    "content": "class_name CameraController extends Node\n\n\n# Controls camera movement and zoom level based on player input.\n\n\nsignal camera_moved(shift_vector)\nsignal camera_zoomed(zoom_value)\n\n\nconst MOVE_SPEED_BASE: float = 1500.0\nconst ZOOM_MIN: float = 0.5\nconst ZOOM_MAX: float = 1.1\nconst ZOOM_SPEED_FOR_TOUCHPAD_WINDOWS: float = 1.0\nconst ZOOM_SPEED_FOR_TOUCHPAD_MAC: float = 0.1\nconst ZOOM_SPEED_FOR_MOUSEWHEEL: float = 0.2\nconst SLOW_SCROLL_MARGIN: float = 0.010\nconst FAST_SCROLL_MARGIN: float = 0.002\nconst SLOW_SCROLL_MULTIPLIER: float = 0.5\n\n\nvar _current_zoom_value: float = 1.0\nvar _drag_origin: Vector2 = Vector2.INF\nvar _keyboard_enabled: bool = true\nvar _any_input_enabled: bool = true\nvar _zoom_speed_for_touchpad: float\n\n@export var _camera: Camera2D\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tif OS.get_name() == \"macOS\":\n\t\t_zoom_speed_for_touchpad = ZOOM_SPEED_FOR_TOUCHPAD_MAC\n\telse:\n\t\t_zoom_speed_for_touchpad = ZOOM_SPEED_FOR_TOUCHPAD_WINDOWS\n\n\nfunc _process(delta):\n\tif !_any_input_enabled:\n\t\treturn\n\t\n\tvar game_window: Window = get_window()\n\tvar game_has_focus: bool = game_window.has_focus()\n\tvar mouse_scroll_is_enabled: bool = Settings.get_bool_setting(Settings.ENABLE_MOUSE_SCROLL)\n\tvar should_do_mouse_scroll: bool = mouse_scroll_is_enabled && game_has_focus\n\n\tvar speed_from_mouse: float = _get_cam_speed_from_setting(Settings.MOUSE_SCROLL)\n\tvar speed_from_keyboard: float = _get_cam_speed_from_setting(Settings.KEYBOARD_SCROLL)\n\n\tvar mouse_pos: Vector2 = get_viewport().get_mouse_position()\n\tvar screen_size: Vector2 = _camera.get_viewport_rect().size\n\n\tvar mouse_ratio: Vector2 = mouse_pos / screen_size\n\n\tvar move_direction_from_mouse: Vector2 = Vector2.ZERO\n\tif mouse_ratio.x < SLOW_SCROLL_MARGIN:\n\t\tmove_direction_from_mouse += Vector2.LEFT\n\tif mouse_ratio.x > 1.0 - SLOW_SCROLL_MARGIN:\n\t\tmove_direction_from_mouse += Vector2.RIGHT\n\tif mouse_ratio.y < SLOW_SCROLL_MARGIN:\n\t\tmove_direction_from_mouse += Vector2.UP\n\tif mouse_ratio.y > 1.0 - SLOW_SCROLL_MARGIN:\n\t\tmove_direction_from_mouse += Vector2.DOWN\n\t\t\n\tvar mouse_scroll_at_fast_speed: bool = false\n\tif mouse_ratio.x < FAST_SCROLL_MARGIN:\n\t\tmouse_scroll_at_fast_speed = true\n\tif mouse_ratio.y < FAST_SCROLL_MARGIN:\n\t\tmouse_scroll_at_fast_speed = true\n\tif mouse_ratio.y > 1.0 - FAST_SCROLL_MARGIN:\n\t\tmouse_scroll_at_fast_speed = true\n\tif mouse_ratio.x > 1.0 - FAST_SCROLL_MARGIN:\n\t\tmouse_scroll_at_fast_speed = true\n\n\tvar move_direction_from_keyboard: Vector2 = Vector2.ZERO\n\tif Input.is_action_pressed(\"ui_left\"):\n\t\tmove_direction_from_keyboard += Vector2.LEFT\n\tif Input.is_action_pressed(\"ui_right\"):\n\t\tmove_direction_from_keyboard += Vector2.RIGHT\n\tif Input.is_action_pressed(\"ui_up\"):\n\t\tmove_direction_from_keyboard += Vector2.UP\n\tif Input.is_action_pressed(\"ui_down\"):\n\t\tmove_direction_from_keyboard += Vector2.DOWN\n\t\n\tif !_keyboard_enabled:\n\t\tmove_direction_from_keyboard = Vector2.ZERO\n\n#\tNOTE: keep different ways of moving the camera\n#\texclusive. Do not allow moving by keyboard and moving by\n#\tscroll at the same time.\n\tvar move_direction: Vector2 = Vector2.ZERO\n\tvar move_speed: float = 0.0\n\tif move_direction_from_keyboard != Vector2.ZERO:\n\t\tmove_direction = move_direction_from_keyboard\n\t\tmove_speed = speed_from_keyboard\n\telif move_direction_from_mouse != Vector2.ZERO && should_do_mouse_scroll:\n\t\tmove_direction = move_direction_from_mouse\n\t\tmove_speed = speed_from_mouse\n\n\t\tif !mouse_scroll_at_fast_speed:\n\t\t\tmove_speed *= SLOW_SCROLL_MULTIPLIER\n\n#\tNOTE: normalize direction vector so that camera moves at\n#\tthe same speed in all directions\n\tmove_direction = move_direction.normalized()\n\t\n\tvar current_mouse_pos: Vector2 = get_viewport().get_mouse_position()\n\tvar drag_started: bool = Input.is_action_just_pressed(\"middle_click\")\n\tvar drag_in_progress: bool = Input.is_action_pressed(\"middle_click\")\n\t\n#\tWhen drag starts, remember position which was clicked.\n\tif drag_started:\n\t\t_drag_origin = current_mouse_pos\n\t\n#\tWhile dragging, move the camera based on offset between\n#\tdrag origin and current mouse position. Constantly\n#\tupdate drag origin so that new offsets can be\n#\trecalculated.\n\tvar move_offset_from_drag: Vector2 = Vector2.ZERO\n\tif drag_in_progress && current_mouse_pos != _drag_origin:\n\t\tmove_offset_from_drag = _drag_origin - current_mouse_pos\n\t\t_drag_origin = current_mouse_pos\n\n#\tNOTE: keep different ways of moving the camera\n#\texclusive. Do not allow moving by keyboard/scroll during\n#\tdrag.\n\tif drag_in_progress:\n\t\t_camera.position = _camera.get_screen_center_position() + move_offset_from_drag\n\telif move_direction != Vector2.ZERO:\n\t\tvar zoom_ratio = sqrt(_camera.zoom.x)\n\t\tvar shift_vector: Vector2 = move_direction * delta * move_speed * zoom_ratio\n\t\t_camera.position = _camera.get_screen_center_position() + shift_vector\n\t\t\n\t\tcamera_moved.emit(shift_vector)\n\n\n# NOTE: player inputs modify zoom_multiplier variable\n# instead of directly modifying zoom because zoom needs to\n# also be divided by interface size. See update_zoom().\nfunc _unhandled_input(event: InputEvent):\n\tif !_any_input_enabled:\n\t\treturn\n\t\n\tvar new_zoom_value: float = _calculate_new_zoom_value(event)\n\tvar zoom_multiplier_changed: bool = new_zoom_value != _current_zoom_value\n\n\tif zoom_multiplier_changed:\n\t\t_current_zoom_value = new_zoom_value\n\t\tcamera_zoomed.emit(_current_zoom_value)\n\t\tupdate_zoom()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_camera_limits(camera_limits_polygon: Polygon2D):\n\tvar camera_limits_rect: Rect2 = Utils.get_polygon_bounding_box(camera_limits_polygon)\n\t_camera.limit_bottom = int(camera_limits_rect.end.y)\n\t_camera.limit_top = int(camera_limits_rect.position.y)\n\t_camera.limit_left = int(camera_limits_rect.position.x)\n\t_camera.limit_right = int(camera_limits_rect.end.x)\n\n\n# Enables/disables moving camera with keyboard\nfunc set_keyboard_enabled(value: bool):\n\t_keyboard_enabled = value\n\n\n# Enables/disables performing any input on camera\nfunc set_any_input_enabled(value: bool):\n\t_any_input_enabled = value\n\n\n# NOTE: need to divide zoom by interface size because\n# interface size is implemented by changing Window's\n# content_scale_factor, which also affects how camera\n# renders.\nfunc update_zoom():\n\tvar interface_size: float = Settings.get_interface_size()\n\t_camera.zoom = Vector2.ONE * _current_zoom_value / interface_size\n\n\n#########################\n###      Private      ###\n#########################\n\n# Gets modified zoom multiplier after applying player input\nfunc _calculate_new_zoom_value(event: InputEvent) -> float:\n\tvar zoom_change: float\n\n\tif event is InputEventMagnifyGesture && Config.enable_zoom_by_touchpad():\n\t\tzoom_change = -(event.factor - 1.0) * _zoom_speed_for_touchpad\n\telif event is InputEventMouseButton && Config.enable_zoom_by_mousewheel():\n#\t\tMake zoom change slower as the camera gets more zoomed in\n\t\tvar slow_down_multiplier: float = _current_zoom_value / ZOOM_MAX\n\t\tvar zoom_change_direction: int\n\t\tmatch event.get_button_index():\n\t\t\tMOUSE_BUTTON_WHEEL_DOWN:\n\t\t\t\tzoom_change_direction = -1\n\t\t\tMOUSE_BUTTON_WHEEL_UP:\n\t\t\t\tzoom_change_direction = 1\n\t\t\t_:\n\t\t\t\tzoom_change_direction = 0\n\n\t\tzoom_change = zoom_change_direction * ZOOM_SPEED_FOR_MOUSEWHEEL * slow_down_multiplier\n\telse:\n\t\tzoom_change = 0.0\n\n\tvar new_zoom: float = _current_zoom_value + zoom_change\n\tnew_zoom = clampf(new_zoom, ZOOM_MIN, ZOOM_MAX)\n\n\treturn new_zoom\n\n\n# NOTE: setting value is in range of [0.0, 1.0]\n# Convert to actual speed.\nfunc _get_cam_speed_from_setting(setting: String) -> float:\n\tvar setting_value: float = Settings.get_setting(setting) as float\n\tvar speed_ratio: float = 1.0 + 2.0 * setting_value\n\tvar speed: float = MOVE_SPEED_BASE * speed_ratio\n\n#\tNOTE: this is a hackfix to make moving camera at min\n#\tzoom (zoomed out fully) not that slow.\n\tif _current_zoom_value == ZOOM_MIN:\n\t\tspeed *= 3\n\n\treturn speed\n\n\nfunc _get_viewport_scale_factor() -> float: \n\tvar factor = min(\n\t\t(float(get_viewport().size.x) / get_viewport().get_visible_rect().size.x),\n\t\t(float(get_viewport().size.y) / get_viewport().get_visible_rect().size.y))\n\t\n\treturn factor\n"
  },
  {
    "path": "src/game_scene/chat_commands.gd",
    "content": "class_name ChatCommands extends Node\n\n# Processes chat commands. All chat messages which start\n# with \"/\" are treated as commands.\n\n\nconst GAMESPEED_MIN: int = 1\nconst GAMESPEED_MAX: int = 30\nconst DAMAGE_METERS_TOWER_COUNT: int = 5\n\n\nconst HELP: Array[String] = [\"/help\"]\nconst READY: Array[String] = [\"/ready\"]\nconst AUTOSPAWN: Array[String] = [\"/autospawn\", \"/as\"]\nconst AUTOOIL: Array[String] = [\"/autooil\", \"/ao\"]\nconst GAMESPEED: Array[String] = [\"/gamespeed\", \"/gs\"]\nconst DAMAGE_METERS: Array[String] = [\"/damage-meters\", \"/dm\"]\nconst DAMAGE_METERS_RECENT: Array[String] = [\"/damage-meters-recent\", \"/dmr\"]\nconst IGNORE: Array[String] = [\"/ignore\"]\nconst UNIGNORE: Array[String] = [\"/unignore\"]\nconst PING: Array[String] = [\"/ping\"]\nconst PAUSE: Array[String] = [\"/pause\"]\nconst UNPAUSE: Array[String] = [\"/unpause\"]\nconst CHECK_RANGE_FRIENDLY: Array[String] = [\"/check-range-friendly\", \"/crf\"]\nconst CHECK_RANGE_ATTACK: Array[String] = [\"/check-range-attack\", \"/cra\"]\nconst PRINT_RANGES_TO_TOWERS: Array[String] = [\"/print-ranges-to-towers\", \"/prtt\"]\nconst ALLOW_ALL: Array[String] = [\"/allow-all\"]\n\nconst CREATE_ITEM: Array[String] = [\"/createitem\", \"/ci\"]\nconst PAUSE_WAVES: Array[String] = [\"/pause-waves\", \"/pw\"]\nconst UNPAUSE_WAVES: Array[String] = [\"/unpause-waves\", \"/upw\"]\nconst ADD_EXP: Array[String] = [\"/add-exp\", \"/ae\"]\nconst ADD_TEST_OILS: Array[String] = [\"/add-test-oils\", \"/ato\"]\nconst SPAWN_CHALLENGE: Array[String] = [\"/spawn-challenge\", \"/sc\"]\nconst SETUP_TEST_TOWER: Array[String] = [\"/setup-test-tower\", \"/stt\"]\nconst FULL_MANA: Array[String] = [\"/full-mana\", \"/fm\"]\n\nconst HOST_COMMAND_LIST_OF_LISTS: Array = [\n\tPAUSE,\n\tUNPAUSE,\n\tGAMESPEED,\n]\n\nconst DEV_COMMAND_LIST_OF_LISTS: Array = [\n\tCREATE_ITEM,\n\tPAUSE_WAVES,\n\tUNPAUSE_WAVES,\n\tADD_EXP,\n\tADD_TEST_OILS,\n\tSPAWN_CHALLENGE,\n\tSETUP_TEST_TOWER,\n\tFULL_MANA,\n]\n\n# Comamnds in this list will be executed only for the player\n# which typed them.\n# NOTE: care must be taken to avoid desyncs for such commands\nconst LOCAL_ONLY_COMMANDS_LIST_OF_LISTS: Array = [\n\tHELP,\n\tDAMAGE_METERS,\n\tDAMAGE_METERS_RECENT,\n\tIGNORE,\n\tUNIGNORE,\n\tPING,\n\tCHECK_RANGE_FRIENDLY,\n\tCHECK_RANGE_ATTACK,\n\tPRINT_RANGES_TO_TOWERS,\n]\n\nvar not_allowed_in_multiplayer: Array = []\nvar dev_command_list: Array = []\nvar local_only_command_list: Array = []\nvar host_command_list: Array = []\n\n@export var _team_container: TeamContainer\n@export var _hud: HUD\n@export var _game_client: GameClient\n@export var _range_checker: TowerPreview\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# NOTE: need to convert list of lists into list of strings\n# for easy \"has()\" calls\nfunc _ready():\n\tfor list in HOST_COMMAND_LIST_OF_LISTS:\n\t\thost_command_list.append_array(list)\n\n\tfor list in DEV_COMMAND_LIST_OF_LISTS:\n\t\tdev_command_list.append_array(list)\n\n\tfor list in LOCAL_ONLY_COMMANDS_LIST_OF_LISTS:\n\t\tlocal_only_command_list.append_array(list)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc process_command(player: Player, command: String):\n\tvar command_split: Array = command.split(\" \")\n\tvar command_main: String = command_split[0]\n\tvar command_args: Array = command_split.slice(1)\n\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tvar is_multiplayer: bool = player_mode == PlayerMode.enm.MULTIPLAYER\n\tvar command_not_allowed_in_multiplayer: bool = not_allowed_in_multiplayer.has(command_main)\n\tif is_multiplayer && command_not_allowed_in_multiplayer:\n\t\t_add_error(player, tr(\"COMMAND_NOT_ALLOWED_IN_MULTIPLAYER\"))\n\n\t\treturn\n\n\tvar command_is_dev: bool = dev_command_list.has(command_main)\n\tvar enable_dev_commands: bool = Config.enable_dev_commands()\n\tif command_is_dev && !enable_dev_commands:\n\t\t_add_error(player, tr(\"COMMAND_ONLY_DEV_MODE\"))\n\t\t\n\t\treturn\n\n\tvar command_is_local_only: bool = local_only_command_list.has(command_main)\n\tvar player_is_local: bool = player == PlayerManager.get_local_player()\n\tif command_is_local_only && !player_is_local:\n\t\tprint_verbose(\"Skipping command %s because it's local only and was requested by another player.\" % command)\n\t\t\n\t\treturn\n\n\tvar command_is_host_only: bool = host_command_list.has(command_main)\n\tvar player_is_host: bool = player.get_peer_id() == 1\n\tif command_is_host_only && !player_is_host:\n\t\t_add_error(player, tr(\"COMMAND_ONLY_HOST\"))\n\t\t\n\t\treturn\n\n\tif HELP.has(command_main):\n\t\t_command_help(player)\n\telif READY.has(command_main):\n\t\t_command_ready(player)\n\telif AUTOSPAWN.has(command_main):\n\t\t_command_autospawn(player, command_args)\n\telif AUTOOIL.has(command_main):\n\t\t_command_autooil(player, command_args)\n\telif GAMESPEED.has(command_main):\n\t\t_command_gamespeed(player, command_args)\n\telif CREATE_ITEM.has(command_main):\n\t\t_command_create_item(player, command_args)\n\telif PAUSE_WAVES.has(command_main):\n\t\t_command_pause_waves(player)\n\telif UNPAUSE_WAVES.has(command_main):\n\t\t_command_unpause_waves(player)\n\telif ADD_EXP.has(command_main):\n\t\t_command_add_exp(player, command_args)\n\telif ADD_TEST_OILS.has(command_main):\n\t\t_command_add_test_oils(player, command_args)\n\telif SPAWN_CHALLENGE.has(command_main):\n\t\t_command_spawn_challenge(player, command_args)\n\telif SETUP_TEST_TOWER.has(command_main):\n\t\t_command_setup_test_tower(player, command_args)\n\telif FULL_MANA.has(command_main):\n\t\t_command_full_mana(player, command_args)\n\telif DAMAGE_METERS.has(command_main):\n\t\t_command_damage_meters(player, command_args)\n\telif DAMAGE_METERS_RECENT.has(command_main):\n\t\t_command_damage_meters_recent(player, command_args)\n\telif IGNORE.has(command_main):\n\t\t_command_ignore(player, command_args)\n\telif UNIGNORE.has(command_main):\n\t\t_command_unignore(player, command_args)\n\telif PING.has(command_main):\n\t\t_command_ping()\n\telif PAUSE.has(command_main):\n\t\t_command_pause()\n\telif UNPAUSE.has(command_main):\n\t\t_command_unpause()\n\telif CHECK_RANGE_FRIENDLY.has(command_main):\n\t\t_command_check_range_friendly(player, command_args)\n\telif CHECK_RANGE_ATTACK.has(command_main):\n\t\t_command_check_range_attack(player, command_args)\n\telif PRINT_RANGES_TO_TOWERS.has(command_main):\n\t\t_command_print_ranges_to_towers(player)\n\telif ALLOW_ALL.has(command_main):\n\t\t_command_allow_all(player)\n\telse:\n\t\t_add_error(player, tr(\"COMMAND_UNKNOWN\").format({COMMAND = command_main}))\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _command_help(_player: Player):\n\tEventBus.player_requested_help.emit()\n\n\nfunc _command_ready(player: Player):\n\tif !player.is_ready():\n\t\tplayer.vote_ready()\n\n\nfunc _command_gamespeed(player: Player, args: Array):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS\"))\n\n\t\treturn\n\n\tvar value: int = args[0].to_int()\n\n\tif GAMESPEED_MIN > value || value > GAMESPEED_MAX:\n\t\t_add_error(player, tr(\"COMMAND_GAMESPEED_OUT_OF_RANGE\").format({MIN = GAMESPEED_MIN, MAX = GAMESPEED_MAX}))\n\n\t\treturn\n\n\tGlobals.set_update_ticks_per_physics_tick(value)\n\n\t_add_status(player, tr(\"COMMAND_GAMESPEED_SUCCESS\").format({GAMESPEED = value}))\n\n\nfunc _command_pause_waves(_player: Player):\n\tvar team_list: Array[Team] = _team_container.get_team_list()\n\tfor team in team_list:\n\t\tteam.set_waves_paused(true)\n\n\t_add_status(null, tr(\"COMMAND_PAUSE_WAVES\"))\n\n\nfunc _command_unpause_waves(_player: Player):\n\tvar team_list: Array[Team] = _team_container.get_team_list()\n\tfor team in team_list:\n\t\tteam.set_waves_paused(false)\n\n\t_add_status(null, tr(\"COMMAND_UNPAUSE_WAVES\"))\n\n\nfunc _command_create_item(player: Player, args: Array):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS\"))\n\n\t\treturn\n\n\tvar item_id: int = args[0].to_int()\n\tvar item: Item = Item.create(player, item_id, Vector3(0, 0, 0))\n\titem.fly_to_stash(0.0)\n\n\t_add_status(player, tr(\"COMMAND_CREATED_ITEM\").format({ITEM_ID = item_id}))\n\n\nfunc _command_autospawn(player: Player, args: Array):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS\"))\n\n\t\treturn\n\n\tvar team: Team = player.get_team()\n\n\tvar option: String = args[0]\n\tvar disable_autospawn: bool = option == \"off\"\n\n\tif disable_autospawn:\n\t\tteam.set_autospawn_time(-1)\n\t\t_add_status_for_team(team, tr(\"COMMAND_AUTOSPAWN_DISABLE\"))\n\n\t\treturn\n\n\tvar autospawn_time: int = option.to_int()\n\n\tif 1.0 > autospawn_time || autospawn_time > 100:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS\"))\n\n\t\treturn\n\n\tteam.set_autospawn_time(autospawn_time)\n\n\t_add_status_for_team(team, tr(\"COMMAND_AUTOSPAWN_SET\").format({TIME = roundi(autospawn_time)}))\n\nfunc _is_tower(unit: Unit) -> bool:\n\t# return false if non-tower is selected or unit is null\n\treturn unit != null and unit is Tower\n\nfunc _require_tower(unit: Unit, player: Player) -> bool:\n\tif not unit is Tower:\n\t\t_add_error(player, tr(\"COMMAND_MUST_SELECT_TOWER\"))\n\t\treturn false\n\treturn true\n\nfunc _require_owner(tower: Tower, player: Player) -> bool:\n\t# other player case\n\tif tower.get_player() != player:\n\t\t_add_error(player, tr(\"MESSAGE_DONT_OWN_TOWER\"))\n\t\treturn false\n\treturn true\n\nfunc _resolve_autooil_arg(player: Player, option: String):\n\tvar unit: Unit = player.get_selected_unit()\n\t\n\tvar tower: Tower = null\n\tvar tower_name: String = \"\"\n\tvar is_tower: bool = _is_tower(unit)\n\tif is_tower:\n\t\ttower = unit as Tower\n\t\ttower_name = tower.get_display_name()\n\t\t\n\tvar matched: bool = true\n\t\n\tmatch option:\n\t\t\"list\":\n\t\t\tvar oil_type_list: Array = AutoOil.get_oil_type_list()\n\t\t\tvar text: String = \", \".join(oil_type_list)\n\t\t\t_add_status(player, tr(\"COMMAND_AVAILABLE_OILS\"))\n\t\t\t_add_status(player, text)\n\t\t\"show\":\n\t\t\tvar status_text: String = player.get_autooil_status()\n\t\t\t_add_status(player, tr(\"COMMAND_AUTOOIL_STATUS\"))\n\t\t\tMessages.add_normal(player, status_text)\n\t\t\"clear\":\n\t\t\tif not is_tower:\n\t\t\t\tplayer.clear_all_autooil()\n\t\t\t\t_add_status(player, tr(\"COMMAND_AUTOOIL_CLEAR_ALL\"))\n\t\t\telse:\n\t\t\t\tif _require_owner(tower, player):\n\t\t\t\t\tplayer.clear_autooil_for_tower(tower)\n\t\t\t\t\t_add_status(player, tr(\"COMMAND_AUTOOIL_CLEAR_FOR_TOWER\").format({TOWER = tower_name}))\n\t\t\t\telse:\n\t\t\t\t\treturn\n\t\t_:\n\t\t\tmatched = false\n\t\n\tif matched:\n\t\treturn\n\t\n\tif _require_tower(unit, player) and _require_owner(tower, player):\n\t\tvar oil_type: String = option\n\t\tvar oil_type_is_valid: bool = AutoOil.get_oil_type_is_valid(oil_type)\n\t\t\n\t\tif not oil_type_is_valid:\n\t\t\t_add_error(player, tr(\"COMMAND_INVALID_OIL_TYPE\").format({OIL = oil_type}))\n\t\t\treturn\n\t\t\n\t\tvar full_oil_type: String = AutoOil.convert_short_type_to_full(oil_type)\n\t\tplayer.set_autooil_for_tower(full_oil_type, tower)\n\t\t_add_status(player, tr(\"COMMAND_AUTOOIL_SET\").format({TOWER = tower_name, OIL_TYPE = full_oil_type}))\n\n\t\treturn\n\telse:\n\t\treturn\n\n\nfunc _command_autooil(player: Player, args: Array):\n\tfor option in args:\n\t\t_resolve_autooil_arg(player, option)\n\t\n\nfunc _command_add_exp(player: Player, args: Array):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS\"))\n\n\t\treturn\n\n\tvar selected_tower: Unit = player.get_selected_unit()\n\n\tif selected_tower == null:\n\t\t_add_error(player, tr(\"COMMAND_MUST_SELECT_TOWER\"))\n\n\t\treturn\n\n\tvar exp_amount: int = args[0].to_int()\n\tselected_tower.add_exp(exp_amount)\n\n\t_add_status(player, tr(\"COMMAND_ADD_EXP\").format({EXP_AMOUNT = exp_amount}))\n\n\nfunc _command_add_test_oils(player: Player, _args: Array):\n\tvar selected_tower: Unit = player.get_selected_unit()\n\n\tif selected_tower == null:\n\t\t_add_error(player, tr(\"COMMAND_MUST_SELECT_TOWER\"))\n\n\t\treturn\n\n\t_add_test_oils(player, selected_tower)\n\t_add_status(player, tr(\"COMMAND_ADD_TEST_OILS\"))\n\n\nfunc _command_spawn_challenge(player: Player, args: Array):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS\"))\n\n\t\treturn\n\n\tvar creep_level: int = args[0].to_int()\n\tvar armor_type: ArmorType.enm = ArmorType.enm.ZOD\n\tvar difficulty: Difficulty.enm = Globals.get_difficulty()\n\tvar creep_health: float = Wave._calculate_base_hp(creep_level, difficulty, armor_type)\n\tvar creep_armor: float = Wave._calculate_base_armor(creep_level, difficulty)\n\tvar creep_path: Path2D = Utils.find_creep_path(player, false)\n\n\tvar creep_scene: PackedScene = Preloads.creep_scenes[\"ChallengeBoss\"]\n\tvar creep: Creep = creep_scene.instantiate()\n\tcreep.set_properties(creep_path, player, CreepSize.enm.CHALLENGE_BOSS, armor_type, CreepCategory.enm.CHALLENGE, creep_health, creep_armor, creep_level)\n\n\tvar first_path_point: Vector2 = Utils.get_path_point_wc3(creep_path, 0)\n\tcreep.set_position_wc3_2d(first_path_point)\n\n\tUtils.add_object_to_world(creep)\n\n\t_add_status(player, tr(\"COMMAND_SPAWN_CHALLENGE\").format({LEVEL = creep_level}))\n\n\nfunc _command_setup_test_tower(player: Player, _args: Array):\n\tvar selected_tower: Unit = player.get_selected_unit()\n\n\tif selected_tower == null:\n\t\t_add_error(player, tr(\"COMMAND_MUST_SELECT_TOWER\"))\n\n\t\treturn\n\n\tselected_tower.add_exp(1000)\n\t_add_test_oils(player, selected_tower)\n\t_add_status(player, tr(\"COMMAND_SETUP_TEST_TOWER\"))\n\n\nfunc _command_full_mana(player: Player, _args: Array):\n\tvar selected_tower: Unit = player.get_selected_unit()\n\n\tif selected_tower == null:\n\t\t_add_error(player, tr(\"COMMAND_MUST_SELECT_TOWER\"))\n\n\t\treturn\n\n\tselected_tower.add_mana_perc(1.0)\n\n\nfunc _command_damage_meters(player: Player, _args: Array):\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\n\ttower_list.sort_custom(\n\t\tfunc(a: Tower, b: Tower) -> bool:\n\t\t\tvar damage_a: float = a.get_total_damage()\n\t\t\tvar damage_b: float = b.get_total_damage()\n\t\t\t\n\t\t\treturn damage_a > damage_b\n\t\t\t)\n\n\t_add_status(player, tr(\"COMMAND_TOP_TOWERS_BY_DAMAGE\"))\n\n\tvar count: int = 0\n\tfor tower in tower_list:\n\t\tif count > DAMAGE_METERS_TOWER_COUNT:\n\t\t\tbreak\n\n\t\tvar tower_name: String = tower.get_display_name()\n\t\tvar damage: float = tower.get_total_damage()\n\t\t# use roundi to display the same value as tower details\n\t\tvar damage_string: String = TowerDetails.int_format(roundi(damage))\n\t\t\n\t\tvar damage_attack: float = tower.get_total_damage_by_type(Tower.DamageSource.Attack)\n\t\tvar attack_percentage: float = Utils.divide_safe(damage_attack, damage) * 100\n\t\tvar attack_percentage_string: String = Utils.format_float(attack_percentage, 1)\n\t\t\n\t\tvar damage_spell: float = tower.get_total_damage_by_type(Tower.DamageSource.Spell)\n\t\tvar spell_percentage: float = Utils.divide_safe(damage_spell, damage) * 100\n\t\tvar spell_percentage_string: String = Utils.format_float(spell_percentage, 1)\n\t\t\n\t\tMessages.add_normal(player, \"%s: [color=GOLD]%s[/color], attack: [color=GOLD]%s%%[/color], spell: [color=GOLD]%s%%[/color]\" % [tower_name, damage_string, attack_percentage_string, spell_percentage_string])\n\n\t\tcount += 1\n\n\nfunc _command_damage_meters_recent(player: Player, _args: Array):\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\n\ttower_list.sort_custom(\n\t\tfunc(a: Tower, b: Tower) -> bool:\n\t\t\tvar damage_a: float = a.get_total_damage_recent()\n\t\t\tvar damage_b: float = b.get_total_damage_recent()\n\t\t\t\n\t\t\treturn damage_a > damage_b\n\t\t\t)\n\n\t_add_status(player, tr(\"COMMAND_TOP_TOWERS_BY_RECENT_DAMAGE\"))\n\n\tvar count: int = 0\n\tfor tower in tower_list:\n\t\tif count > DAMAGE_METERS_TOWER_COUNT:\n\t\t\tbreak\n\n\t\tvar tower_name: String = tower.get_display_name()\n\t\tvar damage: float = tower.get_total_damage_recent()\n\t\t# use roundi to display the same value as tower details\n\t\tvar damage_string: String = TowerDetails.int_format(roundi(damage))\n\t\t\n\t\tvar damage_attack: float = tower.get_total_damage_recent(true, Tower.DamageSource.Attack)\n\t\tvar attack_percentage: float = Utils.divide_safe(damage_attack, damage) * 100\n\t\tvar attack_percentage_string: String = Utils.format_float(attack_percentage, 1)\n\n\t\tvar damage_spell: float = tower.get_total_damage_recent(true, Tower.DamageSource.Spell)\n\t\tvar spell_percentage: float = Utils.divide_safe(damage_spell, damage) * 100\n\t\tvar spell_percentage_string: String = Utils.format_float(spell_percentage, 1)\n\t\t\n\t\tMessages.add_normal(player, \"%s: [color=GOLD]%s[/color], attack: [color=GOLD]%s%%[/color], spell: [color=GOLD]%s%%[/color]\" % [tower_name, damage_string, attack_percentage_string, spell_percentage_string])\n\n\t\tcount += 1\n\n\nfunc _command_ignore(player: Player, args: Array):\n\t_command_ignore_helper(player, args, true)\n\n\nfunc _command_unignore(player: Player, args: Array):\n\t_command_ignore_helper(player, args, false)\n\n\n# NOTE: ignore command has a flaw where it ingores all\n# players who have the target name.\nfunc _command_ignore_helper(player: Player, args: Array, ignored_value: bool):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS_FOR_IGNORE\"))\n\n\t\treturn\n\n\tvar target_name: String = args[0]\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor p in player_list:\n\t\tvar this_name: String = p.get_player_name()\n\t\tvar name_match: bool = this_name == target_name\n\n\t\tif name_match:\n\t\t\tp.set_chat_ignored(ignored_value)\n\n\t\t\tvar player_name_with_color: String = p.get_player_name_with_color()\n\t\t\tvar status_string: String\n\t\t\tif ignored_value == true:\n\t\t\t\tstatus_string = tr(\"COMMAND_IGNORE_START\").format({PLAYER = player_name_with_color})\n\t\t\telse:\n\t\t\t\tstatus_string = tr(\"COMMAND_IGNORE_STOP\").format({PLAYER = player_name_with_color})\n\n\t\t\t_add_status(player, status_string)\n\n\nfunc _command_ping():\n\t_hud.toggle_ping_indicator_visibility()\n\n\nfunc _command_pause():\n\t_command_pause_helper(true)\n\n\nfunc _command_unpause():\n\t_command_pause_helper(false)\n\nfunc _command_pause_helper(value: bool):\n\t_hud.set_multiplayer_pause_indicator_visible(value)\n\t_game_client.set_paused_by_host(value)\n\n\nfunc _command_check_range_friendly(player: Player, args: Array):\n\tvar friendly: bool = true\n\t_command_check_range_helper(player, args, friendly)\n\n\nfunc _command_check_range_attack(player: Player, args: Array):\n\tvar friendly: bool = false\n\t_command_check_range_helper(player, args, friendly)\n\n\nfunc _command_print_ranges_to_towers(player: Player):\n\tvar selected_unit: Unit = player.get_selected_unit()\n\t\n\tif selected_unit == null || !selected_unit is Tower:\n\t\t_add_error(player, tr(\"COMMAND_MUST_SELECT_TOWER\"))\n\n\t\treturn\n\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\n\tvar selected_tower_pos: Vector2 = selected_unit.get_position_wc3_2d()\n\n\tvar message_list: Array[String] = []\n\n\tfor other_tower in tower_list:\n\t\tvar other_tower_name: String = other_tower.get_display_name()\n\t\tvar other_tower_pos: Vector2 = other_tower.get_position_wc3_2d()\n\t\tvar range_to_tower: float = selected_tower_pos.distance_to(other_tower_pos)\n\t\trange_to_tower -= Constants.RANGE_CHECK_BONUS_FOR_TOWERS\n\t\trange_to_tower = round(range_to_tower)\n\t\tvar message: String = tr(\"COMMAND_RANGE_BETWEEN_TOWERS\").format({TOWER = other_tower_name, RANGE = range_to_tower})\n\t\tmessage_list.append(message)\n\n\tfor message in message_list:\n\t\tprint(message)\n\n#\tNOTE: display message on screen with a delay so that all\n#\tof the messages can be read, in case they don't fit on\n#\tscreen if shown at the same time.\n\tfor message in message_list:\n\t\t_add_status(player, message)\n\n#\t\tNOTE: need to use create_timer() instead of\n#\t\tcreate_manual_timer() here because this code is\n#\t\texecuted only for local player (command is local\n#\t\tonly)\n\t\tawait get_tree().create_timer(1.0).timeout\n\n\nfunc _command_allow_all(player: Player):\n\tvar team: Team = player.get_team()\n\n\tteam.enable_allow_shared_build_space()\n\n\t_add_status_for_team(team, tr(\"COMMAND_ALLOW_SHARED_BUILDING\"))\n\n\nfunc _command_check_range_helper(player: Player, args: Array, friendly: bool):\n\tif args.size() != 1:\n\t\t_add_error(player, tr(\"COMMAND_INVALID_ARGS_FOR_RANGE_CHECK\"))\n\n\t\treturn\n\t\n\tvar arg_string: String = args[0]\n\t\n\tif arg_string == \"off\":\n\t\t_range_checker.hide()\n\t\t_add_status(player, tr(\"COMMAND_RANGE_CHECK_DISABLE\"))\n\t\t\n\t\treturn\n\t\n\tvar radius: int = arg_string.to_int()\n\t_range_checker.set_range_manual(radius, friendly)\n\t_range_checker.show()\n\n\n# NOTE: oil counts are based on average oil counts obtained\n# by wave 200\nfunc _add_test_oils(player: Player, tower: Tower):\n\tconst test_oil_map: Dictionary = {\n\t\t1001: 20, # sharpness (attack damage)\n\t\t1002: 10, # arcane sharpness (attack damage)\n\t\t1003: 3,  # divine sharpness (attack damage)\n\n\t\t1004: 20, # magic (mana pool and regen)\n\t\t1005: 10, # magic (mana pool and regen)\n\t\t1006: 3, # magic (mana pool and regen)\n\n\t\t1007: 20, # accuracy (attack crit)\n\t\t1008: 10, # accuracy (attack crit)\n\t\t1009: 3, # accuracy (attack crit)\n\n\t\t1010: 20, # swiftness (attack speed)\n\t\t1011: 10, # swiftness (attack speed)\n\t\t1012: 3, # swiftness (attack speed)\n\n\t\t1013: 20, # sorcery (spell damage and spell crit)\n\t\t1014: 10, # sorcery (spell damage and spell crit)\n\t\t1015: 3, # sorcery (spell damage and spell crit)\n\t}\n\n\tfor oil_id in test_oil_map.keys():\n\t\tvar oil_count: int = test_oil_map[oil_id]\n\n\t\tfor i in range(0, oil_count):\n\t\t\tvar oil_item: Item = Item.create(player, oil_id, Vector3.ZERO)\n\t\t\toil_item.pickup(tower)\n\n\nfunc _add_status(player: Player, text: String):\n\tMessages.add_normal(player, \"[color=CYAN]%s[/color]\" % text)\n\n\nfunc _add_error(player: Player, text: String):\n\tMessages.add_normal(player, \"[color=RED]%s[/color]\" % text)\n\n\nfunc _add_status_for_team(team: Team, text: String):\n\tvar player_list: Array[Player] = team.get_players()\n\n\tfor player in player_list:\n\t\t_add_status(player, text)\n"
  },
  {
    "path": "src/game_scene/combat_log_storage.gd",
    "content": "class_name CombatLogStorage extends Node\n\n\n# Stores combat log entries. Use CombatLog autoload to access this globally.\n\n# NOTE: log entries cannot store references to game objects\n# because log entries need to be usable after game objects\n# are removed from the game. That's why log entries save\n# string names.\n\n\nenum Type {\n\tDAMAGE,\n\tBUFF_APPLY,\n\tKILL,\n\tEXP,\n\tABILITY,\n\tAUTOCAST,\n\tITEM_CHARGE,\n}\n\nclass Entry:\n\tvar _type: CombatLogStorage.Type\n\tvar _timestamp: float\n\tvar _string: String\n\n\tfunc _init(type: CombatLogStorage.Type):\n\t\t_type = type\n\t\t_timestamp = Utils.get_time()\n\t\t_string = \"default log entry string\"\n\n\n\tfunc get_string() -> String:\n\t\treturn _string\n\n\n\tfunc get_timestamp_string() -> String:\n\t\treturn \"[color=GOLD]%s[/color]\" % Utils.format_float(_timestamp, 2)\n\n\n\tfunc get_type_name() -> String:\n\t\tmatch _type:\n\t\t\tType.DAMAGE: return \"DAMAGE\"\n\t\t\tType.KILL: return \"KILL\"\n\t\t\tType.BUFF_APPLY: return \"BUFF_APPLY\"\n\t\t\tType.EXP: return \"EXP\"\n\t\t\tType.ABILITY: return \"ABILITY\"\n\t\t\tType.AUTOCAST: return \"AUTOCAST\"\n\t\t\tType.ITEM_CHARGE: return \"ITEM_CHARGE\"\n\n\t\treturn \"unknown event type\"\n\n\n\nclass DamageEntry extends Entry:\n\tvar _caster_name: String\n\tvar _target_name: String\n\tvar _damage_source: Unit.DamageSource\n\tvar _damage: float\n\tvar _crit_count: int\n\n\tfunc _init(caster: Unit, target: Unit, damage_source: Unit.DamageSource, damage: float, crit_count: int):\n\t\tsuper(CombatLogStorage.Type.DAMAGE)\n\n\t\t_caster_name = caster.get_log_name()\n\t\t_target_name = target.get_log_name()\n\t\t_damage_source = damage_source\n\t\t_damage = damage\n\t\t_crit_count = crit_count\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\t\tvar crit_string: String = \"\"\n\t\tif crit_count > 0:\n\t\t\tfor i in range(0, crit_count):\n\t\t\t\tcrit_string += \"!\"\n\t\telse:\n\t\t\tcrit_string = \"\"\n\t\tvar damage_color: Color\n\t\tmatch damage_source:\n\t\t\tUnit.DamageSource.Attack: damage_color = Color.RED\n\t\t\tUnit.DamageSource.Spell: damage_color = Color.LIGHT_BLUE\n\t\tvar damage_string: String = Utils.get_colored_string(Utils.format_float(_damage, 0), damage_color)\n\n\t\t_string = \"%s: %s %s->%s [color=RED]%s %s[/color]\" % [timestamp_string, type_name, _caster_name, _target_name, damage_string, crit_string]\n\n\nclass KillEntry extends Entry:\n\tvar _caster_name: String\n\tvar _target_name: String\n\n\tfunc _init(caster: Unit, target: Unit):\n\t\tsuper(CombatLogStorage.Type.KILL)\n\n\t\t_caster_name = caster.get_log_name()\n\t\t_target_name = target.get_log_name()\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\n\t\t_string = \"%s: %s %s->%s\" % [timestamp_string, type_name, _caster_name, _target_name]\n\n\nclass BuffApplyEntry extends Entry:\n\tvar _caster_name: String\n\tvar _target_name: String\n\tvar _buff_name: String\n\n\tfunc _init(caster: Unit, target: Unit, buff: Buff):\n\t\tsuper(CombatLogStorage.Type.BUFF_APPLY)\n\n\t\t_caster_name = caster.get_log_name()\n\t\t_target_name = target.get_log_name()\n\t\t_buff_name = buff.get_buff_type_name()\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\n\t\t_string = \"%s: %s %s->%s buff=\\\"%s\\\"\" % [timestamp_string, type_name, _caster_name, _target_name, _buff_name]\n\n\nclass ExpEntry extends Entry:\n\tvar _unit_name: String\n\tvar _experience: float\n\n\tfunc _init(unit: Unit, experience: float):\n\t\tsuper(CombatLogStorage.Type.EXP)\n\n\t\t_unit_name = unit.get_log_name()\n\t\t_experience = experience\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\n\t\tvar exp_color: Color\n\t\tif experience >= 0.0:\n\t\t\texp_color = Color.GREEN\n\t\telse:\n\t\t\texp_color = Color.RED\n\t\tvar exp_string: String = Utils.format_float(experience, 1)\n\t\tif experience >= 0.0:\n\t\t\texp_string = \"+\" + exp_string\n\t\texp_string = Utils.get_colored_string(exp_string, exp_color)\n\n\t\t_string = \"%s: %s %s %s\" % [timestamp_string, type_name, _unit_name, exp_string]\n\n\nclass AbilityEntry extends Entry:\n\tvar _caster_name: String\n\tvar _target_name: String\n\tvar _ability: String\n\n\tfunc _init(caster: Unit, target: Unit, ability: String):\n\t\tsuper(CombatLogStorage.Type.ABILITY)\n\n\t\t_caster_name = caster.get_log_name()\n\t\tif target != null:\n\t\t\t_target_name = target.get_log_name()\n\t\telse:\n\t\t\t_target_name = \"\"\n\t\t_ability = ability\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\t\tvar ability_string: String = \"[color=LIGHT_BLUE]\\\"%s\\\"[/color]\" % ability\n\n\t\tif target != null:\n\t\t\t_string = \"%s: %s %s->%s %s\" % [timestamp_string, type_name, _caster_name, _target_name, ability_string]\n\t\telse:\n\t\t\t_string = \"%s: %s %s %s\" % [timestamp_string, type_name, _caster_name, ability_string]\n\n\nclass ItemAbilityEntry extends Entry:\n\tvar _carrier_name: String\n\tvar _item_name: String\n\tvar _target_name: String\n\tvar _ability: String\n\n\tfunc _init(item: Item, target: Unit, ability: String):\n\t\tsuper(CombatLogStorage.Type.ABILITY)\n\n\t\tvar carrier: Unit = item.get_carrier()\n\t\t_carrier_name = carrier.get_log_name()\n\t\t_item_name = item.get_display_name()\n\t\tif target != null:\n\t\t\t_target_name = target.get_log_name()\n\t\telse:\n\t\t\t_target_name = \"\"\n\t\t_ability = ability\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\t\tvar carrier_string: String = \"[color=GREEN]\\\"%s\\\"[/color]\" % _carrier_name\n\t\tvar item_string: String = \"[color=ORANGE]\\\"%s\\\"[/color]\" % _item_name\n\t\tvar ability_string: String = \"[color=LIGHT_BLUE]\\\"%s\\\"[/color]\" % ability\n\n\t\tif target != null:\n\t\t\t_string = \"%s: %s %s %s->%s %s\" % [timestamp_string, type_name, carrier_string, item_string, _target_name, ability_string]\n\t\telse:\n\t\t\t_string = \"%s: %s %s %s %s\" % [timestamp_string, type_name, carrier_string, item_string, ability_string]\n\n\nclass AutocastEntry extends Entry:\n\tvar _caster_name: String\n\tvar _target_name: String\n\tvar _autocast_name: String\n\n\tfunc _init(caster: Unit, target: Unit, autocast: Autocast):\n\t\tsuper(CombatLogStorage.Type.AUTOCAST)\n\n\t\t_caster_name = caster.get_log_name()\n\t\tif target != null:\n\t\t\t_target_name = target.get_log_name()\n\t\telse:\n\t\t\t_target_name = \"\"\n\t\t_autocast_name = autocast.get_autocast_name()\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\t\tvar autocast_name_string: String = \"[color=LIGHT_BLUE]\\\"%s\\\"[/color]\" % _autocast_name\n\n\t\tif target != null:\n\t\t\t_string = \"%s: %s %s->%s %s\" % [timestamp_string, type_name, _caster_name, _target_name, autocast_name_string]\n\t\telse:\n\t\t\t_string = \"%s: %s %s %s\" % [timestamp_string, type_name, _caster_name, autocast_name_string]\n\n\nclass ItemChargeEntry extends Entry:\n\tvar _carrier_name: String\n\tvar _item_name: String\n\tvar _old_charge: int\n\tvar _new_charge: int\n\n\tfunc _init(item: Item, old_charge: int, new_charge: int):\n\t\tsuper(CombatLogStorage.Type.ITEM_CHARGE)\n\n\t\tvar carrier: Unit = item.get_carrier()\n\t\tif carrier != null:\n\t\t\t_carrier_name = carrier.get_log_name()\n\t\telse:\n\t\t\t_carrier_name = \"null\"\n\t\t_item_name = ItemProperties.get_display_name(item.get_id())\n\t\t_item_name = Utils.get_colored_string(_item_name, Color.LIGHT_BLUE)\n\t\t_old_charge = old_charge\n\t\t_new_charge = new_charge\n\n\t\tvar timestamp_string: String = get_timestamp_string()\n\t\tvar type_name: String = get_type_name()\n\n\t\tvar change_color: Color\n\t\tif new_charge > old_charge:\n\t\t\tchange_color = Color.GREEN\n\t\telse:\n\t\t\tchange_color = Color.RED\n\t\tvar change_string: String = \"%d->%d\" % [old_charge, new_charge]\n\t\tchange_string = Utils.get_colored_string(change_string, change_color)\n\n\t\t_string = \"%s: %s %s item=\\\"%s\\\" %s\" % [timestamp_string, type_name, _carrier_name, _item_name, change_string]\n\n\nconst LOG_SIZE_MAX: int = 1000\n\nvar _entry_map: Dictionary = {}\nvar _min_index: int = 0\nvar _max_index: int = 0\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tEventBus.player_requested_to_clear_combatlog.connect(_on_player_requested_to_clear_combatlog)\n\n#########################\n###       Public      ###\n#########################\n\nfunc add_entry(entry: Entry):\n\tvar new_index: int = _max_index\n\t_max_index += 1\n\n\t_entry_map[new_index] = entry\n\n#\tDelete old entries when list gets too big.\n#\tWe need to limit log length to prevent CombatLog\n#\tusing up too much memory.\n\tif _max_index > LOG_SIZE_MAX:\n\t\t_entry_map.erase(_min_index)\n\t\t_min_index += 1\n\n\nfunc get_min_index() -> int:\n\treturn _min_index\n\n\nfunc get_max_index() -> int:\n\treturn _max_index\n\n\nfunc get_entry_string(index: int) -> String:\n\tif _entry_map.is_empty() || _min_index > index || index >= _max_index:\n\t\treturn \"\"\n\n\tvar entry: CombatLogStorage.Entry = _entry_map[index]\n\tvar entry_string: String = entry.get_string()\n\n\treturn entry_string\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_player_requested_to_clear_combatlog():\n\t_min_index = _max_index\n\t_entry_map.clear()\n"
  },
  {
    "path": "src/game_scene/game_client.gd",
    "content": "class_name GameClient extends Node\n\n\n# GameClient for the game ticks, synchronized with the\n# server.\n# \n# GameClient ticks 30 times per second (based on\n# physics_ticks_per_second config value).\n# \n# Peers send actions requested by local player to host.\n# Host combines all actions into timeslots and sends\n# timeslots to all peers.\n# \n# Stops ticking if a timeslot is not ready for current tick.\n# \n# The end result is that clients are synchronized.\n\n\nsignal received_first_timeslot()\n\n\n# NOTE: this value determines how fast timeslot buffer\n# lowers when ping decreases. Higher value = faster\n# lowering.\nconst TIMESLOT_BUFFER_SIZE_LOWERING_FACTOR: float = 0.4\nconst PING_HISTORY_SIZE: int = 10\nconst TICKS_PER_SECOND: int = 30\nconst CHECKSUM_PERIOD_TICKS: int = TICKS_PER_SECOND * GameHost.MULTIPLAYER_TURN_LENGTH\n\n\nvar _tick_delta: float\nvar _current_tick: int = 0\nvar _turn_length: int\n# Timeslot buffer determines how many timeslots to keep in\n# buffer. Turns are buffered to avoid getting into\n# situations where client runs out of timeslots and has to\n# stall until next one arrives.\nvar _timeslot_buffer_size: float\n\n# A map of timeslots. Need to keep a map in case we receive\n# future timeslots before we processed current one.\n# {tick -> timeslot}\nvar _timeslot_map: Dictionary = {}\nvar _time_when_sent_ping: int = 0\nvar _ping_history: Array = [0]\nvar _received_any_timeslots: bool = false\nvar _paused_by_host: bool = false\nvar _last_received_timeslot_list: Array = []\n# Store checksum data for desync debugging: {tick -> checksum_data_dict}\nvar _checksum_data_map: Dictionary = {}\n\n\n@export var _game_host: GameHost\n@export var _game_time: GameTime\n@export var _hud: HUD\n@export var _build_space: BuildSpace\n@export var _chat_commands: ChatCommands\n@export var _select_unit: SelectUnit\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar tick_rate: int = ProjectSettings.get_setting(\"physics/common/physics_ticks_per_second\")\n\n\tif tick_rate != 30:\n\t\tpush_error(\"Physics tick rate got changed by accident. Must be 30 for multiplayer purposes.\")\n\n#\tNOTE: save this delta and use it instead of the one we\n#\tget in _physics_process because we need all clients to\n#\tuse the same delta value.\n\t_tick_delta = 1.0 / tick_rate\n\n\t_turn_length = Utils.get_turn_length()\n\t_timeslot_buffer_size = _turn_length\n\n\n# NOTE: using _physics_process() because it provides a\n# built-in way to do consistent tickrate, independent of\n# framerate.\nfunc _physics_process(_delta: float):\n#\tNOTE: depending on _should_tick() return value, client\n#\tmay tick 0, 1 or multiple times.\n\tvar ticks_during_this_process: int = 0\n\twhile _should_tick(ticks_during_this_process):\n\t\t_do_tick()\n\t\tticks_during_this_process += 1\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_paused_by_host(value: bool):\n\t_paused_by_host = value\n\n\n# Send action from client to host\nfunc add_action(action: Action):\n\tvar serialized_action: Dictionary = action.serialize()\n\t_game_host.receive_action.rpc_id(1, serialized_action)\n\n\n# Returns current tick number. Used for deterministic\n# calculations in multiplayer to avoid float precision issues.\nfunc get_current_tick() -> int:\n\treturn _current_tick\n\n\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc receive_alive_check():\n\t_game_host.receive_alive_check_response.rpc_id(1)\n\n\n# Receive timeslot sent by host to this client and receive\n# turn length\n# \n# NOTE: this f-n needs to handle cases where timeslots\n# are received out of order.\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc receive_timeslots(timeslot_list: Dictionary):\n\tif !_received_any_timeslots:\n\t\t_received_any_timeslots = true\n\t\treceived_first_timeslot.emit()\n\n#\tNOTE: it's important to skip old ticks, host can send\n#\told ticks if it hasn't received ack from client yet due\n#\tto network/logic delay. If we don't skip old ticks, then\n#\t_timeslot_map would grow forever.\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_timeslot_keys: Array = timeslot_list.keys()\n\tsorted_timeslot_keys.sort()\n\tfor tick in sorted_timeslot_keys:\n\t\tif tick < _current_tick:\n\t\t\tcontinue\n\n\t\t_timeslot_map[tick] = timeslot_list[tick]\n\n\t_last_received_timeslot_list = timeslot_list.keys()\n\n\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc receive_pong():\n\tvar time_when_received_pong: int = Time.get_ticks_msec()\n\tvar ping_time: int = time_when_received_pong - _time_when_sent_ping\n\n\t_ping_history.append(ping_time)\n\tif _ping_history.size() > PING_HISTORY_SIZE:\n\t\t_ping_history.pop_front()\n\n\tvar ping_average: float = _get_ping_average()\n\t_hud.set_ping_time(ping_average)\n\n\tvar ping_max: float = _get_ping_max()\n\t_update_timeslot_buffer_size(ping_max)\n\n\t_game_host.receive_ping_time_for_player.rpc_id(1, ping_time)\n\n\n# NOTE: arg must be Array instead of Array[String]. RPC\n# calls have typing issues\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc set_lagging_players(lagging_player_list: Array):\n\tvar players_are_lagging: bool = lagging_player_list.size() > 0\n\n\t_hud.set_waiting_for_lagging_players_indicator_player_list(lagging_player_list)\n\t_hud.set_waiting_for_lagging_players_indicator_visible(players_are_lagging)\n\n\n# Receive desync notification from server and send back stored checksum data\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc receive_desync_notification(tick: int):\n\tpush_error(\"!!! DESYNC NOTIFICATION received from server for tick %d !!!\" % tick)\n\n\tif _checksum_data_map.has(tick):\n\t\tvar checksum_data: Dictionary = _checksum_data_map[tick]\n\t\t_game_host.receive_checksum_data_from_client.rpc_id(1, tick, checksum_data)\n\telse:\n\t\tpush_error(\"  ERROR: No stored checksum data for tick %d\" % tick)\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: buffer value rises instantly but lowers gradually.\n# This is to prevent abrupt changes in input latency.\nfunc _update_timeslot_buffer_size(ping_time_ms: float):\n\tvar ping_time_sec: float = ping_time_ms / 1000.0\n\tvar new_size: float = ping_time_sec / _tick_delta\n\n\tif new_size < _timeslot_buffer_size:\n\t\t_timeslot_buffer_size = lerp(_timeslot_buffer_size, new_size, TIMESLOT_BUFFER_SIZE_LOWERING_FACTOR)\n\telse:\n\t\t_timeslot_buffer_size = new_size\n\n\tif _timeslot_buffer_size < _turn_length:\n\t\t_timeslot_buffer_size = _turn_length\n\n\nfunc _should_tick(ticks_during_this_process: int) -> bool:\n# \tNOTE: need to limit ticks per process to not disrupt\n# \ttiming of _physics_process() too much\n\tvar too_many_ticks: bool = ticks_during_this_process > Constants.MAX_UPDATE_TICKS_PER_PHYSICS_TICK\n\tif too_many_ticks:\n\t\treturn false\n\t\n#\tIf current tick needs a timeslot and client hasn't\n#\treceived timeslot from host yet, client has to wait\n\tvar need_timeslot: bool = _current_tick % _turn_length == 0\n\tvar have_timeslot: bool = _timeslot_map.has(_current_tick)\n\tif need_timeslot && !have_timeslot:\n\t\treturn false\n\n#\tNOTE: keep size of timeslot buffer within certain value.\n#\tIf too many timeslots are buffered, client fast forward\n#\tto catch up to host.\n\tif !_timeslot_map.is_empty():\n\t\tvar timeslot_ticks: Array = _timeslot_map.keys()\n\t\ttimeslot_ticks.sort()\n\t\tvar latest_timeslot_tick: int = timeslot_ticks.back()\n\t\tvar ticks_to_latest_timeslot: int = latest_timeslot_tick - _current_tick\n\t\tvar buffer_is_too_big: bool = ticks_to_latest_timeslot > _timeslot_buffer_size\n\t\t\n\t\tif buffer_is_too_big:\n\t\t\treturn true\n\n#\tIf don't need to fast forward, tick at regular pace (1\n#\ttick per process() call or more if custom game speed is\n#\tset)\n\tvar update_tick_count: int = min(Globals.get_update_ticks_per_physics_tick(), Constants.MAX_UPDATE_TICKS_PER_PHYSICS_TICK)\n\tvar should_tick: bool = ticks_during_this_process < update_tick_count\n\n\treturn should_tick\n\n\nfunc _do_tick():\n\tvar need_timeslot: bool = _current_tick % _turn_length == 0\n\tvar have_timeslot: bool = _timeslot_map.has(_current_tick)\n\t\n\tif need_timeslot && !have_timeslot:\n\t\treturn\n\n\tif need_timeslot:\n\t\tvar timeslot: Array = _timeslot_map[_current_tick]\n\t\t_timeslot_map.erase(_current_tick)\n\n\t\tfor action in timeslot:\n\t\t\t_execute_action(action)\n\n\t\tvar time_to_send_checksum: bool = _current_tick % CHECKSUM_PERIOD_TICKS == 0\n\t\tif time_to_send_checksum:\n\t\t\tvar checksum: PackedByteArray = _calculate_game_state_checksum()\n\t\t\t_game_host.receive_timeslot_checksum.rpc_id(1, _current_tick, checksum)\n\n\t_update_state()\n\t_current_tick += 1\n\n\nfunc _calculate_game_state_checksum():\n\tvar ctx: HashingContext = HashingContext.new()\n\tctx.start(HashingContext.HASH_MD5)\n\n\tvar game_state: PackedByteArray = PackedByteArray()\n\n\t# Store all values for desync debugging\n\tvar checksum_data: Dictionary = {\n\t\t\"players\": [],\n\t\t\"towers\": [],\n\t}\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor player in player_list:\n\t\tvar total_damage: int = floori(player.get_total_damage())\n\t\tvar gold_farmed: int = floori(player.get_gold_farmed())\n\t\tvar gold: int = floori(player.get_gold())\n\t\tvar tomes: int = player.get_tomes()\n\t\tvar lives: int = floori(player.get_team().get_lives_percent())\n\t\tvar level: int = player.get_team().get_level()\n\n\t\tgame_state.append(total_damage)\n\t\tgame_state.append(gold_farmed)\n\t\tgame_state.append(gold)\n\t\tgame_state.append(tomes)\n\t\tgame_state.append(lives)\n\t\tgame_state.append(level)\n\n\t\tchecksum_data[\"players\"].append({\n\t\t\t\"id\": player.get_id(),\n\t\t\t\"name\": player.get_player_name(),\n\t\t\t\"total_damage\": total_damage,\n\t\t\t\"gold_farmed\": gold_farmed,\n\t\t\t\"gold\": gold,\n\t\t\t\"tomes\": tomes,\n\t\t\t\"lives\": lives,\n\t\t\t\"level\": level,\n\t\t})\n\n\t# Include tower state to catch tower-related desyncs\n\t# NOTE: tower_list is already sorted by UID in Utils.get_tower_list()\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\tfor tower in tower_list:\n\t\tvar tower_uid: int = tower.get_uid()\n\t\tvar tower_id: int = tower.get_id()\n\t\tvar tower_level: int = tower.get_level()\n\t\tvar tower_exp: int = floori(tower.get_exp())\n\n\t\tgame_state.append(tower_uid)\n\t\tgame_state.append(tower_id)\n\t\tgame_state.append(tower_level)\n\t\tgame_state.append(tower_exp)\n\n\t\tvar tower_data: Dictionary = {\n\t\t\t\"uid\": tower_uid,\n\t\t\t\"id\": tower_id,\n\t\t\t\"level\": tower_level,\n\t\t\t\"exp\": tower_exp,\n\t\t\t\"owner_id\": tower.get_player().get_id(),\n\t\t\t\"items\": [],\n\t\t}\n\n\t\t# Include item state to catch item-related desyncs\n\t\tvar item_list: Array[Item] = tower.get_item_container().get_item_list()\n\t\tUtils.sort_objects_for_multiplayer(item_list)\n\n\t\tfor item in item_list:\n\t\t\tvar item_id: int = item.get_id()\n\t\t\tvar item_uid: int = item.get_uid()\n\t\t\tvar item_charges: int = item.get_charges()\n\t\t\tvar item_user_int: int = item.user_int\n\t\t\tvar item_user_int2: int = item.user_int2\n\t\t\tvar item_user_int3: int = item.user_int3\n\t\t\tvar item_user_real: int = floori(item.user_real)\n\t\t\tvar item_user_real2: int = floori(item.user_real2)\n\t\t\tvar item_user_real3: int = floori(item.user_real3)\n\n\t\t\tgame_state.append(item_id)\n\t\t\tgame_state.append(item_uid)\n\t\t\tgame_state.append(item_charges)\n\t\t\tgame_state.append(item_user_int)\n\t\t\tgame_state.append(item_user_int2)\n\t\t\tgame_state.append(item_user_int3)\n\t\t\tgame_state.append(item_user_real)\n\t\t\tgame_state.append(item_user_real2)\n\t\t\tgame_state.append(item_user_real3)\n\n\t\t\ttower_data[\"items\"].append({\n\t\t\t\t\"uid\": item_uid,\n\t\t\t\t\"id\": item_id,\n\t\t\t\t\"charges\": item_charges,\n\t\t\t\t\"user_int\": item_user_int,\n\t\t\t\t\"user_int2\": item_user_int2,\n\t\t\t\t\"user_int3\": item_user_int3,\n\t\t\t\t\"user_real\": item_user_real,\n\t\t\t\t\"user_real2\": item_user_real2,\n\t\t\t\t\"user_real3\": item_user_real3,\n\t\t\t})\n\n\t\tchecksum_data[\"towers\"].append(tower_data)\n\n\tctx.update(game_state)\n\n\tvar checksum: PackedByteArray = ctx.finish()\n\n\t# Store checksum data for this tick\n\t_checksum_data_map[_current_tick] = checksum_data\n\n\t# Clean up old checksum data (keep last 10 ticks)\n\t# NOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar ticks_to_remove: Array = []\n\tvar sorted_checksum_ticks: Array = _checksum_data_map.keys()\n\tsorted_checksum_ticks.sort()\n\tfor tick in sorted_checksum_ticks:\n\t\tif tick < _current_tick - CHECKSUM_PERIOD_TICKS * 10:\n\t\t\tticks_to_remove.append(tick)\n\tfor tick in ticks_to_remove:\n\t\t_checksum_data_map.erase(tick)\n\n\treturn checksum\n\n\n# NOTE: need to implement this with a match statement\n# because action is a plain Dictionary passed via RPC. Doing\n# this via dynamic dispatch is not possible because it's not\n# possible to pass custom classes through RPC. Also, some\n# execute()'s require extra args like \"map\" which is a\n# further obstruction.\nfunc _execute_action(action: Dictionary):\n\tvar player_id: int = action[Action.Field.PLAYER_ID] as int\n\tvar player: Player = PlayerManager.get_player(player_id)\n\n\tif player == null:\n\t\tpush_error(\"player is null\")\n\t\t\n\t\treturn\n\n\tvar action_type: Action.Type = action[Action.Field.TYPE]\n\n\tmatch action_type:\n\t\tAction.Type.IDLE: return\n\t\tAction.Type.CHAT: ActionChat.execute(action, player, _hud, _chat_commands)\n\t\tAction.Type.BUILD_TOWER: ActionBuildTower.execute(action, player, _build_space)\n\t\tAction.Type.UPGRADE_TOWER: ActionUpgradeTower.execute(action, player, _select_unit)\n\t\tAction.Type.TRANSFORM_TOWER: ActionTransformTower.execute(action, player)\n\t\tAction.Type.SELL_TOWER: ActionSellTower.execute(action, player, _build_space)\n\t\tAction.Type.SELECT_BUILDER: ActionSelectBuilder.execute(action, player)\n\t\tAction.Type.TOGGLE_AUTOCAST: ActionToggleAutocast.execute(action, player)\n\t\tAction.Type.CONSUME_ITEM: ActionConsumeItem.execute(action, player)\n\t\tAction.Type.DROP_ITEM: ActionDropItem.execute(action, player)\n\t\tAction.Type.MOVE_ITEM: ActionMoveItem.execute(action, player)\n\t\tAction.Type.SWAP_ITEMS: ActionSwapItems.execute(action, player)\n\t\tAction.Type.AUTOFILL: ActionAutofill.execute(action, player)\n\t\tAction.Type.TRANSMUTE: ActionTransmute.execute(action, player)\n\t\tAction.Type.RESEARCH_ELEMENT: ActionResearchElement.execute(action, player)\n\t\tAction.Type.ROLL_TOWERS: ActionRollTowers.execute(action, player)\n\t\tAction.Type.START_NEXT_WAVE: ActionStartNextWave.execute(action, player)\n\t\tAction.Type.AUTOCAST: ActionAutocast.execute(action, player)\n\t\tAction.Type.FOCUS_TARGET: ActionFocusTarget.execute(action, player)\n\t\tAction.Type.CHANGE_BUFFGROUP: ActionChangeBuffgroup.execute(action, player)\n\t\tAction.Type.SELECT_WISDOM_UPGRADES: ActionSelectWisdomUpgrades.execute(action, player)\n\t\tAction.Type.SELECT_UNIT: ActionSelectUnit.execute(action, player)\n\t\tAction.Type.SORT_ITEM_STASH: ActionSortItemStash.execute(action, player)\n\n\nfunc _update_state():\n#\tNOTE: the pause is implemented this way so that all game\n#\tobjects/timers are paused but chat commands are still\n#\tprocessed so that /unpause command can go through. Note\n#\tthat game host still continues to tick and send\n#\ttimeslots.\n\tif _paused_by_host:\n\t\treturn\n\n\t_game_time.update(_tick_delta)\n\n#\tNOTE: use separate groups so that update() calls are\n#\tordered by type. This makes gameplay logic more\n#\tconsistent.\n\tvar timer_list: Array = get_tree().get_nodes_in_group(\"manual_timers\")\n\tUtils.sort_objects_for_multiplayer(timer_list)\n\n\tvar creep_list: Array[Creep] = Utils.get_creep_list()\n\n\tvar projectile_list: Array = get_tree().get_nodes_in_group(\"projectiles\")\n\tUtils.sort_objects_for_multiplayer(projectile_list)\n\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\tvar node_list: Array = []\n\tnode_list.append_array(timer_list)\n\tnode_list.append_array(creep_list)\n\tnode_list.append_array(projectile_list)\n\tnode_list.append_array(tower_list)\n\n# \tNOTE: need to check is_inside_tree() because nodes may\n# \tget removed during iteration. For example, timer_list is\n# \tobtained once before iteration starts. Then timer A\n# \ttriggers an explosion which kills a creep which carries\n# \ttimer B. Timer B is now outside tree but still inside\n# \ttimer_list!\n\tfor node in node_list:\n\t\tvar should_update: bool = node.is_inside_tree() && !node.is_queued_for_deletion()\n\t\tif !should_update:\n\t\t\tcontinue\n\n\t\tnode.update(_tick_delta)\n\n\nfunc _get_ping_average() -> float:\n\tvar sum: float = 0\n\n\tfor ping in _ping_history:\n\t\tsum += ping\n\n\tvar ping_average: float = sum / _ping_history.size()\n\n\treturn ping_average\n\n\nfunc _get_ping_max() -> float:\n\tvar ping_max: float = 0\n\n\tfor ping in _ping_history:\n\t\tping_max = max(ping_max, ping)\n\n\treturn ping_max\n\n\n#########################\n###     Callbacks     ###\n#########################\n\n# Periodically send a ping from client to host. This ping is\n# used to calculate ping time. It also includes a list of\n# last received timeslots to ack receival of those timeslots\n# and let the host know which timeslots it can stop sending.\nfunc _on_ping_timer_timeout():\n\t_time_when_sent_ping = Time.get_ticks_msec()\n\t_game_host.receive_ping.rpc_id(1, _last_received_timeslot_list)\n"
  },
  {
    "path": "src/game_scene/game_client.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://dp2tmdi8ms5qo\"]\n\n[ext_resource type=\"Script\" path=\"res://src/game_scene/game_client.gd\" id=\"1_5ijxp\"]\n\n[node name=\"GameClient\" type=\"Node\"]\nscript = ExtResource(\"1_5ijxp\")\n\n[node name=\"PingTimer\" type=\"Timer\" parent=\".\"]\nautostart = true\n\n[connection signal=\"timeout\" from=\"PingTimer\" to=\".\" method=\"_on_ping_timer_timeout\"]\n"
  },
  {
    "path": "src/game_scene/game_host.gd",
    "content": "class_name GameHost extends Node\n\n\n# Host receives actions from peers, combines them into\n# \"timeslots\" and sends timeslots back to the peers. A\n# \"timeslot\" is a group of actions for a given tick. A host\n# has it's own tick, independent of the GameClient on the\n# host's client. Host sends timeslots periodically with an\n# interval equal to current \"turn length\" value.\n# \n# Note that server peer acts as a host and a peer at the\n# same time.\n# \n# There's an ACK system for timeslots. Host keeps track of\n# which timeslots have been ack'ed by clients. Each message\n# sent from host to a client contains all timeslots which\n# haven't been ack'ed by that client yet. This ensures that\n# if some client temporarily disconnects, they will not miss\n# any timeslots and will be able to continue the game.\n\n# NOTE: GameHost node needs to be positioned before\n# GameClient node in the tree, so that it is processed\n# first.\n\n\nenum HostState {\n\tRUNNING,\n\tWAITING_FOR_LAGGING_PLAYERS,\n}\n\n# NOTE: 3 ticks at 30ticks/second = 100ms\n# 100ms was chosen so that turn length is short enough to\n# minimize input lag but not too often keep bandwidth usage\n# reasonable.\n# \n# Turn length affects input lag because when a player sends\n# an action to host, the action will be stored for a random\n# amount of time from 0ms to _turn_length before turn ends\n# and action is sent inside timeslot. Therefore, 100ms adds\n# on average 50ms of input lag, in addition to transmission\n# time and timeslot buffering on client.\nconst MULTIPLAYER_TURN_LENGTH: int = 3\nconst SINGLEPLAYER_TURN_LENGTH: int = 1\nconst TICK_DELTA: float = 1000 / 30.0\n# LAG_TIME_MSEC is the max time since last contact from\n# player. If host hasn't received any responses from player\n# for this long, host will start considering that player to\n# be lagging and will pause game turns.\nconst LAG_TIME_MSEC: float = 3000.0\n\n@export var _game_client: GameClient\n@export var _hud: HUD\n\n\nvar _current_tick: int = 0\nvar _turn_length: int\nvar _in_progress_timeslot: Array = []\nvar _player_ping_time_map: Dictionary = {}\nvar _player_last_contact_time: Dictionary = {}\n# {tick -> {player_id -> checksum}}\nvar _checksum_map: Dictionary = {}\n# {tick -> {player_id -> checksum_data_dict}}\nvar _checksum_data_map: Dictionary = {}\nvar _showed_desync_indicator: bool = false\n# Stores timeslots which should be sent to players and\n# haven't been ack'ed yet.\n# {player_id -> {tick -> timeslot}}\nvar _player_timeslot_send_queue: Dictionary = {}\n# NOTE: initial state is WAITING_FOR_LAGGING_PLAYERS until\n# host confirms that all players have connected successfully\n# and finished loading game scene.\nvar _state: HostState = HostState.WAITING_FOR_LAGGING_PLAYERS\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tif !multiplayer.is_server():\n\t\treturn\n\n\tPlayerManager.players_created.connect(_on_players_created)\n\t\n\t_turn_length = Utils.get_turn_length()\n\n\nfunc _physics_process(_delta: float):\n\tif !multiplayer.is_server():\n\t\treturn\n\n\tmatch _state:\n\t\tHostState.RUNNING: _update_state_running()\n\t\tHostState.WAITING_FOR_LAGGING_PLAYERS: pass\n\n\n#########################\n###       Public      ###\n#########################\n\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc receive_alive_check_response():\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\tvar player: Player = PlayerManager.get_player_by_peer_id(peer_id)\n\tvar player_id: int = player.get_id()\n\n\t_update_last_contact_time_for_player(player_id)\n\n\n# Receive action sent from client to host. Actions are\n# compiled into timeslots - a group of actions from all\n# clients.\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc receive_action(action: Dictionary):\n\tif _state != HostState.RUNNING:\n\t\treturn\n\n#\tNOTE: need to attach player id to action in this host\n#\tfunction to ensure safety. If we were to let clients\n#\tattach player_id to actions, then clients could attach\n#\tany value.\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\tvar player: Player = PlayerManager.get_player_by_peer_id(peer_id)\n\tvar player_id: int = player.get_id()\n\taction[Action.Field.PLAYER_ID] = player_id\n\n\t_in_progress_timeslot.append(action)\n\n\n# TODO: handle disconnections here. If player is\n# disconnected, then need to not count him when determining\n# whether host has collected checksums from all players.\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc receive_timeslot_checksum(tick: int, checksum: PackedByteArray):\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\tvar player: Player = PlayerManager.get_player_by_peer_id(peer_id)\n\tvar player_id: int = player.get_id()\n\n\tif !_checksum_map.has(tick):\n\t\t_checksum_map[tick] = {}\n\n\t_checksum_map[tick][player_id] = checksum\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\tvar player_count: int = player_list.size()\n\tvar collected_all_checksums_for_tick: bool = _checksum_map[tick].size() == player_count\n\n\tif collected_all_checksums_for_tick:\n\t\t_verify_checksums(tick)\n\t\t_checksum_map.erase(tick)\n\n\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc receive_ping(last_received_timeslot_list: Array):\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\tvar player: Player = PlayerManager.get_player_by_peer_id(peer_id)\n\tvar player_id: int = player.get_id()\n\n\t_update_last_contact_time_for_player(player_id)\n\n#\tWhen player ack's timeslots, host erases ack'd timeslots\n#\tfrom queue and stops sending them.\n\tvar timeslots_to_send: Dictionary = _player_timeslot_send_queue[player_id]\n\tfor tick in last_received_timeslot_list:\n\t\ttimeslots_to_send.erase(tick)\n\n\t_game_client.receive_pong.rpc_id(peer_id)\n\n\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc receive_ping_time_for_player(ping_time: int):\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\tvar player: Player = PlayerManager.get_player_by_peer_id(peer_id)\n\tvar player_id: int = player.get_id()\n\n\t_player_ping_time_map[player_id] = ping_time\n\n\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc receive_checksum_data_from_client(tick: int, checksum_data: Dictionary):\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\tvar player: Player = PlayerManager.get_player_by_peer_id(peer_id)\n\tvar player_id: int = player.get_id()\n\n\tif !_checksum_data_map.has(tick):\n\t\t_checksum_data_map[tick] = {}\n\n\t_checksum_data_map[tick][player_id] = checksum_data\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\tvar player_count: int = player_list.size()\n\tvar collected_all_data: bool = _checksum_data_map[tick].size() == player_count\n\n\tif collected_all_data:\n\t\t_log_detailed_desync_data(tick)\n\t\t_checksum_data_map.erase(tick)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_last_contact_time_for_player(player_id: int):\n\tvar ticks_msec: int = Time.get_ticks_msec()\n\t_player_last_contact_time[player_id] = ticks_msec\n\n\nfunc _update_state_running():\n\tvar lagging_player_list: Array[Player] = _get_lagging_players()\n\tvar players_are_lagging: bool = lagging_player_list.size() > 0\n\n\tif players_are_lagging:\n\t\t_state = HostState.WAITING_FOR_LAGGING_PLAYERS\n\n\t\tvar lagging_player_name_list: Array = _get_player_name_list(lagging_player_list)\n\n\t\t_game_client.set_lagging_players.rpc(lagging_player_name_list)\n\n\t\treturn\n\n#\tAdvance ticks on host and save completed timeslots\n\tvar update_tick_count: int = min(Globals.get_update_ticks_per_physics_tick(), Constants.MAX_UPDATE_TICKS_PER_PHYSICS_TICK)\n\n\tfor i in range(0, update_tick_count):\n\t\tvar turn_ended: int = _current_tick % _turn_length == 0\n\n\t\tif turn_ended:\n\t\t\t_save_timeslot()\n\t\t\n\t\t_current_tick += 1\n\n#\tSend timeslots\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\t\tvar peer_id: int = player.get_peer_id()\n\t\tvar timeslots_to_send: Dictionary = _player_timeslot_send_queue[player_id]\n\n\t\tif timeslots_to_send.is_empty():\n\t\t\tcontinue\n\n\t\t_game_client.receive_timeslots.rpc_id(peer_id, timeslots_to_send)\n\n\nfunc _save_timeslot():\n\tvar timeslot: Array = _in_progress_timeslot.duplicate()\n\t_in_progress_timeslot.clear()\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\t\tvar timeslots_to_send: Dictionary = _player_timeslot_send_queue[player_id]\n\n\t\ttimeslots_to_send[_current_tick] = timeslot\n\n\n# Returns highest ping of all players, in msec. Ping is\n# determined from the most recent ACK exchange.\nfunc _get_highest_ping() -> int:\n\tvar highest_ping: int = 0\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\t\tvar this_ping_time: int = _player_ping_time_map[player_id]\n\n\t\tif this_ping_time > highest_ping:\n\t\t\thighest_ping = this_ping_time\n\n\treturn highest_ping\n\n\n# NOTE: player is considered to be lagging if the last\n# timeslot ACK is too old.\nfunc _get_lagging_players() -> Array[Player]:\n\tvar lagging_player_list: Array[Player] = []\n\t\n#\tNOTE: skip lag check in singleplayer, to avoid the popup\n#\tshowing at the start of the game.\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tif player_mode == PlayerMode.enm.SINGLEPLAYER:\n\t\treturn lagging_player_list\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tvar ticks_msec: int = Time.get_ticks_msec()\n\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\t\tvar last_contact_time: float = _player_last_contact_time[player_id]\n\t\tvar time_since_last_contact: float = ticks_msec - last_contact_time\n\t\tvar player_is_lagging: bool = time_since_last_contact > LAG_TIME_MSEC\n\n\t\tif player_is_lagging:\n\t\t\tlagging_player_list.append(player)\n\n\treturn lagging_player_list\n\n\n# TODO: kick desynced players from the game\nfunc _verify_checksums(tick: int):\n\tvar desync_detected: bool = false\n\n\tvar player_to_checksum: Dictionary = _checksum_map[tick]\n\n\tvar authority_player: Player = PlayerManager.get_player_by_peer_id(1)\n\tvar authority_player_id: int = authority_player.get_id()\n\n\tvar authority_checksum: PackedByteArray = player_to_checksum[authority_player_id]\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tvar desynced_players: Array[String] = []\n\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\t\tvar checksum: PackedByteArray = player_to_checksum[player_id]\n\t\tvar checksum_match: bool = checksum == authority_checksum\n\n\t\tif !checksum_match:\n\t\t\tdesync_detected = true\n\t\t\tvar player_name: String = player.get_player_name()\n\t\t\tvar peer_id: int = player.get_peer_id()\n\t\t\tdesynced_players.append(\"%s (peer %d)\" % [player_name, peer_id])\n\n\tif desync_detected && !_showed_desync_indicator:\n\t\t_log_desync_detected(tick, authority_player, desynced_players, player_to_checksum)\n\t\t_hud.show_desync_indicator()\n\t\t_showed_desync_indicator = true\n\n\t\t# Notify all clients to send their detailed checksum data\n\t\tfor player in player_list:\n\t\t\tvar peer_id: int = player.get_peer_id()\n\t\t\t_game_client.receive_desync_notification.rpc_id(peer_id, tick)\n\n\nfunc _log_desync_detected(tick: int, authority_player: Player, desynced_players: Array[String], player_to_checksum: Dictionary):\n\tpush_error(\"========================================\")\n\tpush_error(\"DESYNC DETECTED at tick %d\" % tick)\n\tpush_error(\"========================================\")\n\tpush_error(\"Authority player: %s (peer %d)\" % [authority_player.get_player_name(), authority_player.get_peer_id()])\n\tpush_error(\"Desynced players: %s\" % \", \".join(desynced_players))\n\tpush_error(\"\")\n\tpush_error(\"Checksum details:\")\n\n\tvar authority_player_id: int = authority_player.get_id()\n\tvar authority_checksum: PackedByteArray = player_to_checksum[authority_player_id]\n\tvar authority_checksum_hex: String = authority_checksum.hex_encode()\n\tpush_error(\"  Authority checksum: %s\" % authority_checksum_hex)\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\t\tif player_id == authority_player_id:\n\t\t\tcontinue\n\n\t\tvar checksum: PackedByteArray = player_to_checksum[player_id]\n\t\tvar checksum_hex: String = checksum.hex_encode()\n\t\tvar player_name: String = player.get_player_name()\n\t\tvar peer_id: int = player.get_peer_id()\n\t\tvar match_status: String = \"MATCH\" if checksum == authority_checksum else \"DESYNC\"\n\n\t\tpush_error(\"  %s (peer %d): %s [%s]\" % [player_name, peer_id, checksum_hex, match_status])\n\n\tpush_error(\"\")\n\tpush_error(\"Game state summary:\")\n\n\t# Log current game state for debugging\n\tvar tower_count: int = Utils.get_tower_list().size()\n\tvar creep_count: int = Utils.get_creep_list().size()\n\n\tpush_error(\"  Total towers: %d\" % tower_count)\n\tpush_error(\"  Total creeps: %d\" % creep_count)\n\n\tfor player in player_list:\n\t\tvar player_name: String = player.get_player_name()\n\t\tvar gold: int = floori(player.get_gold())\n\t\tvar damage: int = floori(player.get_total_damage())\n\t\tvar lives: int = floori(player.get_team().get_lives_percent())\n\t\tpush_error(\"  %s: gold=%d, damage=%d, lives=%d%%\" % [player_name, gold, damage, lives])\n\n\tpush_error(\"========================================\")\n\n\nfunc _log_detailed_desync_data(tick: int):\n\tvar log_lines: Array[String] = []\n\n\tlog_lines.append(\"\")\n\tlog_lines.append(\"========================================\")\n\tlog_lines.append(\"DETAILED DESYNC DATA COMPARISON - tick %d\" % tick)\n\tlog_lines.append(\"========================================\")\n\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\tvar authority_player: Player = PlayerManager.get_player_by_peer_id(1)\n\tvar authority_player_id: int = authority_player.get_id()\n\n\tif !_checksum_data_map.has(tick):\n\t\tlog_lines.append(\"ERROR: No checksum data collected for tick %d\" % tick)\n\t\tpush_error(\"\\n\".join(log_lines))\n\t\treturn\n\n\tvar player_to_data: Dictionary = _checksum_data_map[tick]\n\tvar authority_data: Dictionary = player_to_data[authority_player_id]\n\n\t# Compare player data\n\tlog_lines.append(\"\")\n\tlog_lines.append(\"=== PLAYER DATA COMPARISON ===\")\n\tfor player_data in authority_data[\"players\"]:\n\t\tvar game_player_id: int = player_data[\"id\"]\n\t\tvar player_name: String = player_data[\"name\"]\n\n\t\tlog_lines.append(\"\")\n\t\tlog_lines.append(\"  Player[%d] %s:\" % [game_player_id, player_name])\n\n\t\t# Compare this player's data across all clients\n\t\tfor player in player_list:\n\t\t\tvar peer_player_id: int = player.get_id()\n\t\t\tvar peer_player_name: String = player.get_player_name()\n\t\t\tvar peer_data: Dictionary = player_to_data[peer_player_id]\n\n\t\t\t# Find matching player data\n\t\t\tvar peer_player_data: Dictionary = {}\n\t\t\tfor pd in peer_data[\"players\"]:\n\t\t\t\tif pd[\"id\"] == game_player_id:\n\t\t\t\t\tpeer_player_data = pd\n\t\t\t\t\tbreak\n\n\t\t\tvar role: String = \"AUTH\" if peer_player_id == authority_player_id else \"PEER\"\n\t\t\tvar desync_markers: Array[String] = []\n\n\t\t\t# Compare each field\n\t\t\tif peer_player_data[\"total_damage\"] != player_data[\"total_damage\"]:\n\t\t\t\tdesync_markers.append(\"damage\")\n\t\t\tif peer_player_data[\"gold_farmed\"] != player_data[\"gold_farmed\"]:\n\t\t\t\tdesync_markers.append(\"gold_farmed\")\n\t\t\tif peer_player_data[\"gold\"] != player_data[\"gold\"]:\n\t\t\t\tdesync_markers.append(\"gold\")\n\t\t\tif peer_player_data[\"tomes\"] != player_data[\"tomes\"]:\n\t\t\t\tdesync_markers.append(\"tomes\")\n\t\t\tif peer_player_data[\"lives\"] != player_data[\"lives\"]:\n\t\t\t\tdesync_markers.append(\"lives\")\n\t\t\tif peer_player_data[\"level\"] != player_data[\"level\"]:\n\t\t\t\tdesync_markers.append(\"level\")\n\n\t\t\tvar desync_str: String = \"\"\n\t\t\tif desync_markers.size() > 0:\n\t\t\t\tdesync_str = \" <<<<< DESYNC in: \" + \", \".join(desync_markers)\n\n\t\t\tlog_lines.append(\"    [%s] %s: damage=%d, gold_farmed=%d, gold=%d, tomes=%d, lives=%d%%, level=%d%s\" % [\n\t\t\t\trole, peer_player_name,\n\t\t\t\tpeer_player_data[\"total_damage\"],\n\t\t\t\tpeer_player_data[\"gold_farmed\"],\n\t\t\t\tpeer_player_data[\"gold\"],\n\t\t\t\tpeer_player_data[\"tomes\"],\n\t\t\t\tpeer_player_data[\"lives\"],\n\t\t\t\tpeer_player_data[\"level\"],\n\t\t\t\tdesync_str\n\t\t\t])\n\n\t# Compare tower data\n\tlog_lines.append(\"\")\n\tlog_lines.append(\"=== TOWER DATA COMPARISON ===\")\n\n\t# First, check if tower counts match\n\tvar tower_counts: Dictionary = {}\n\tfor player in player_list:\n\t\tvar peer_player_id: int = player.get_id()\n\t\tvar peer_data: Dictionary = player_to_data[peer_player_id]\n\t\ttower_counts[peer_player_id] = peer_data[\"towers\"].size()\n\n\tvar all_same_tower_count: bool = true\n\tvar authority_tower_count: int = tower_counts[authority_player_id]\n\t# NOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_player_ids: Array = tower_counts.keys()\n\tsorted_player_ids.sort()\n\tfor peer_player_id in sorted_player_ids:\n\t\tif tower_counts[peer_player_id] != authority_tower_count:\n\t\t\tall_same_tower_count = false\n\t\t\tbreak\n\n\tif !all_same_tower_count:\n\t\tlog_lines.append(\"  !! TOWER COUNT MISMATCH !!\")\n\t\tfor player in player_list:\n\t\t\tvar peer_player_id: int = player.get_id()\n\t\t\tvar peer_player_name: String = player.get_player_name()\n\t\t\tvar role: String = \"AUTH\" if peer_player_id == authority_player_id else \"PEER\"\n\t\t\tlog_lines.append(\"    [%s] %s: %d towers\" % [role, peer_player_name, tower_counts[peer_player_id]])\n\t\tlog_lines.append(\"\")\n\n\t# Compare individual towers\n\tlog_lines.append(\"  Comparing %d towers:\" % authority_tower_count)\n\n\tvar towers_with_desyncs: int = 0\n\tfor i in range(authority_tower_count):\n\t\tvar authority_tower: Dictionary = authority_data[\"towers\"][i]\n\t\tvar tower_uid: int = authority_tower[\"uid\"]\n\n\t\tvar has_desync: bool = false\n\n\t\t# First pass: check if this tower has any desyncs\n\t\tfor player in player_list:\n\t\t\tvar peer_player_id: int = player.get_id()\n\t\t\tif peer_player_id == authority_player_id:\n\t\t\t\tcontinue\n\n\t\t\tvar peer_data: Dictionary = player_to_data[peer_player_id]\n\n\t\t\t# Find matching tower by UID\n\t\t\tvar peer_tower: Dictionary = {}\n\t\t\tfor tower in peer_data[\"towers\"]:\n\t\t\t\tif tower[\"uid\"] == tower_uid:\n\t\t\t\t\tpeer_tower = tower\n\t\t\t\t\tbreak\n\n\t\t\tif peer_tower.is_empty():\n\t\t\t\thas_desync = true\n\t\t\t\tbreak\n\n\t\t\tif peer_tower[\"id\"] != authority_tower[\"id\"] || peer_tower[\"level\"] != authority_tower[\"level\"] || peer_tower[\"exp\"] != authority_tower[\"exp\"] || peer_tower[\"owner_id\"] != authority_tower[\"owner_id\"]:\n\t\t\t\thas_desync = true\n\t\t\t\tbreak\n\n\t\t\t# Check items\n\t\t\tif peer_tower[\"items\"].size() != authority_tower[\"items\"].size():\n\t\t\t\thas_desync = true\n\t\t\t\tbreak\n\n\t\t\tfor item_idx in range(authority_tower[\"items\"].size()):\n\t\t\t\tvar auth_item: Dictionary = authority_tower[\"items\"][item_idx]\n\t\t\t\tvar peer_item: Dictionary = peer_tower[\"items\"][item_idx]\n\n\t\t\t\tif auth_item[\"uid\"] != peer_item[\"uid\"] || auth_item[\"id\"] != peer_item[\"id\"] || auth_item[\"charges\"] != peer_item[\"charges\"] || auth_item[\"user_int\"] != peer_item[\"user_int\"] || auth_item[\"user_int2\"] != peer_item[\"user_int2\"] || auth_item[\"user_int3\"] != peer_item[\"user_int3\"] || auth_item[\"user_real\"] != peer_item[\"user_real\"] || auth_item[\"user_real2\"] != peer_item[\"user_real2\"] || auth_item[\"user_real3\"] != peer_item[\"user_real3\"]:\n\t\t\t\t\thas_desync = true\n\t\t\t\t\tbreak\n\n\t\t\tif has_desync:\n\t\t\t\tbreak\n\n\t\tif has_desync:\n\t\t\ttowers_with_desyncs += 1\n\n\t\t# Log ALL towers (not just desynced ones) to help debug\n\t\tlog_lines.append(\"\")\n\t\tvar tower_header: String = \"  Tower[uid=%d]\" % tower_uid\n\t\tif has_desync:\n\t\t\ttower_header += \" - DESYNC DETECTED:\"\n\t\telse:\n\t\t\ttower_header += \":\"\n\t\tlog_lines.append(tower_header)\n\n\t\tfor player in player_list:\n\t\t\tvar peer_player_id: int = player.get_id()\n\t\t\tvar peer_player_name: String = player.get_player_name()\n\t\t\tvar peer_data: Dictionary = player_to_data[peer_player_id]\n\t\t\tvar role: String = \"AUTH\" if peer_player_id == authority_player_id else \"PEER\"\n\n\t\t\t# Find matching tower by UID\n\t\t\tvar peer_tower: Dictionary = {}\n\t\t\tfor tower in peer_data[\"towers\"]:\n\t\t\t\tif tower[\"uid\"] == tower_uid:\n\t\t\t\t\tpeer_tower = tower\n\t\t\t\t\tbreak\n\n\t\t\tif peer_tower.is_empty():\n\t\t\t\tlog_lines.append(\"    [%s] %s: TOWER MISSING\" % [role, peer_player_name])\n\t\t\t\tcontinue\n\n\t\t\tvar tower_desync_markers: Array[String] = []\n\t\t\tif peer_tower[\"id\"] != authority_tower[\"id\"]:\n\t\t\t\ttower_desync_markers.append(\"id\")\n\t\t\tif peer_tower[\"level\"] != authority_tower[\"level\"]:\n\t\t\t\ttower_desync_markers.append(\"level\")\n\t\t\tif peer_tower[\"exp\"] != authority_tower[\"exp\"]:\n\t\t\t\ttower_desync_markers.append(\"exp\")\n\t\t\tif peer_tower[\"owner_id\"] != authority_tower[\"owner_id\"]:\n\t\t\t\ttower_desync_markers.append(\"owner_id\")\n\n\t\t\tvar tower_desync_str: String = \"\"\n\t\t\tif tower_desync_markers.size() > 0:\n\t\t\t\ttower_desync_str = \" <<<<< DESYNC in: \" + \", \".join(tower_desync_markers)\n\n\t\t\tlog_lines.append(\"    [%s] %s: id=%d, level=%d, exp=%d, owner_id=%d, items=%d%s\" % [\n\t\t\t\trole, peer_player_name,\n\t\t\t\tpeer_tower[\"id\"],\n\t\t\t\tpeer_tower[\"level\"],\n\t\t\t\tpeer_tower[\"exp\"],\n\t\t\t\tpeer_tower[\"owner_id\"],\n\t\t\t\tpeer_tower[\"items\"].size(),\n\t\t\t\ttower_desync_str\n\t\t\t])\n\n\t\t\t# Log items\n\t\t\tif peer_tower[\"items\"].size() != authority_tower[\"items\"].size():\n\t\t\t\tlog_lines.append(\"      Items: COUNT MISMATCH (AUTH=%d, THIS=%d)\" % [authority_tower[\"items\"].size(), peer_tower[\"items\"].size()])\n\t\t\telif peer_tower[\"items\"].size() > 0:\n\t\t\t\t# Always log items if there are any\n\t\t\t\tfor item_idx in range(peer_tower[\"items\"].size()):\n\t\t\t\t\tvar peer_item: Dictionary = peer_tower[\"items\"][item_idx]\n\t\t\t\t\tvar auth_item: Dictionary = authority_tower[\"items\"][item_idx]\n\n\t\t\t\t\tvar item_desync_markers: Array[String] = []\n\t\t\t\t\tif peer_item[\"uid\"] != auth_item[\"uid\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"uid\")\n\t\t\t\t\tif peer_item[\"id\"] != auth_item[\"id\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"id\")\n\t\t\t\t\tif peer_item[\"charges\"] != auth_item[\"charges\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"charges\")\n\t\t\t\t\tif peer_item[\"user_int\"] != auth_item[\"user_int\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"int\")\n\t\t\t\t\tif peer_item[\"user_int2\"] != auth_item[\"user_int2\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"int2\")\n\t\t\t\t\tif peer_item[\"user_int3\"] != auth_item[\"user_int3\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"int3\")\n\t\t\t\t\tif peer_item[\"user_real\"] != auth_item[\"user_real\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"real\")\n\t\t\t\t\tif peer_item[\"user_real2\"] != auth_item[\"user_real2\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"real2\")\n\t\t\t\t\tif peer_item[\"user_real3\"] != auth_item[\"user_real3\"]:\n\t\t\t\t\t\titem_desync_markers.append(\"real3\")\n\n\t\t\t\t\tvar item_desync_str: String = \"\"\n\t\t\t\t\tif item_desync_markers.size() > 0:\n\t\t\t\t\t\titem_desync_str = \" <<<<< DESYNC in: \" + \", \".join(item_desync_markers)\n\n\t\t\t\t\tlog_lines.append(\"      Item[%d] uid=%d, id=%d, charges=%d, int=[%d,%d,%d], real=[%d,%d,%d]%s\" % [\n\t\t\t\t\t\titem_idx,\n\t\t\t\t\t\tpeer_item[\"uid\"],\n\t\t\t\t\t\tpeer_item[\"id\"],\n\t\t\t\t\t\tpeer_item[\"charges\"],\n\t\t\t\t\t\tpeer_item[\"user_int\"],\n\t\t\t\t\t\tpeer_item[\"user_int2\"],\n\t\t\t\t\t\tpeer_item[\"user_int3\"],\n\t\t\t\t\t\tpeer_item[\"user_real\"],\n\t\t\t\t\t\tpeer_item[\"user_real2\"],\n\t\t\t\t\t\tpeer_item[\"user_real3\"],\n\t\t\t\t\t\titem_desync_str\n\t\t\t\t\t])\n\n\t# Add summary at the end of tower comparison\n\tlog_lines.append(\"\")\n\tif towers_with_desyncs == 0:\n\t\tlog_lines.append(\"  >> NO TOWER DESYNCS - All %d towers match perfectly across all clients\" % authority_tower_count)\n\telse:\n\t\tlog_lines.append(\"  >> Summary: %d/%d towers have desyncs\" % [towers_with_desyncs, authority_tower_count])\n\n\tlog_lines.append(\"\")\n\tlog_lines.append(\"========================================\")\n\tlog_lines.append(\"END DETAILED DESYNC DATA\")\n\tlog_lines.append(\"========================================\")\n\tlog_lines.append(\"\")\n\n\t# Print entire log as one message\n\tpush_error(\"\\n\".join(log_lines))\n\n\nfunc _get_player_name_list(player_list: Array[Player]) -> Array[String]:\n\tvar result: Array[String] = []\n\n\tfor player in player_list:\n\t\tvar player_name: String = player.get_player_name()\n\t\tresult.append(player_name)\n\n\treturn result\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_players_created():\n\tif !multiplayer.is_server():\n\t\treturn\n\t\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor player in player_list:\n\t\tvar player_id: int = player.get_id()\n\n\t\t_player_ping_time_map[player_id] = 0\n\t\t_player_last_contact_time[player_id] = 0\n\t\t_player_timeslot_send_queue[player_id] = {}\n\n\n# While waiting for lagging players, periodically send a\n# message to check if lagging players respond. If there's a\n# response, host will stop considering those players to be\n# lagging.\n# \n# Also in this timeout, tell clients about which players are\n# lagging.\nfunc _on_alive_check_timer_timeout():\n\tif !multiplayer.is_server():\n\t\treturn\n\t\n\tif _state != HostState.WAITING_FOR_LAGGING_PLAYERS:\n\t\treturn\n\n\tvar lagging_players: Array[Player] = _get_lagging_players()\n\tvar players_are_lagging: bool = lagging_players.size() > 0\n\n\tif players_are_lagging:\n\t\tfor player in lagging_players:\n\t\t\tvar peer_id: int = player.get_peer_id()\n\n\t\t\t_game_client.receive_alive_check.rpc_id(peer_id)\n\telse:\n\t\t_state = HostState.RUNNING\n\n\tvar lagging_player_name_list: Array[String] = _get_player_name_list(lagging_players)\n\t_game_client.set_lagging_players.rpc(lagging_player_name_list)\n"
  },
  {
    "path": "src/game_scene/game_host.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://b8hcppig3r5q6\"]\n\n[ext_resource type=\"Script\" path=\"res://src/game_scene/game_host.gd\" id=\"1_c320g\"]\n\n[node name=\"GameHost\" type=\"Node\"]\nscript = ExtResource(\"1_c320g\")\n\n[node name=\"AliveCheckTimer\" type=\"Timer\" parent=\".\"]\nautostart = true\n\n[connection signal=\"timeout\" from=\"AliveCheckTimer\" to=\".\" method=\"_on_alive_check_timer_timeout\"]\n"
  },
  {
    "path": "src/game_scene/game_scene.gd",
    "content": "class_name GameScene extends Node\n\n\n@export var _game_menu: Control\n@export var _hud: HUD\n@export var _map_small: Map\n@export var _camera: Camera2D\n@export var _camera_controller: CameraController\n@export var _team_container: TeamContainer\n@export var _game_start_timer: ManualTimer\n@export var _select_point_for_cast: SelectPointForCast\n@export var _select_target_for_cast: SelectTargetForCast\n@export var _move_item: MoveItem\n@export var _select_unit: SelectUnit\n@export var _build_tower: BuildTower\n@export var _mouse_state: MouseState\n@export var _game_client: GameClient\n@export var _game_time: GameTime\n@export var _pause_shadow_rect: ColorRect\n@export var _shadow_below_builder_menu: ColorRect\n@export var _shadow_above_builder_menu: ColorRect\n@export var _object_container: Node2D\n@export var _build_space: BuildSpace\n@export var _tutorial_menu: TutorialMenu\n@export var _tutorial_controller: TutorialController\n@export var _builder_menu: BuilderMenu\n@export var _range_checker: TowerPreview\n\nvar _ui_input_is_enabled: bool = false\nvar _map: Map = null\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tprint_verbose(\"GameScene has loaded.\")\n\t\n\tGlobals.reset()\n\tPlayerManager.reset()\n\tGroupManager.reset()\n\n#\tReplace small map with big map if playing in multiplayer\n#\tNOTE: need to swap instead of using big map for both\n#\tcases because big map makes the framerate worse,\n#\tespecially when playing in browser.\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tmatch player_mode:\n\t\tPlayerMode.enm.SINGLEPLAYER:\n\t\t\t_map = _map_small\n\t\tPlayerMode.enm.MULTIPLAYER:\n\t\t\tvar map_big_scene: PackedScene = load(\"res://src/map/map_big.tscn\")\n\t\t\tvar map_big: Map = map_big_scene.instantiate()\n\t\t\t_map_small.add_sibling(map_big)\n\t\t\t_map = map_big\n\t\t\t_map_small.get_parent().remove_child(_map_small)\n\t\t\t_map_small.queue_free()\n\t\n\tGlobals._map = _map\n\t\n\tvar camera_limits_polygon: Polygon2D = _map.get_camera_limits()\n\t_camera_controller.set_camera_limits(camera_limits_polygon)\n\n\tvar default_update_ticks_per_physics_tick: int = Config.update_ticks_per_physics_tick()\n\tGlobals.set_update_ticks_per_physics_tick(default_update_ticks_per_physics_tick)\n\n\t_hud.set_game_start_timer(_game_start_timer)\n\t\n\tEventBus.player_requested_help.connect(_on_player_requested_help)\n\tEventBus.player_requested_quit_to_title.connect(_on_player_requested_quit_to_title)\n\tEventBus.player_selected_builder.connect(_on_player_selected_builder)\n\tEventBus.player_requested_start_game.connect(_on_player_requested_start_game)\n\tEventBus.player_requested_next_wave.connect(_on_player_requested_next_wave)\n\tEventBus.player_requested_to_roll_towers.connect(_on_player_requested_to_roll_towers)\n\tEventBus.player_requested_to_research_element.connect(_on_player_requested_to_research_element)\n\tEventBus.player_requested_to_build_tower.connect(_on_player_requested_to_build_tower)\n\tEventBus.player_requested_to_upgrade_tower.connect(_on_player_requested_to_upgrade_tower)\n\tEventBus.player_requested_to_sell_tower.connect(_on_player_requested_to_sell_tower)\n\tEventBus.player_clicked_autocast.connect(_on_player_clicked_autocast)\n\tEventBus.player_requested_transmute.connect(_on_player_requested_transmute)\n\tEventBus.player_requested_return_from_horadric_cube.connect(_on_player_requested_return_from_horadric_cube)\n\tEventBus.player_requested_autofill.connect(_on_player_requested_autofill)\n\tEventBus.player_right_clicked_autocast.connect(_on_player_right_clicked_autocast)\n\tEventBus.player_right_clicked_item.connect(_on_player_right_clicked_item)\n\tEventBus.player_shift_right_clicked_item.connect(_on_player_shift_right_clicked_item)\n\tEventBus.player_clicked_tower_buff_group.connect(_on_player_clicked_tower_buff_group)\n\tEventBus.player_requested_to_sort_item_stash.connect(_on_player_requested_to_sort_item_stash)\n\t\n\t_select_unit.selected_unit_changed.connect(_on_selected_unit_changed)\n\n# \tNOTE: this is where normal gameplay starts\n\tSettings.changed.connect(_on_settings_changed)\n\t_on_settings_changed()\n\t\n#\tNOTE: load game settings which were selected during TitleScreen. They are passed via Globals.\n\tvar origin_seed: int = Globals.get_origin_seed()\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\n# \tSave the seed which host gave to this client so that rng\n# \ton this game client is the same as on all other clients.\n\tGlobals.synced_rng.set_seed(origin_seed)\n\t\n\tprint_verbose(\"Origin seed to: \", origin_seed)\n\n\t_setup_players()\n\tPlayerManager.send_players_created_signal()\n\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t_tutorial_controller.connect_to_local_player(local_player)\n\t_hud.connect_to_local_player(local_player)\n\t\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tfor player in player_list:\n\t\tplayer.voted_ready.connect(_on_player_voted_ready)\n\t\n\tfor player in player_list:\n\t\tvar buildable_cells: Array[Vector2i] = _map.get_buildable_cells(player)\n\t\t_build_space.set_buildable_cells(player, buildable_cells)\n\t\n\tif game_mode == GameMode.enm.BUILD:\n\t\tfor player in player_list:\n\t\t\tvar tower_stash: TowerStash = player.get_tower_stash()\n\t\t\ttower_stash.add_all_towers()\n\t\n\tfor player in player_list:\n\t\tplayer.generate_waves()\n\n\tvar test_item_list: Array = Config.test_item_list()\n\tfor player in player_list:\n\t\tfor item_id in test_item_list:\n\t\t\tvar item: Item = Item.make(item_id, player)\n\t\t\tvar item_stash: ItemContainer = player.get_item_stash()\n\t\t\titem_stash.add_item(item)\n\n\t_game_start_timer.start(Constants.TIME_BEFORE_FIRST_WAVE)\n\n\t_check_nodes_mapped_to_players()\n\n\t_camera.position = _get_camera_origin_pos()\n\t\n#\tNOTE: when game initially starts, we need to wait a bit for client-host connection to be established. Until that point, show shadows to block input and indicate that input is not possible.\n\t_builder_menu.show()\n\t_shadow_above_builder_menu.show()\n\t_set_ui_input_enabled(false)\n\t\n#\tNOTE: 515 is Lesser Iron Defender, average placeholder looking tower\n\t_range_checker.set_tower(515)\n\t\n#\tNOTE: tower tests need to run after everything else has\n#\tbeen initialized\n\tif Config.run_test_towers_tool():\n\t\tTestTowersTool.run(self, local_player)\n\n\tif Config.run_test_items_tool():\n\t\tTestItemsTool.run(self, local_player)\n\n\tif Config.run_test_horadric_tool():\n\t\tTestHoradricTool.run(local_player)\n\n\tif Config.run_auto_playtest_bot():\n\t\tPlaytestBot.run(_build_space)\n\n\tif Config.run_test_tower_sprite_size():\n\t\tTestTowerSpriteSize.run()\n\n\tif Config.run_test_item_drop_chances():\n\t\tTestItemDropChances.run()\n\n\nfunc _unhandled_input(event: InputEvent):\n\tvar enter_pressed: bool = event.is_action_released(\"ui_text_newline\")\n\tvar slash_pressed: bool = event.is_action_released(\"forward_slash\")\n\tvar cancel_pressed: bool = event.is_action_released(\"ui_cancel\") || event.is_action_released(\"pause\")\n\tvar left_click: bool = event.is_action_released(\"left_click\")\n\tvar right_click: bool = event.is_action_released(\"right_click\")\n\tvar hovered_unit: Unit = _select_unit.get_hovered_unit()\n\tvar hovered_tower: Tower = hovered_unit as Tower\n\tvar selected_unit: Unit = _select_unit.get_selected_unit()\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar editing_chat: bool = _hud.editing_chat()\n\t\n\tif !_ui_input_is_enabled:\n\t\tif cancel_pressed:\n\t\t\t_toggle_game_menu()\n\t\t\n\t\treturn\n\t\n\tif slash_pressed && !editing_chat:\n#\t\tNOTE: when \"/\" is pressed, automatically open chat\n#\t\tand enter the slash in chat. This makes it\n#\t\tconvenient to enter chat commands.\n\t\t_start_editing_chat()\n\t\t_hud.enter_slash_into_chat()\n\telif enter_pressed:\n\t\tif !editing_chat:\n\t\t\t_start_editing_chat()\n\t\telse:\n\t\t\t_submit_chat_message()\n\telif cancel_pressed:\n#\t\t1. First, any ongoing actions are cancelled\n#\t\t2. Then, if there are no mouse actions, hud windows\n#\t\t   are hidden\n#\t\t3. Finally, game is paused\n\t\tif _mouse_state.get_state() != MouseState.enm.NONE:\n\t\t\t_cancel_current_mouse_action()\n\t\telif editing_chat:\n\t\t\t_finish_editing_chat()\n\t\telif _hud.any_window_is_open():\n\t\t\t_hud.close_one_window()\n\t\telif selected_unit != null:\n\t\t\t_select_unit.set_selected_unit(null)\n\t\telif !_tutorial_menu.visible:\n#\t\t\tNOTE: if tutorial menu is open, the game is\n#\t\t\talready paused so game menu should not be\n#\t\t\topened. Also note that pressing Escape doesn't\n#\t\t\tclose tutorial menu on purpose - to prevent\n#\t\t\tplayer accidentally cancelling the tutorial.\n\t\t\t_toggle_game_menu()\n\telif left_click:\n\t\tmatch _mouse_state.get_state():\n\t\t\tMouseState.enm.BUILD_TOWER: _build_tower.try_to_finish(local_player)\n\t\t\tMouseState.enm.SELECT_POINT_FOR_CAST: _select_point_for_cast.finish(_map)\n\t\t\tMouseState.enm.SELECT_TARGET_FOR_CAST: _select_target_for_cast.finish(hovered_unit)\n\t\t\tMouseState.enm.MOVE_ITEM:\n\t\t\t\tif hovered_tower != null:\n\t\t\t\t\t_move_item.process_click_on_tower(hovered_tower)\n\t\t\t\telse:\n\t\t\t\t\t_move_item.process_click_on_nothing()\n\t\t\tMouseState.enm.NONE:\n#\t\t\t\tNOTE: if clicked on unit, will selected that unit\n#\t\t\t\tif clicked on nothing - deselect\n\t\t\t\t_select_unit.set_selected_unit(hovered_unit)\n\telif right_click:\n\t\tif _mouse_state.get_state() != MouseState.enm.NONE:\n\t\t\t_cancel_current_mouse_action()\n\t\telse:\n\t\t\t_do_focus_target()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_build_space() -> BuildSpace:\n\treturn _build_space\n\n\n#########################\n###      Private      ###\n#########################\n\n# Disables/enables all input (except builder menu)\nfunc _set_ui_input_enabled(enabled: bool):\n\t_shadow_below_builder_menu.visible = !enabled\n\t\n\t_ui_input_is_enabled = enabled\n\t_camera_controller.set_any_input_enabled(enabled)\n\t\n\tvar hud_process_mode: ProcessMode\n\tif enabled:\n\t\thud_process_mode = ProcessMode.PROCESS_MODE_PAUSABLE\n\telse:\n\t\thud_process_mode = ProcessMode.PROCESS_MODE_DISABLED\n\t\t\n\t_hud.set_process_mode(hud_process_mode)\n\n\nfunc _save_player_exp_on_quit():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_team: Team = local_player.get_team()\n\n#\tNOTE: if finished the game, then don't save exp because\n#\texp was already saved during win/lose process.\n\tvar finished_the_game: bool = local_team.finished_the_game()\n\tif finished_the_game:\n\t\treturn\n\n\tlocal_team.convert_local_player_score_to_exp()\n\n\nfunc _setup_players():\n\tvar peer_id_list: Array[int] = []\n\tvar local_peer_id: int = multiplayer.get_unique_id()\n\tpeer_id_list.append(local_peer_id)\n\tvar remote_peer_id_list: PackedInt32Array = multiplayer.get_peers()\n\tfor peer_id in remote_peer_id_list:\n\t\tpeer_id_list.append(peer_id)\n\n#\tNOTE: create players in the order of peer id's to ensure determinism\n\tpeer_id_list.sort()\n\t\n#\tCreate teams\n\tvar team_mode: TeamMode.enm = Globals.get_team_mode()\n\tvar player_count_per_team: int = TeamMode.get_player_count_per_team(team_mode)\n\tvar player_count: int = peer_id_list.size()\n\tvar team_count: int = ceili(player_count * 1.0 / player_count_per_team)\n\n\tfor i in range(0, team_count):\n\t\tvar team: Team = Team.make(i)\n\t\t_team_container.add_team(team)\n\n\tvar connection_type: Globals.ConnectionType = Globals.get_connect_type()\n\n\tfor peer_id in peer_id_list:\n\t\tvar player_id: int = peer_id_list.find(peer_id)\n\n#\t\tNOTE: multiply player id in \"1 player per team\" mode\n#\t\tby 2 because the second slot in teams is not\n#\t\toccupied\n\t\tif team_mode == TeamMode.enm.ONE_PLAYER_PER_TEAM:\n\t\t\tplayer_id *= 2\n\n\t\tvar user_id: String\n\t\tmatch connection_type:\n\t\t\tGlobals.ConnectionType.ENET:\n\t\t\t\tuser_id = \"\"\n\t\t\tGlobals.ConnectionType.NAKAMA:\n\t\t\t\tvar webrtc_player: OnlineMatch.WebrtcPlayer = OnlineMatch.get_player_by_peer_id(peer_id)\n\t\t\t\tuser_id = webrtc_player.user_id\n\n\t\tvar player: Player = Player.make(player_id, peer_id, user_id)\n\t\tPlayerManager.add_player(player)\n\n#\tAssign players to teams\n\tvar remaining_player_list: Array[Player] = PlayerManager.get_player_list()\n\tvar team_list: Array[Team] = _team_container.get_team_list()\n\n\tfor team in team_list:\n\t\tfor i in range(0, player_count_per_team):\n\t\t\tif remaining_player_list.is_empty():\n\t\t\t\tbreak\n\n\t\t\tvar player: Player = remaining_player_list.pop_front()\n\t\t\tteam.add_player(player)\n\n\nfunc _start_game():\n\t_game_start_timer.stop()\n\n\tvar team_list: Array[Team] = _team_container.get_team_list()\n\tfor team in team_list:\n\t\tteam.start_first_wave()\n\t\n#\tNOTE: start counting game time after first wave starts\n\t_game_time.set_enabled(true)\n\n\nfunc _toggle_autocast(autocast: Autocast):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar verify_ok: bool = ActionToggleAutocast.verify(local_player, autocast)\n\n\tif !verify_ok:\n\t\treturn\n\n\tvar autocast_uid: int = autocast.get_uid()\n\n\tvar action: Action = ActionToggleAutocast.make(autocast_uid)\n\t_game_client.add_action(action)\n\n\n# NOTE: this f-n checks nodes that are mapped to player\n# id's. If any of the players are not mapped, this will\n# print an error. For example, each of the 8 players must\n# have a camera origin node mapped to it.\nfunc _check_nodes_mapped_to_players():\n#\tCollect all mapped nodes\n\tvar camera_origin_check_list: Array[int] = []\n\tvar camera_origin_list: Array[Node] = get_tree().get_nodes_in_group(\"camera_origins\")\n\tfor node in camera_origin_list:\n\t\tvar camera_origin: CameraOrigin = node as CameraOrigin\n\t\tvar player_id: int = camera_origin.player_id\n\t\tcamera_origin_check_list.append(player_id)\n\n\tvar air_wave_path_check_list: Array[int] = []\n\tvar ground_wave_path_check_list: Array[int] = []\n\tvar wave_path_list: Array = get_tree().get_nodes_in_group(\"wave_paths\")\n\tfor node in wave_path_list:\n\t\tvar wave_path: WavePath = node as WavePath\n\t\tvar path_is_air: int = wave_path.is_air\n\t\tvar player_id: int = wave_path.player_id\n\n\t\tif path_is_air:\n\t\t\tair_wave_path_check_list.append(player_id)\n\t\telse:\n\t\t\tground_wave_path_check_list.append(player_id)\n\n\tvar buildable_area_check_list: Array[int] = []\n\tvar buildable_area_list: Array = get_tree().get_nodes_in_group(\"buildable_areas\")\n\tfor node in buildable_area_list:\n\t\tvar buildable_area: BuildableArea = node as BuildableArea\n\t\tvar player_id: int = buildable_area.player_id\n\n\t\tbuildable_area_check_list.append(player_id)\n\n#\tCheck that all players have correct sets of mapped nodes\n\tfor player_id in range(0, Constants.PLAYER_COUNT_MAX):\n\t\tvar player_has_camera_origin: bool = camera_origin_check_list.has(player_id)\n\t\tif !player_has_camera_origin:\n\t\t\tpush_error(\"Camera origin is not setup for player %d!\" % player_id)\n\n\t\tvar player_has_ground_wave_path: bool = ground_wave_path_check_list.has(player_id)\n\t\tif !player_has_ground_wave_path:\n\t\t\tpush_error(\"Ground path is not setup for player %d!\" % player_id)\n\n\t\tvar player_has_air_wave_path: bool = air_wave_path_check_list.has(player_id)\n\t\tif !player_has_air_wave_path:\n\t\t\tpush_error(\"Air path is not setup for player %d!\" % player_id)\n\n\t\tvar player_has_buildable_area: bool = buildable_area_check_list.has(player_id)\n\t\tif !player_has_buildable_area:\n\t\t\tpush_error(\"Buildable area is not setup for player %d!\" % player_id)\n\n\nfunc _get_camera_origin_pos() -> Vector2:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_player_id: int = local_player.get_id()\n\t\n\tvar local_camera_origin: CameraOrigin = null\n\t\n\tvar camera_origin_list: Array[Node] = get_tree().get_nodes_in_group(\"camera_origins\")\n\t\n\tfor node in camera_origin_list:\n\t\tif !node is CameraOrigin:\n\t\t\tpush_error(\"Incorrect type in camera_origins group\")\n\t\t\t\n\t\t\tcontinue\n\t\t\n\t\tvar camera_origin: CameraOrigin = node as CameraOrigin\n\t\tvar player_id: int = camera_origin.player_id\n\t\tvar player_match: bool = player_id == local_player_id\n\t\t\n\t\tif player_match:\n\t\t\tlocal_camera_origin = camera_origin\n\t\t\t\n\t\t\tbreak\n\t\n\tif local_camera_origin == null:\n\t\tpush_error(\"Failed to find local camera origin\")\n\t\t\n\t\treturn Vector2.ZERO\n\t\n\tvar camera_origin_pos: Vector2 = local_camera_origin.position\n\n\treturn camera_origin_pos\n\t\n\nfunc _start_editing_chat():\n\t_hud.start_editing_chat()\n\t_camera_controller.set_keyboard_enabled(false)\n\n\nfunc _finish_editing_chat():\n\t_hud.finish_editing_chat()\n\t_camera_controller.set_keyboard_enabled(true)\n\n\nfunc _submit_chat_message():\n\tvar chat_message: String = _hud.get_chat_edit_text()\n\t_finish_editing_chat()\n\n\tvar chat_action: Action = ActionChat.make(chat_message)\n\t_game_client.add_action(chat_action)\n\n\nfunc _cancel_current_mouse_action():\n\tmatch _mouse_state.get_state():\n\t\tMouseState.enm.BUILD_TOWER: _build_tower.cancel()\n\t\tMouseState.enm.SELECT_POINT_FOR_CAST: _select_point_for_cast.cancel()\n\t\tMouseState.enm.SELECT_TARGET_FOR_CAST: _select_target_for_cast.cancel()\n\t\tMouseState.enm.MOVE_ITEM: _move_item.cancel()\n\n\n# Focus targeting forces towers to attack the clicked target\n# until it dies.\nfunc _do_focus_target():\n\tvar selected_unit: Unit = _select_unit.get_selected_unit()\n\tvar hovered_unit: Unit = _select_unit.get_hovered_unit()\n\n\tif !hovered_unit is Creep:\n\t\treturn\n\n\tvar hovered_creep: Creep = hovered_unit as Creep\n\tvar target_uid: int = hovered_creep.get_uid()\n\n\tvar selected_tower: Tower = selected_unit as Tower\n\tvar selected_tower_uid: int\n\tif selected_tower != null && selected_tower.belongs_to_local_player():\n\t\tselected_tower_uid = selected_tower.get_uid()\n\telse:\n\t\tselected_tower_uid = 0\n\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar verify_ok: bool = ActionFocusTarget.verify(local_player, hovered_creep, selected_tower)\n\tif !verify_ok:\n\t\treturn\n\n\tvar action: Action = ActionFocusTarget.make(target_uid, selected_tower_uid)\n\t_game_client.add_action(action)\n\n\nfunc _toggle_game_menu():\n\t_game_menu.visible = !_game_menu.visible\n\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tif player_mode == PlayerMode.enm.SINGLEPLAYER:\n\t\tvar toggled_paused_value: bool = !get_tree().paused\n\t\t_set_game_paused(toggled_paused_value)\n\n\nfunc _set_game_paused(value: bool):\n\tvar tree: SceneTree = get_tree()\n\ttree.paused = value\n\t_pause_shadow_rect.visible = value\n\n\nfunc _show_tutorial(tutorial_id: TutorialProperties.TutorialId):\n\tvar game_is_paused: bool = get_tree().paused\n\tif game_is_paused:\n\t\tpush_error(\"A tutorial was triggered while game is paused. This should not happen\")\n\t\t\n\t\treturn\n\t\n\t_set_game_paused(true)\n\t_tutorial_menu.set_tutorial_id(tutorial_id)\n\t_tutorial_menu.show()\n\n\nfunc _get_cmdline_value(key: String):\n\tvar arguments = {}\n\tfor argument in OS.get_cmdline_user_args():\n\t\tif argument.find(\"=\") > -1:\n\t\t\tvar key_value = argument.split(\"=\")\n\t\t\targuments[key_value[0].lstrip(\"--\")] = key_value[1]\n\t\telse:\n\t\t\t# Options without an argument will be present in the dictionary,\n\t\t\t# with the value set to an empty string.\n\t\t\targuments[argument.lstrip(\"--\")] = \"\"\n\t\n\tvar cmdline_value = false\n\tif arguments.has(key):\n\t\tif arguments.get(key).is_empty():\n\t\t\tcmdline_value = true\n\t\telse:\n\t\t\tcmdline_value = arguments.get(key)\n\t\n\treturn cmdline_value\n\n\n# NOTE: need to remove objects from tree before quitting or\n# restarting. Otherwise, creeps will emit tree_exited()\n# signals, then WaveSpawner will react to those signals and\n# access tree nodes while it's in the process of deletion.\n# \n# NOTE: need to remove objects inside while loop because\n# some abilities may add new objects when another object is\n# removed.\nfunc _cleanup_all_objects():\n\twhile _object_container.get_child_count() > 0:\n\t\tvar child_list: Array[Node] = _object_container.get_children()\n\n\t\tfor child in child_list:\n#\t\t\tNOTE: need to check if child is inside tree\n#\t\t\tbecause when objects are deleted they can delete\n#\t\t\tother objects.\n\t\t\tif !child.is_inside_tree():\n\t\t\t\tcontinue\n\t\t\t\n\t\t\t_object_container.remove_child(child)\n\t\t\tchild.queue_free()\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_game_menu_continue_pressed():\n\t_toggle_game_menu()\n\n\nfunc _on_settings_changed():\n#\tNOTE: need to call update_zoom() to update camera zoom\n#\twhen interface size is changed in settings menu. Calling\n#\tupdate_zoom() inside Camera script via callback does not\n#\twork because the game is paused while the settings menu\n#\tis open.\n\t_camera_controller.update_zoom()\n\n\nfunc _on_player_requested_start_game():\n\tvar local_player_has_towers: bool = false\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\tfor tower in tower_list:\n\t\tif tower.get_player() == local_player:\n\t\t\tlocal_player_has_towers = true\n\n\tif !local_player_has_towers:\n\t\tUtils.add_ui_error(local_player, tr(\"MESSAGE_BUILD_TOWERS_BEFORE_START\"))\n\n\t\treturn\n\n\tvar action: Action = ActionChat.make(ChatCommands.READY[0])\n\t_game_client.add_action(action)\n\n\nfunc _on_game_start_timer_timeout():\n\t_start_game()\n\n\nfunc _on_player_requested_next_wave():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\n\tvar verify_ok: bool = ActionStartNextWave.verify(local_player)\n\n\tif !verify_ok:\n\t\treturn\n\n\tvar action: Action = ActionStartNextWave.make()\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_to_roll_towers():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t\n\tvar verify_ok: bool = ActionRollTowers.verify(local_player)\n\n\tif !verify_ok:\n\t\treturn\n\n\tvar action: Action = ActionRollTowers.make()\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_to_research_element(element: Element.enm):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t\n\tvar verify_ok: bool = ActionResearchElement.verify(local_player, element)\n\n\tif !verify_ok:\n\t\treturn\n\n\tvar action: Action = ActionResearchElement.make(element)\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_to_build_tower(tower_id: int):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t_build_tower.start(tower_id, local_player)\n\n\nfunc _on_player_requested_to_upgrade_tower(preceding_tower: Tower):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar verify_ok: bool = ActionUpgradeTower.verify(local_player, preceding_tower)\n\tif !verify_ok:\n\t\treturn\n\n\tvar mouse_pos: Vector2 = _map.get_global_mouse_position()\n\tvar random_pitch: float = Globals.local_rng.randf_range(1.0, 1.1)\n\tSFX.sfx_at_pos(SfxPaths.BUILD_TOWER, mouse_pos, 0.0, random_pitch)\n\n\tvar preceding_tower_uid: int = preceding_tower.get_uid()\n\tvar action: Action = ActionUpgradeTower.make(preceding_tower_uid)\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_to_sell_tower(tower: Tower):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar verify_ok: bool = ActionSellTower.verify(local_player, tower)\n\tif !verify_ok:\n\t\treturn\n\n\tSFX.play_sfx(SfxPaths.PICKUP_GOLD)\n\n\tvar tower_unit_id: int = tower.get_uid()\n\tvar action: Action = ActionSellTower.make(tower_unit_id)\n\t_game_client.add_action(action)\n\n\nfunc _on_player_clicked_autocast(autocast: Autocast):\n\tif !autocast.can_cast():\n\t\tautocast.add_cast_error_message()\n\n\t\treturn\n\n\tvar autocast_uid: int = autocast.get_uid()\n\n#\tNOTE: immediate autocasts do not have targets. For other\n#\tautocast types we switch to selecting the target. The\n#\tcast will finish when player selects a target and\n#\tSelectTargetForCast.finish() or\n#\tSelectPointForCast.finish() gets called.\n\tif autocast.type_is_immediate():\n\t\tvar target_uid: int = 0\n\t\tvar target_pos: Vector2 = Vector2.ZERO\n\t\tvar action: Action = ActionAutocast.make(autocast_uid, target_uid, target_pos)\n\t\t_game_client.add_action(action)\n\telif autocast.type_is_point():\n\t\t_select_point_for_cast.start(autocast)\n\telse:\n\t\t_select_target_for_cast.start(autocast)\n\n\nfunc _on_selected_unit_changed(_prev_unit: Unit):\n\tvar selected_unit: Unit = _select_unit.get_selected_unit()\n\t_hud.set_menu_unit(selected_unit)\n\n\nfunc _on_player_requested_autofill(recipe: HoradricCube.Recipe, rarity_filter: Array):\n\tvar random_pitch: float = Globals.local_rng.randf_range(1.0, 1.1)\n\tSFX.play_sfx(SfxPaths.PICKUP_ITEM, 0.0, random_pitch)\n\t\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t\n\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\tvar horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\n#\tNOTE: need to also include items which are currently in\n#\thoradric cube because ignoring them would be an annoying\n#\tbehavior for player. Player would need to manually move\n#\tall items back to item stash for them to be included in\n#\tautofill item pool.\n\tvar full_item_list: Array[Item] = []\n\tvar item_stash_item_list: Array[Item] = item_stash.get_item_list()\n\tvar horadric_stash_item_list: Array[Item] = horadric_stash.get_item_list()\n\tfull_item_list.append_array(item_stash_item_list)\n\tfull_item_list.append_array(horadric_stash_item_list)\n\n\tvar filtered_item_list: Array[Item] = Utils.filter_item_list(full_item_list, rarity_filter)\n\tvar autofill_list: Array[Item] = HoradricCube.get_item_list_for_autofill(recipe, filtered_item_list)\n\n\tvar can_autofill: bool = !autofill_list.is_empty()\n\t\n\tif !can_autofill:\n\t\tUtils.add_ui_error(local_player, tr(\"MESSAGE_NOT_ENOUGH_ITEMS_FOR_RECIPE\"))\n\t\t\n\t\treturn\n\n\tvar autofill_uid_list: Array[int] = []\n\tfor item in autofill_list:\n\t\tvar item_uid: int = item.get_uid()\n\t\tautofill_uid_list.append(item_uid)\n\n\tvar action: Action = ActionAutofill.make(autofill_uid_list)\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_transmute():\n\tvar random_pitch: float = Globals.local_rng.randf_range(1.0, 1.1)\n\tSFX.play_sfx(SfxPaths.PICKUP_ITEM, 0.0, random_pitch)\n\t\n\tvar action: Action = ActionTransmute.make()\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_return_from_horadric_cube():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\tvar horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\tvar items_in_horadric_stash: Array[Item] = horadric_stash.get_item_list()\n\n\tvar src_container_uid: int = horadric_stash.get_uid()\n\tvar dest_container_uid: int = item_stash.get_uid()\n\n\tfor item in items_in_horadric_stash:\n\t\tvar item_uid: int = item.get_uid()\n\t\tvar action: Action = ActionMoveItem.make(item_uid, src_container_uid, dest_container_uid)\n\t\t\n\t\t_game_client.add_action(action)\n\n\nfunc _on_builder_menu_finished():\n\tvar builder_id: int = _builder_menu.get_builder_id()\n\n\tvar action: Action = ActionSelectBuilder.make(builder_id)\n\t_game_client.add_action(action)\n\n\n# NOTE: need to do action for wisdom upgrades after setting\n# builders because some builders affect wisdom upgrades.\nfunc _on_player_selected_builder():\n\t_builder_menu.hide()\n\t_builder_menu.queue_free()\n\t_builder_menu = null\n\t\n\t_set_ui_input_enabled(true)\n\t\n\tvar wisdom_upgrades: Dictionary = Settings.get_wisdom_upgrades()\n\tvar action: Action = ActionSelectWisdomUpgrades.make(wisdom_upgrades)\n\t_game_client.add_action(action)\n\n\tvar wave_count: int = Globals.get_wave_count()\n\tvar difficulty: Difficulty.enm = Globals.get_difficulty()\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar difficulty_string: String = Difficulty.convert_to_colored_string(difficulty)\n\tvar game_mode_string: String = GameMode.convert_to_display_string(game_mode)\n\tvar local_player: Player = PlayerManager.get_local_player()\n\n\tMessages.add_normal(local_player, tr(\"MESSAGE_WELCOME_1\"))\n\tMessages.add_normal(local_player, tr(\"MESSAGE_WELCOME_2\").format({WAVE_COUNT = wave_count, DIFFICULTY = difficulty_string, GAME_MODE = game_mode_string}))\n\n\nfunc _on_player_voted_ready():\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tvar not_ready_player_list: Array[Player] = []\n\t\n\tfor player in player_list:\n\t\tif !player.is_ready():\n\t\t\tnot_ready_player_list.append(player)\n\t\n\tvar all_players_are_ready: bool = not_ready_player_list.is_empty()\n\n\tif all_players_are_ready:\n\t\tMessages.add_normal(null, tr(\"MESSAGE_PLAYERS_READY\"))\n\t\t_start_game()\n\telse:\n\t\tfor player in not_ready_player_list:\n\t\t\tvar player_name: String = player.get_player_name_with_color()\n\t\t\tMessages.add_normal(null, tr(\"MESSAGE_WAITING_FOR_PLAYER\").format({PLAYER_NAME = player_name}))\n\n\nfunc _on_player_right_clicked_autocast(autocast: Autocast):\n\t_toggle_autocast(autocast)\n\n\nfunc _on_player_right_clicked_item(item: Item):\n\tvar clicked_on_consumable: bool = item.is_consumable()\n\tvar autocast: Autocast = item.get_autocast()\n\tvar carrier: Unit = item.get_carrier()\n\tvar clicked_on_item_with_autocast: bool = autocast != null && carrier != null\n\n\tif clicked_on_consumable:\n\t\tvar local_player: Player = PlayerManager.get_local_player()\n\t\tvar verify_ok: bool = ActionConsumeItem.verify(local_player, item)\n\t\tif !verify_ok:\n\t\t\treturn\n\n\t\tvar item_uid: int = item.get_uid()\n\t\tvar action: Action = ActionConsumeItem.make(item_uid)\n\t\t_game_client.add_action(action)\n\telif clicked_on_item_with_autocast:\n\t\t_on_player_clicked_autocast(autocast)\n\n\nfunc _on_player_shift_right_clicked_item(item: Item):\n\tvar autocast: Autocast = item.get_autocast()\n\n\tif autocast != null:\n\t\t_toggle_autocast(autocast)\n\n\nfunc _on_player_clicked_tower_buff_group(tower: Tower, buff_group: int):\n\tvar tower_uid: int = tower.get_uid()\n\tvar current_mode: BuffGroupMode.enm = tower.get_buff_group_mode(buff_group)\n\tvar new_mode: BuffGroupMode.enm = wrapi(current_mode + 1, BuffGroupMode.enm.NONE, BuffGroupMode.enm.BOTH + 1) as BuffGroupMode.enm\n\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar verify_ok: bool = ActionChangeBuffgroup.verify(local_player, tower)\n\tif !verify_ok:\n\t\treturn\n\t\n\tvar action: Action = ActionChangeBuffgroup.make(tower_uid, buff_group, new_mode)\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_to_sort_item_stash():\n\tvar action: Action = ActionSortItemStash.make()\n\t_game_client.add_action(action)\n\n\nfunc _on_player_requested_help():\n\t_toggle_game_menu()\n\t_game_menu.switch_to_help_menu()\n\n\nfunc _on_game_menu_quit_pressed():\n\t_quit_to_title()\n\n\nfunc _on_player_requested_quit_to_title():\n\t_quit_to_title()\n\n\nfunc _quit_to_title():\n\t_save_player_exp_on_quit()\n\t_cleanup_all_objects()\n\tOnlineMatch.leave()\n\tget_tree().set_pause(false)\n#\tNOTE: need to use load() here instead of preload()\n#\tbecause preload() causes an error here since Godot\n#\t4.1->4.3 migration, for unknown reason.\n\tvar title_screen_scene: PackedScene = load(\"res://src/ui/title_screen/title_screen.tscn\")\n\tget_tree().change_scene_to_packed(title_screen_scene)\n\n\nfunc _on_tutorial_controller_tutorial_triggered(tutorial_id):\n#\tNOTE: ignore tutorial triggers in build mode because\n#\ttutorial is written for random mode and shouldn't show\n#\tup in build mode. Don't ignore the trigger for intro\n#\tbecause it's necessary to show it.\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar game_mode_is_build: bool = game_mode == GameMode.enm.BUILD\n\tif game_mode_is_build && tutorial_id != TutorialProperties.TutorialId.INTRO_FOR_BUILD_MODE:\n\t\treturn\n\t\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tvar player_mode_is_single: bool = player_mode == PlayerMode.enm.SINGLEPLAYER\n\tif !player_mode_is_single:\n\t\treturn\n\n\tvar tutorial_is_enabled_in_settings: bool = Settings.get_bool_setting(Settings.SHOW_TUTORIAL_ON_START)\n\tif !tutorial_is_enabled_in_settings:\n\t\treturn\n\t\n\t_show_tutorial(tutorial_id)\n\n\nfunc _on_tutorial_menu_hidden():\n\t_set_game_paused(false)\n\n\n# NOTE: when first timeslot is received, that means that client has connected to host and it is safe to send actions now. Hide shadow above builder menu to allow player to select builder.\nfunc _on_game_client_received_first_timeslot():\n\t_shadow_above_builder_menu.hide()\n"
  },
  {
    "path": "src/game_scene/game_scene.tscn",
    "content": "[gd_scene load_steps=49 format=3 uid=\"uid://ccr6p41srpf4p\"]\n\n[ext_resource type=\"Script\" path=\"res://src/game_scene/game_scene.gd\" id=\"1_0wd1b\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_gestc\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/team_container.gd\" id=\"3_qsih1\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/game_time.gd\" id=\"5_8syq6\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/select_unit.gd\" id=\"6_vam2w\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/select_point_for_cast.gd\" id=\"7_h82dk\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/select_target_for_cast.gd\" id=\"8_n5fu4\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/move_item.gd\" id=\"9_tujdk\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/build_tower.gd\" id=\"10_tkjjb\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/mouse_state.gd\" id=\"11_e0bvs\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/combat_log_storage.gd\" id=\"12_8gb75\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b8hcppig3r5q6\" path=\"res://src/game_scene/game_host.tscn\" id=\"12_sbijg\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dp2tmdi8ms5qo\" path=\"res://src/game_scene/game_client.tscn\" id=\"15_a5l86\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/chat_commands.gd\" id=\"16_amwbk\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/build_space.gd\" id=\"16_p1jwo\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/tutorial_controller.gd\" id=\"17_5cvlj\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/camera_controller.gd\" id=\"17_imw8o\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bjvafnsglmpin\" path=\"res://src/map/map_small.tscn\" id=\"17_td8cv\"]\n[ext_resource type=\"Script\" path=\"res://src/creeps/wave_path.gd\" id=\"18_m2fcq\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://u567sx64fpwa\" path=\"res://src/missions/mission_manager.tscn\" id=\"18_ujbrx\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ccrjj36jwy707\" path=\"res://src/player/camera_origin.tscn\" id=\"19_icnp7\"]\n[ext_resource type=\"Script\" path=\"res://src/effects/effects_container.gd\" id=\"20_rnpn6\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://djkt0t0jveoks\" path=\"res://src/effects/vampiric_aura.tscn\" id=\"21_5ytv3\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://db0630tccvc2i\" path=\"res://src/towers/tower_preview.tscn\" id=\"22_53ta1\"]\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/saturation_burn.gdshader\" id=\"23_go3nh\"]\n[ext_resource type=\"Shader\" path=\"res://resources/shaders/foggy_camera.gdshader\" id=\"24_omg4c\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cngv1rgplre2c\" path=\"res://src/ui/hud/hud.tscn\" id=\"25_m068l\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://4dakdefm73rd\" path=\"res://src/ui/hud/builder_menu.tscn\" id=\"26_2bi2s\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://hiex318b5cvk\" path=\"res://src/ui/game_menu/game_menu.tscn\" id=\"26_xukvx\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://u1yl8rbswhtp\" path=\"res://src/ui/hud/tutorial_menu.tscn\" id=\"27_vroom\"]\n\n[sub_resource type=\"Curve2D\" id=\"1\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 2555, -2374, 0, 0, 0, 0, -376, -882, 3.76354, -42.3398, -3.76354, 42.3398, -426, -827, 0, 0, 0, 0, -386, -759, 0, 0, 0, 0, 384, -373, -36.6945, -0.470442, 36.6945, 0.470442, 500, -341, 0, 0, 0, 0, 643, -372, 0, 0, 0, 0, 2050, -1077, -45.8031, 3.23768, 45.8031, -3.23768, 2174, -1124, 0, 0, 0, 0, 2309, -1077, 0, 0, 0, 0, 3071, -689, 1.40535, -33.4014, -1.40535, 33.4014, 3131, -625, 0, 0, 0, 0, 3075, -562, 0, 0, 0, 0, 642, 647, 40.458, 0.470442, -40.458, -0.470442, 515, 695, 0, 0, 0, 0, 388, 648, 0, 0, 0, 0, -897, 9, 45.1023, 0.136732, -45.1023, -0.136732, -1022, -33, 0, 0, 0, 0, -1152, 8, 0, 0, 0, 0, -1920, 394, -0.840896, -31.3902, 0.840896, 31.3902, -1961, 459, 0, 0, 0, 0, -1919, 521, 0, 0, 0, 0, -640, 1163, 0.379654, -32.8072, -0.379654, 32.8072, -603, 1228, 0, 0, 0, 0, -641, 1290, 0, 0, 0, 0, -3200, 2558)\n}\npoint_count = 26\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_72x3r\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 2558, -2376, 0, 0, 0, 0, 1540, -1845, 0, 0, 0, 0, 1537, 206, 0, 0, 0, 0, -1536, 188, 0, 0, 0, 0, -1149, 1536, 0, 0, 0, 0, -3198, 2557)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_u40fb\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 6655, -324, 0, 0, 0, 0, 3712, 1167, 67.4238, 0.374577, -67.4238, -0.374577, 3585, 1199, 0, 0, 0, 0, 3457, 1165, 0, 0, 0, 0, 2689, 780, 0.471937, 35.3953, -0.471937, -35.3953, 2652, 717, 0, 0, 0, 0, 2689, 654, 0, 0, 0, 0, 4097, -50, 0, 39.1708, 0, -39.1708, 4130, -114, 0, 0, 0, 0, 4097, -177, 0, 0, 0, 0, 3330, -563, 41.0585, -1.41581, -41.0585, 1.41581, 3199, -597, 0, 0, 0, 0, 3075, -559, 0, 0, 0, 0, 641, 650, 1.5, -34.5, -1.5, 34.5, 607, 711, 0, 0, 0, 0, 638, 776, 0, 0, 0, 0, 1922, 1420, 1, -39.5, -1, 39.5, 1958, 1483, 0, 0, 0, 0, 1916, 1546, 0, 0, 0, 0, 1151, 1927, 54.5, -1.5, -54.5, 1.5, 1020, 1952, 0, 0, 0, 0, 897, 1929, 0, 0, 0, 0, -387, 1288, 54.5, 1, -54.5, -1, -517, 1253, 0, 0, 0, 0, -639, 1287, 0, 0, 0, 0, -3200, 2559)\n}\npoint_count = 26\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_gtbgo\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 6658, -328, 0, 0, 0, 0, 5637, 189, 0, 0, 0, 0, 1535, 202, 0, 0, 0, 0, 1540, 1729, 0, 0, 0, 0, -1149, 1537, 0, 0, 0, 0, -3203, 2561)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_cq3y7\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 6656, 5447, 0, 0, 0, 0, 3709, 3975, 127.961, -62.2966, -127.961, 62.2966, 3457, 3976, 0, 0, 0, 0, 2688, 4357, -127.356, -61.4306, 127.356, 61.4306, 2689, 4489, 0, 0, 0, 0, 3966, 5131, 122.053, -63.6993, -122.053, 63.6993, 3969, 5257, 0, 0, 0, 0, 3199, 5642, 125.865, 63.6396, -125.865, -63.6396, 2946, 5640, 0, 0, 0, 0, 639, 4490, -123.648, 66.0712, 123.648, -66.0712, 640, 4360, 0, 0, 0, 0, 1918, 3720, 130.767, 63.4191, -130.767, -63.4191, 1916, 3593, 0, 0, 0, 0, 1153, 3208, 127.423, -62.7676, -127.423, 62.7676, 897, 3209, 0, 0, 0, 0, -384, 3850, 128.195, 66.7462, -128.195, -66.7462, -640, 3848, 0, 0, 0, 0, -3201, 2563)\n}\npoint_count = 18\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_46yp1\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 6656, 5451, 0, 0, 0, 0, 5631, 4937, 0, 0, 0, 0, 1536, 4937, 0, 0, 0, 0, 1539, 3403, 0, 0, 0, 0, -1152, 3592, 0, 0, 0, 0, -3202, 2563)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_pp4lg\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 2562, 7498, 0, 0, 0, 0, -383, 6026, -131.328, 67.909, 131.328, -67.909, -380, 5895, 0, 0, 0, 0, 379, 5511, -125.155, -62.8579, 125.155, 62.8579, 636, 5513, 0, 0, 0, 0, 1921, 6154, -130.5, 64, 130.5, -64, 2178, 6154, 0, 0, 0, 0, 2941, 5770, 124.487, 63.5678, -124.487, -63.5678, 2945, 5641, 0, 0, 0, 0, 639, 4492, 128.812, -66.742, -128.812, 66.742, 381, 4492, 0, 0, 0, 0, -897, 5130, 126.5, 66, -126.5, -66, -1152, 5129, 0, 0, 0, 0, -1922, 4745, -126.81, 65.4072, 126.81, -65.4072, -1921, 4618, 0, 0, 0, 0, -639, 3977, 123.5, 66, -123.5, -66, -638, 3848, 0, 0, 0, 0, -3200, 2563)\n}\npoint_count = 18\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_rkhsb\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, 2562, 7497, 0, 0, 0, 0, 1532, 6986, 0, 0, 0, 0, 1535, 4938, 0, 0, 0, 0, -1537, 4938, 0, 0, 0, 0, -1152, 3593, 0, 0, 0, 0, -3201, 2562)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_bg1uo\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -8959, 7496, 0, 0, 0, 0, -6018, 6026, 131, 64.5, -131, -64.5, -6019, 5898, 0, 0, 0, 0, -6783, 5515, 130.813, -63.028, -130.813, 63.028, -7041, 5514, 0, 0, 0, 0, -8448, 6218, 127.961, 65.1028, -127.961, -65.1028, -8705, 6217, 0, 0, 0, 0, -9473, 5835, -124.032, 65.664, 124.032, -65.664, -9474, 5705, 0, 0, 0, 0, -7040, 4487, -132.548, -65.0834, 132.548, 65.0834, -6780, 4489, 0, 0, 0, 0, -5507, 5129, -130.727, 62.2957, 130.727, -62.2957, -5251, 5128, 0, 0, 0, 0, -4483, 4747, 123.957, 64.0975, -123.957, -64.0975, -4478, 4617, 0, 0, 0, 0, -5762, 3975, -124.102, 66.1459, 124.102, -66.1459, -5761, 3849, 0, 0, 0, 0, -3202, 2562)\n}\npoint_count = 18\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_6lk1i\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -8958, 7494, 0, 0, 0, 0, -7933, 6984, 0, 0, 0, 0, -7940, 4935, 0, 0, 0, 0, -4864, 4935, 0, 0, 0, 0, -5252, 3592, 0, 0, 0, 0, -3203, 2561)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_mksiu\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -13060, 5441, 0, 0, 0, 0, -10114, 3978, -129.029, -64.8118, 129.029, 64.8118, -9855, 3978, 0, 0, 0, 0, -9087, 4359, 124.102, -61.7361, -124.102, 61.7361, -9088, 4488, 0, 0, 0, 0, -10498, 5192, -124.451, -62.9325, 124.451, 62.9325, -10497, 5321, 0, 0, 0, 0, -9730, 5704, -131.903, 64.0975, 131.903, -64.0975, -9470, 5706, 0, 0, 0, 0, -7040, 4487, 126.595, 63.8929, -126.595, -63.8929, -7043, 4363, 0, 0, 0, 0, -8321, 3721, -127, 67, 127, -67, -8320, 3592, 0, 0, 0, 0, -7552, 3208, -126.5, -63, 126.5, 63, -7297, 3207, 0, 0, 0, 0, -6016, 3849, -125, 62, 125, -62, -5761, 3851, 0, 0, 0, 0, -3201, 2563)\n}\npoint_count = 18\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_niioj\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -13059, 5446, 0, 0, 0, 0, -12033, 4936, 0, 0, 0, 0, -7939, 4934, 0, 0, 0, 0, -7940, 3403, 0, 0, 0, 0, -5252, 3593, 0, 0, 0, 0, -3201, 2565)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_l5rss\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -13053, -317, 0, 0, 0, 0, -10110, 1160, -126.277, 64.5416, 126.277, -64.5416, -9858, 1160, 0, 0, 0, 0, -9088, 777, 122.138, 66.0746, -122.138, -66.0746, -9086, 649, 0, 0, 0, 0, -10370, 11, -125.865, 65.0538, 125.865, -65.0538, -10365, -120, 0, 0, 0, 0, -9602, -505, -126.076, -70.984, 126.076, 70.984, -9348, -503, 0, 0, 0, 0, -7039, 647, 112.246, -67.3477, -112.246, 67.3477, -7040, 775, 0, 0, 0, 0, -8322, 1414, -129.18, -59.6902, 129.18, 59.6902, -8320, 1544, 0, 0, 0, 0, -7551, 1928, -125.158, 65.0538, 125.158, -65.0538, -7298, 1929, 0, 0, 0, 0, -6016, 1286, -125.617, -63.2538, 125.617, 63.2538, -5759, 1286, 0, 0, 0, 0, -3201, 2560)\n}\npoint_count = 18\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_xs7e3\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -13054, -312, 0, 0, 0, 0, -12026, 203, 0, 0, 0, 0, -7937, 201, 0, 0, 0, 0, -7933, 1736, 0, 0, 0, 0, -5251, 1546, 0, 0, 0, 0, -3201, 2559)\n}\npoint_count = 6\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_8wjuw\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -8959, -2358, 0, 0, 0, 0, -6017, -886, 126.572, -60.1041, -126.572, 60.1041, -6020, -762, 0, 0, 0, 0, -6780, -372, 129.784, 65.157, -129.784, -65.157, -7038, -375, 0, 0, 0, 0, -8321, -1014, 132.292, -64.8859, -132.292, 64.8859, -8577, -1014, 0, 0, 0, 0, -9343, -630, -120.11, -61.8388, 120.11, 61.8388, -9346, -503, 0, 0, 0, 0, -7037, 648, -132.292, 64.256, 132.292, -64.256, -6780, 648, 0, 0, 0, 0, -5504, 8, -123.037, -64.3467, 123.037, 64.3467, -5250, 10, 0, 0, 0, 0, -4479, 392, 122.805, -60.7352, -122.805, 60.7352, -4479, 519, 0, 0, 0, 0, -5764, 1161, -116.097, -61.3518, 116.097, 61.3518, -5762, 1285, 0, 0, 0, 0, -3206, 2557)\n}\npoint_count = 18\n\n[sub_resource type=\"Curve2D\" id=\"Curve2D_sd1kw\"]\n_data = {\n\"points\": PackedVector2Array(0, 0, 0, 0, -8958, -2360, 0, 0, 0, 0, -7936, -1847, 0, 0, 0, 0, -7938, 201, 0, 0, 0, 0, -4863, 199, 0, 0, 0, 0, -5243, 1545, 0, 0, 0, 0, -3205, 2562)\n}\npoint_count = 6\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_cij5r\"]\nshader = ExtResource(\"23_go3nh\")\nshader_parameter/vignette_intensity = 1.214\nshader_parameter/edge_saturation = 0.174\n\n[sub_resource type=\"ShaderMaterial\" id=\"ShaderMaterial_6fevd\"]\nshader = ExtResource(\"24_omg4c\")\nshader_parameter/vignette_intensity = 0.299\nshader_parameter/vignette_opacity = 0.742\nshader_parameter/vignette_rgb = Color(0, 0, 0.129412, 1)\n\n[node name=\"GameScene\" type=\"Node\" node_paths=PackedStringArray(\"_game_menu\", \"_hud\", \"_map_small\", \"_camera\", \"_camera_controller\", \"_team_container\", \"_game_start_timer\", \"_select_point_for_cast\", \"_select_target_for_cast\", \"_move_item\", \"_select_unit\", \"_build_tower\", \"_mouse_state\", \"_game_client\", \"_game_time\", \"_pause_shadow_rect\", \"_shadow_below_builder_menu\", \"_shadow_above_builder_menu\", \"_object_container\", \"_build_space\", \"_tutorial_menu\", \"_tutorial_controller\", \"_builder_menu\", \"_range_checker\")]\nprocess_mode = 3\nscript = ExtResource(\"1_0wd1b\")\n_game_menu = NodePath(\"UI/GameMenu\")\n_hud = NodePath(\"UI/HUD\")\n_map_small = NodePath(\"World/MapSmall\")\n_camera = NodePath(\"World/Camera2D\")\n_camera_controller = NodePath(\"Gameplay/CameraController\")\n_team_container = NodePath(\"Gameplay/TeamContainer\")\n_game_start_timer = NodePath(\"Gameplay/GameStartTimer\")\n_select_point_for_cast = NodePath(\"Gameplay/SelectPointForCast\")\n_select_target_for_cast = NodePath(\"Gameplay/SelectTargetForCast\")\n_move_item = NodePath(\"Gameplay/MoveItem\")\n_select_unit = NodePath(\"Gameplay/SelectUnit\")\n_build_tower = NodePath(\"Gameplay/BuildTower\")\n_mouse_state = NodePath(\"Gameplay/MouseState\")\n_game_client = NodePath(\"Gameplay/GameClient\")\n_game_time = NodePath(\"Gameplay/GameTime\")\n_pause_shadow_rect = NodePath(\"UI/PauseShadowRect\")\n_shadow_below_builder_menu = NodePath(\"UI/ShadowBelowBuilderMenu\")\n_shadow_above_builder_menu = NodePath(\"UI/ShadowAboveBuilderMenu\")\n_object_container = NodePath(\"World/ObjectContainer\")\n_build_space = NodePath(\"Gameplay/BuildSpace\")\n_tutorial_menu = NodePath(\"UI/VBoxContainer/TutorialMenu\")\n_tutorial_controller = NodePath(\"Gameplay/TutorialController\")\n_builder_menu = NodePath(\"UI/BuilderMenu\")\n_range_checker = NodePath(\"World/RangeChecker\")\n\n[node name=\"Gameplay\" type=\"Node\" parent=\".\"]\nprocess_mode = 1\n\n[node name=\"GameStartTimer\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"2_gestc\")\none_shot = true\n\n[node name=\"TeamContainer\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"3_qsih1\")\n\n[node name=\"GameTime\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"5_8syq6\")\n\n[node name=\"SelectUnit\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_game_client\")]\nscript = ExtResource(\"6_vam2w\")\n_game_client = NodePath(\"../GameClient\")\n\n[node name=\"SelectPointForCast\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_mouse_state\", \"_game_client\")]\nscript = ExtResource(\"7_h82dk\")\n_mouse_state = NodePath(\"../MouseState\")\n_game_client = NodePath(\"../GameClient\")\n\n[node name=\"SelectTargetForCast\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_mouse_state\", \"_game_client\")]\nscript = ExtResource(\"8_n5fu4\")\n_mouse_state = NodePath(\"../MouseState\")\n_game_client = NodePath(\"../GameClient\")\n\n[node name=\"MoveItem\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_mouse_state\", \"_world\", \"_game_client\")]\nscript = ExtResource(\"9_tujdk\")\n_mouse_state = NodePath(\"../MouseState\")\n_world = NodePath(\"../../World\")\n_game_client = NodePath(\"../GameClient\")\n\n[node name=\"BuildTower\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_mouse_state\", \"_build_space\", \"_tower_preview\", \"_game_client\")]\nscript = ExtResource(\"10_tkjjb\")\n_mouse_state = NodePath(\"../MouseState\")\n_build_space = NodePath(\"../BuildSpace\")\n_tower_preview = NodePath(\"../../World/TowerPreview\")\n_game_client = NodePath(\"../GameClient\")\n\n[node name=\"MouseState\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"11_e0bvs\")\n\n[node name=\"CombatLogStorage\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"12_8gb75\")\n\n[node name=\"GameHost\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_game_client\", \"_hud\") instance=ExtResource(\"12_sbijg\")]\n_game_client = NodePath(\"../GameClient\")\n_hud = NodePath(\"../../UI/HUD\")\n\n[node name=\"GameClient\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_game_host\", \"_game_time\", \"_hud\", \"_build_space\", \"_chat_commands\", \"_select_unit\") instance=ExtResource(\"15_a5l86\")]\n_game_host = NodePath(\"../GameHost\")\n_game_time = NodePath(\"../GameTime\")\n_hud = NodePath(\"../../UI/HUD\")\n_build_space = NodePath(\"../BuildSpace\")\n_chat_commands = NodePath(\"../ChatCommands\")\n_select_unit = NodePath(\"../SelectUnit\")\n\n[node name=\"ChatCommands\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_team_container\", \"_hud\", \"_game_client\", \"_range_checker\")]\nscript = ExtResource(\"16_amwbk\")\n_team_container = NodePath(\"../TeamContainer\")\n_hud = NodePath(\"../../UI/HUD\")\n_game_client = NodePath(\"../GameClient\")\n_range_checker = NodePath(\"../../World/RangeChecker\")\n\n[node name=\"BuildSpace\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"16_p1jwo\")\n\n[node name=\"TutorialController\" type=\"Node\" parent=\"Gameplay\"]\nscript = ExtResource(\"17_5cvlj\")\n\n[node name=\"CameraController\" type=\"Node\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_camera\")]\nscript = ExtResource(\"17_imw8o\")\n_camera = NodePath(\"../../World/Camera2D\")\n\n[node name=\"MissionManager\" parent=\"Gameplay\" node_paths=PackedStringArray(\"_hud\") instance=ExtResource(\"18_ujbrx\")]\n_hud = NodePath(\"../../UI/HUD\")\n\n[node name=\"World\" type=\"Node2D\" parent=\".\"]\nprocess_mode = 1\ny_sort_enabled = true\n\n[node name=\"MapSmall\" parent=\"World\" instance=ExtResource(\"17_td8cv\")]\n\n[node name=\"PathContainer\" type=\"Node2D\" parent=\"World\"]\nz_index = 999\n\n[node name=\"Ground0\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"1\")\nscript = ExtResource(\"18_m2fcq\")\n\n[node name=\"Air0\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_72x3r\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\n\n[node name=\"Ground1\" type=\"Path2D\" parent=\"World/PathContainer\"]\nmodulate = Color(0.52549, 0.329412, 0, 1)\ncurve = SubResource(\"Curve2D_u40fb\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 1\n\n[node name=\"Air1\" type=\"Path2D\" parent=\"World/PathContainer\"]\nmodulate = Color(1, 0, 1, 1)\ncurve = SubResource(\"Curve2D_gtbgo\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 1\n\n[node name=\"Ground2\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_cq3y7\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 2\n\n[node name=\"Air2\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_46yp1\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 2\n\n[node name=\"Ground3\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_pp4lg\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 3\n\n[node name=\"Air3\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_rkhsb\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 3\n\n[node name=\"Ground4\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_bg1uo\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 4\n\n[node name=\"Air4\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_6lk1i\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 4\n\n[node name=\"Ground5\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_mksiu\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 5\n\n[node name=\"Air5\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_niioj\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 5\n\n[node name=\"Ground6\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_l5rss\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 6\n\n[node name=\"Air6\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_xs7e3\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 6\n\n[node name=\"Ground7\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_8wjuw\")\nscript = ExtResource(\"18_m2fcq\")\nplayer_id = 7\n\n[node name=\"Air7\" type=\"Path2D\" parent=\"World/PathContainer\"]\ncurve = SubResource(\"Curve2D_sd1kw\")\nscript = ExtResource(\"18_m2fcq\")\nis_air = true\nplayer_id = 7\n\n[node name=\"CameraOriginContainer\" type=\"Node2D\" parent=\"World\"]\n\n[node name=\"CameraOrigin0\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(900, -1300)\n\n[node name=\"CameraOrigin1\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(4000, 400)\nplayer_id = 1\n\n[node name=\"CameraOrigin2\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(3957, 4454)\nplayer_id = 2\n\n[node name=\"CameraOrigin3\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(817, 5984)\nplayer_id = 3\n\n[node name=\"CameraOrigin4\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(-7345, 6149)\nplayer_id = 4\n\n[node name=\"CameraOrigin5\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(-10235, 4538)\nplayer_id = 5\n\n[node name=\"CameraOrigin6\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(-10061, 638)\nplayer_id = 6\n\n[node name=\"CameraOrigin7\" parent=\"World/CameraOriginContainer\" instance=ExtResource(\"19_icnp7\")]\nposition = Vector2(-7166, -1087)\nplayer_id = 7\n\n[node name=\"ObjectContainer\" type=\"Node2D\" parent=\"World\"]\ny_sort_enabled = true\n\n[node name=\"EffectsContainer\" type=\"Node2D\" parent=\"World\"]\nscript = ExtResource(\"20_rnpn6\")\n\n[node name=\"VampiricAura\" parent=\"World/EffectsContainer\" instance=ExtResource(\"21_5ytv3\")]\nmodulate = Color(0.341176, 0.72549, 0.992157, 0.901961)\nz_index = 9\nposition = Vector2(-3200, 2560)\nscale = Vector2(6, 3)\nautoplay = \"default\"\nframe_progress = 0.0\n\n[node name=\"FloatingTextContainer\" type=\"Node2D\" parent=\"World\"]\nz_index = 1000\n\n[node name=\"Camera2D\" type=\"Camera2D\" parent=\"World\"]\nz_index = 1000\nposition = Vector2(2.08165e-12, 2.08165e-12)\nscale = Vector2(0.31481, 0.5)\nlimit_smoothed = true\neditor_draw_limits = true\neditor_draw_drag_margin = true\n\n[node name=\"TowerPreview\" parent=\"World\" node_paths=PackedStringArray(\"_build_space\") instance=ExtResource(\"22_53ta1\")]\nvisible = false\nz_index = 100\n_build_space = NodePath(\"../../Gameplay/BuildSpace\")\n\n[node name=\"RangeChecker\" parent=\"World\" node_paths=PackedStringArray(\"_build_space\") instance=ExtResource(\"22_53ta1\")]\nvisible = false\nmodulate = Color(1, 1, 1, 0.784314)\nz_index = 100\n_build_space = NodePath(\"../../Gameplay/BuildSpace\")\n\n[node name=\"UI\" type=\"CanvasLayer\" parent=\".\"]\n\n[node name=\"DesaturationFilter\" type=\"ColorRect\" parent=\"UI\"]\nmaterial = SubResource(\"ShaderMaterial_cij5r\")\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_filter = 2\n\n[node name=\"VignetteFilter\" type=\"ColorRect\" parent=\"UI\"]\nmaterial = SubResource(\"ShaderMaterial_6fevd\")\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_filter = 2\n\n[node name=\"HUD\" parent=\"UI\" instance=ExtResource(\"25_m068l\")]\nunique_name_in_owner = true\nprocess_mode = 1\nsize_flags_horizontal = 1\nmouse_filter = 2\n\n[node name=\"ShadowBelowBuilderMenu\" type=\"ColorRect\" parent=\"UI\"]\nvisible = false\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_force_pass_scroll_events = false\ncolor = Color(0, 0, 0, 0.392157)\n\n[node name=\"BuilderMenu\" parent=\"UI\" instance=ExtResource(\"26_2bi2s\")]\nvisible = false\noffset_left = -350.0\noffset_top = -300.0\noffset_right = 350.0\noffset_bottom = 300.0\n\n[node name=\"PauseShadowRect\" type=\"ColorRect\" parent=\"UI\"]\nvisible = false\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ncolor = Color(0, 0, 0, 0.392157)\n\n[node name=\"ShadowAboveBuilderMenu\" type=\"ColorRect\" parent=\"UI\"]\nvisible = false\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_force_pass_scroll_events = false\ncolor = Color(0, 0, 0, 0.392157)\n\n[node name=\"GameMenu\" parent=\"UI\" instance=ExtResource(\"26_xukvx\")]\nvisible = false\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -121.5\noffset_top = -192.5\noffset_right = 121.5\noffset_bottom = 192.5\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"UI\"]\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -20.0\noffset_top = -20.0\noffset_right = 20.0\noffset_bottom = 20.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"TutorialMenu\" parent=\"UI/VBoxContainer\" instance=ExtResource(\"27_vroom\")]\nprocess_mode = 3\nvisible = false\nlayout_mode = 2\n\n[connection signal=\"timeout\" from=\"Gameplay/GameStartTimer\" to=\".\" method=\"_on_game_start_timer_timeout\"]\n[connection signal=\"received_first_timeslot\" from=\"Gameplay/GameClient\" to=\".\" method=\"_on_game_client_received_first_timeslot\"]\n[connection signal=\"tutorial_triggered\" from=\"Gameplay/TutorialController\" to=\".\" method=\"_on_tutorial_controller_tutorial_triggered\"]\n[connection signal=\"finished\" from=\"UI/BuilderMenu\" to=\".\" method=\"_on_builder_menu_finished\"]\n[connection signal=\"continue_pressed\" from=\"UI/GameMenu\" to=\".\" method=\"_on_game_menu_continue_pressed\"]\n[connection signal=\"quit_pressed\" from=\"UI/GameMenu\" to=\".\" method=\"_on_game_menu_quit_pressed\"]\n[connection signal=\"hidden\" from=\"UI/VBoxContainer/TutorialMenu\" to=\".\" method=\"_on_tutorial_menu_hidden\"]\n"
  },
  {
    "path": "src/game_scene/game_time.gd",
    "content": "class_name GameTime extends Node\n\n\n# Counts game time. You can access this globally via Utils.\n\n\nvar _current_game_time: float = 0.0\nvar _enabled: bool = false\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc update(delta: float):\n\tif !_enabled:\n\t\treturn\n\n\t_current_game_time += delta\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_enabled(enabled: bool):\n\t_enabled = enabled\n\n\n# Returns time in seconds since the game started. Starts\n# counting after first wave begins. Doesn't count time spent\n# in pause menu.\nfunc get_time() -> float:\n\treturn _current_game_time\n"
  },
  {
    "path": "src/game_scene/horadric_cube.gd",
    "content": "class_name HoradricCube\n\n\n# NOTE: implements transmutation of items. The UI for\n# horadric cube is located in ItemStashMenu scene. Items are\n# stored inside ItemContainer which is child of GameScene.\n# \n# Tests for some horadric functions can be found in\n# TestHoradricTool.gd\n\n\n# NOTE: these values must match the id's in\n# recipe_properties.csv\nenum Recipe {\n\tNONE = 0,\n\tREBREW = 1,\n\tDISTILL = 2,\n\tREASSEMBLE = 3,\n\tPERFECT = 4,\n\tLIQUEFY = 5,\n\tPRECIPITATE = 6,\n\tIMBUE = 7,\n}\n\n\nconst CAPACITY: int = 5\nconst LEVEL_MOD_UNLUCKY: int = -9\nconst LEVEL_MOD_NORMAL: int = 0\nconst LEVEL_MOD_LUCKY: int = 7\nconst LEVEL_MOD_SUPER_LUCKY: int = 18\n\nconst _bonus_mod_chance_map: Dictionary = {\n\tLEVEL_MOD_UNLUCKY: 20,\n\tLEVEL_MOD_NORMAL: 50,\n\tLEVEL_MOD_LUCKY: 20,\n\tLEVEL_MOD_SUPER_LUCKY: 10\n}\n\n\n#########################\n###       Public      ###\n#########################\n\nstatic func has_recipe_ingredients(recipe: Recipe, item_list: Array[Item]) -> bool:\n\treturn !get_item_list_for_autofill(recipe, item_list).is_empty()\n\n\nstatic func can_transmute(player: Player, item_list: Array[Item]) -> bool:\n\tvar current_recipe: Recipe = HoradricCube.get_current_recipe(player, item_list)\n\tvar recipe_is_valid: bool = current_recipe != Recipe.NONE\n\n\treturn recipe_is_valid\n\n\n# Returns list of filtered items from the provided item_list,\n# which can be used for a recipe. Prioritizes items with\n# lowest rarity and level. Returns empty list if autofill\n# can't be performed.\nstatic func get_item_list_for_autofill(recipe: Recipe, item_list: Array[Item]) -> Array[Item]:\n\tvar current_rarity: Rarity.enm = Rarity.enm.COMMON\n\n\twhile current_rarity <= Rarity.enm.UNIQUE:\n\t\tvar result_list: Array[Item] = HoradricCube.get_item_list_for_autofill_for_rarity(recipe, item_list, current_rarity)\n\n\t\tif !result_list.is_empty():\n\t\t\treturn result_list\n\t\t\n\t\tcurrent_rarity = (current_rarity + 1) as Rarity.enm\n\n\treturn []\n\n\nstatic func get_item_list_for_autofill_for_rarity(recipe: Recipe, item_list: Array[Item], rarity: Rarity.enm) -> Array[Item]:\n\tvar rarity_change_from_recipe: int = RecipeProperties.get_rarity_change(recipe)\n\tvar result_rarity: int = rarity + rarity_change_from_recipe\n\tvar result_rarity_is_valid: bool = Rarity.enm.COMMON <= result_rarity && result_rarity <= Rarity.enm.UNIQUE\n\n\tif !result_rarity_is_valid:\n\t\treturn []\n\n# \tFilter rarities\n\titem_list = item_list.filter(\n\t\tfunc(item: Item) -> bool:\n\t\t\tvar item_rarity: Rarity.enm = item.get_rarity()\n\t\t\tvar rarity_match: bool = item_rarity == rarity\n\n\t\t\treturn rarity_match\n\t)\n\n# \tFilter out locked items\n\titem_list = item_list.filter(\n\t\tfunc(item: Item) -> bool:\n\t\t\tvar item_is_locked: bool = item.get_horadric_lock_is_enabled()\n\t\t\tvar item_can_be_autofilled: bool = !item_is_locked\n\n\t\t\treturn item_can_be_autofilled\n\t)\n\n# \tSort by level to prioritize lower level items first\n\titem_list.sort_custom(func(a, b): return a.get_required_wave_level() < b.get_required_wave_level())\n\n\tvar result_list: Array[Item] = []\n\n\tvar permanent_count: int = RecipeProperties.get_permanent_count(recipe)\n\tvar usable_count: int = RecipeProperties.get_usable_count(recipe)\n\tvar ingredient_list: Array = [\n\t\t[[ItemType.enm.REGULAR], permanent_count],\n\t\t[[ItemType.enm.OIL, ItemType.enm.CONSUMABLE], usable_count],\n\t]\n\n\tfor ingredient in ingredient_list:\n\t\tvar item_type_list: Array = ingredient[0]\n\t\tvar required_count: int = ingredient[1]\n\n\t\tvar sub_list: Array[Item] = item_list.filter(\n\t\t\tfunc(item: Item) -> bool:\n\t\t\t\tvar item_type: ItemType.enm = item.get_item_type()\n\t\t\t\tvar item_type_match: bool = item_type_list.has(item_type)\n\n\t\t\t\treturn item_type_match\n\t\t)\n\n\t\tvar item_count_is_enough: bool = sub_list.size() >= required_count\n\n\t\tif item_count_is_enough:\n\t\t\tsub_list.resize(required_count)\n\t\t\tresult_list.append_array(sub_list)\n\t\telse:\n\t\t\treturn []\n\n\treturn result_list\n\n\n# Returns recipe which matches the given item list. Do this\n# by getting an autofill list and checking if autofill list\n# is equal to input list.\nstatic func get_current_recipe(player: Player, item_list: Array[Item]) -> Recipe:\n\tif item_list.is_empty():\n\t\treturn Recipe.NONE\n\n\tvar item_id_list: Array[int] = Utils.item_list_to_item_id_list(item_list)\n\n\tvar recipe_list: Array = RecipeProperties.get_id_list()\n\n\tvar builder: Builder = player.get_builder()\n\tvar builder_id: int = builder.get_id()\n\tvar backpacked_builder_is_selected: bool = builder_id == BuilderProperties.BACKPACKER_BUILDER_ID\n\n\tfor recipe in recipe_list:\n\t\tvar recipe_unlocked_by_backpacker: bool = RecipeProperties.get_unlocked_by_backpacker(recipe)\n\t\tvar recipe_is_locked: bool = recipe_unlocked_by_backpacker && !backpacked_builder_is_selected\n\n\t\tif recipe_is_locked:\n\t\t\tcontinue\n\n\t\tvar autofill_item_list: Array[Item] = HoradricCube.get_item_list_for_autofill(recipe, item_list)\n\t\tvar autofill_id_list: Array[int] = Utils.item_list_to_item_id_list(autofill_item_list)\n\n\t\tvar recipe_matches: bool = item_id_list == autofill_id_list\n\n\t\tif recipe_matches:\n\t\t\treturn recipe\n\t\n\treturn Recipe.NONE\n\n\nstatic func get_result_item_for_recipe(player: Player, recipe: Recipe, item_list: Array[Item]) -> Array[int]:\n\tvar rarity_change_from_recipe: int = RecipeProperties.get_rarity_change(recipe)\n\tvar ingredient_rarity: Rarity.enm = HoradricCube._get_ingredient_rarity(item_list)\n\tvar result_rarity: Rarity.enm = (ingredient_rarity + rarity_change_from_recipe) as Rarity.enm\n\tvar result_item_type: Array[ItemType.enm] = RecipeProperties.get_result_item_type(recipe)\n\tvar avg_ingredient_level: int = HoradricCube._get_average_ingredient_level(item_list)\n\tvar random_bonus_mod: int = HoradricCube._get_random_bonus_mod()\n\tvar lvl_min: int = avg_ingredient_level + RecipeProperties.get_lvl_bonus_min(recipe) + random_bonus_mod\t\n\tvar lvl_max: int = avg_ingredient_level + RecipeProperties.get_lvl_bonus_max(recipe) + random_bonus_mod\n\n#\tNOTE: for PRECIPITATE recipe need to pick completely\n#\trandom level\n\tif recipe == Recipe.PRECIPITATE:\n\t\tlvl_min = 0\n\t\tlvl_max = 100000\n\n\tvar recipe_is_oil_or_consumable: bool = result_item_type.has(ItemType.enm.OIL) && result_item_type.has(ItemType.enm.CONSUMABLE)\n\tvar recipe_is_regular: bool = result_item_type.has(ItemType.enm.REGULAR)\n\n\tvar result_item_list: Array[int] = []\n\t\n\tvar result_count: int = RecipeProperties.get_result_count(recipe)\n\n\tfor i in range(0, result_count):\n\t\tif recipe_is_oil_or_consumable:\n\t\t\tvar result_item: int = HoradricCube._get_transmuted_oil_or_consumable(item_list, result_rarity)\n\t\t\tresult_item_list.append(result_item)\n\t\telif recipe_is_regular:\n\t\t\tvar result_item: int = HoradricCube._get_transmuted_item(item_list, result_rarity, lvl_min, lvl_max)\n\t\t\tresult_item_list.append(result_item)\n\t\n\t# luck only influences regular recipes and specifically not PRECIPITATE\n\tif recipe_is_regular and recipe != Recipe.PRECIPITATE:\n\t\tvar luck_message: String\n\t\tmatch random_bonus_mod:\n\t\t\tLEVEL_MOD_UNLUCKY: luck_message = Utils.tr(\"MESSAGE_TRANSMUTE_UNLUCKY\").format({BONUS_LEVELS = random_bonus_mod})\n\t\t\tLEVEL_MOD_NORMAL: luck_message = \"\"\n\t\t\tLEVEL_MOD_LUCKY: luck_message =  Utils.tr(\"MESSAGE_TRANSMUTE_LUCKY\").format({BONUS_LEVELS = random_bonus_mod})\n\t\t\tLEVEL_MOD_SUPER_LUCKY: luck_message = Utils.tr(\"MESSAGE_TRANSMUTE_SUPER_LUCKY\").format({BONUS_LEVELS = random_bonus_mod})\n\n\t\tif !luck_message.is_empty():\n\t\t\tMessages.add_normal(player, luck_message)\n\n\treturn result_item_list\n\n\n#########################\n###      Private      ###\n#########################\n\nstatic func _get_transmuted_oil_or_consumable(item_list: Array[Item], rarity: Rarity.enm) -> int:\n\tvar oil_list: Array = ItemDropCalc.get_oil_and_consumables_list(rarity)\n\n# \tRemove ingredients from item pool so that trasmute result is different from ingredients\n\tvar ingredient_list: Array[int] = Utils.item_list_to_item_id_list(item_list)\n\tfor ingredient in ingredient_list:\n\t\toil_list.erase(ingredient)\n\n\tif oil_list.is_empty():\n\t\tpush_error(\"Possible result pool for transmuting oils is empty. This shouldn't happen.\")\n\n\t\treturn 0\n\n\tvar random_oil: int = Utils.pick_random(Globals.synced_rng, oil_list)\n\n\treturn random_oil\n\n\nstatic func _get_transmuted_item(ingredient_item_list: Array[Item], rarity: Rarity.enm, lvl_min: int, lvl_max: int) -> int:\n\tvar current_lvl_min: int = lvl_min\n\tvar item_list: Array[int] = []\n\tvar loop_count: int = 0\n\n#\tIt's possible for random item pool to be empty if\n#\tlevel of ingredients is too high, in this case,\n#\tlower the lower lvl bound to make the pool not empty\n\twhile item_list.is_empty():\n\t\titem_list = ItemDropCalc.get_item_list_bounded(rarity, current_lvl_min, lvl_max)\n\n# \t\tRemove ingredients from item pool so that transmute result is different from ingredients\n\t\tvar ingredient_list: Array[int] = Utils.item_list_to_item_id_list(ingredient_item_list)\n\t\tfor ingredient in ingredient_list:\n\t\t\titem_list.erase(ingredient)\n\n\t\tcurrent_lvl_min -= 10\n\n\t\tloop_count += 1\n\n\t\tif loop_count > 10:\n\t\t\titem_list = []\n\n\t\t\tbreak\n\n\tif item_list.is_empty():\n\t\tpush_error(\"Possible result pool for transmuting items is empty. This shouldn't happen.\")\n\n\t\treturn 0\n\n\tvar random_item: int = Utils.pick_random(Globals.synced_rng, item_list)\n\t\n\treturn random_item\n\n\nstatic func _get_ingredient_rarity(item_list: Array[Item]) -> Rarity.enm:\n\tif item_list.is_empty():\n\t\treturn Rarity.enm.COMMON\n\n\tvar first_item: Item = item_list[0]\n\tvar rarity: Rarity.enm = first_item.get_rarity()\n\n\treturn rarity\n\n\n# NOTE: only check level of permanent items. Skip oils and\n# consumables. This is needed because Imbue recipe uses a\n# mix of permanent items and oils as ingredients.\nstatic func _get_average_ingredient_level(item_list: Array[Item]) -> int:\n\tif item_list.is_empty():\n\t\treturn 0\n\n\tvar permanent_item_list: Array[Item] = item_list.filter(\n\t\tfunc(item: Item) -> bool:\n\t\t\tvar item_id: int = item.get_id()\n\t\t\tvar item_type: ItemType.enm = ItemProperties.get_type(item_id)\n\t\t\tvar item_is_permanent: bool = item_type == ItemType.enm.REGULAR\n\n\t\t\treturn item_is_permanent\n\t)\n\n\tvar sum: float = 0.0\n\tfor item in permanent_item_list:\n\t\tvar item_id: int = item.get_id()\n\t\tvar level: int = ItemProperties.get_required_wave_level(item_id)\n\t\tsum += level\n\n\tvar item_count: int = permanent_item_list.size()\n\t\n\tvar average_level: int = floori(Utils.divide_safe(sum, item_count, 0))\n\n\treturn average_level\n\n\nstatic func _get_random_bonus_mod() -> int:\n\tvar bonus_mod: int = Utils.random_weighted_pick(Globals.synced_rng, _bonus_mod_chance_map)\n\n\treturn bonus_mod\n"
  },
  {
    "path": "src/game_scene/manual_timer.gd",
    "content": "class_name ManualTimer extends Node\n\n# ManualTimer must be used instead of native Timer for\n# everything except UI. ManualTimer ensures multiplayer\n# determinism because it is updated inside the game client\n# tick. ManualTimer has the same API as native Timer.\n\n\nsignal timeout()\n\n# UID system for deterministic sorting in multiplayer\nstatic var _uid_max: int = 1\nvar _uid: int = 0\n\n# NOTE: need all of these getsets to have same API as native\n# Timer\nvar time_left: float = 0.0: get = get_time_left\n@export var wait_time: float = 1.0: get = get_wait_time, set = set_wait_time\n@export var one_shot: bool = false: get = is_one_shot, set = set_one_shot\n@export var autostart: bool = false: get = has_autostart, set = set_autostart\nvar _stopped: bool = true\nvar paused: bool = false: get = is_paused, set = set_paused\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_uid = _uid_max\n\t_uid_max += 1\n\n\tadd_to_group(\"manual_timers\")\n\n\tif autostart:\n\t\tstart()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_autostart(value: bool):\n\tautostart = value\n\n\nfunc has_autostart() -> bool:\n\treturn autostart\n\n\nfunc set_wait_time(value: float):\n\twait_time = value\n\n\nfunc get_wait_time() -> float:\n\treturn wait_time\n\n\nfunc set_one_shot(value: bool):\n\tone_shot = value\n\n\nfunc is_one_shot() -> bool:\n\treturn one_shot\n\n\nfunc set_paused(value: bool):\n\tpaused = value\n\n\nfunc is_paused() -> bool:\n\treturn paused\n\n\nfunc start(new_wait_time: float = wait_time):\n\twait_time = new_wait_time\n\ttime_left = new_wait_time\n\t_stopped = false\n\n\nfunc stop():\n\ttime_left = wait_time\n\t_stopped = true\n\n\nfunc update(delta: float):\n\tif _stopped || paused:\n\t\treturn\n\n\ttime_left -= delta\n\n#\tNOTE: need to use is_zero_approx() to handle floats\n#\tbeing off from 0 by a small amount\n\tif is_zero_approx(time_left):\n\t\ttime_left = 0\n\t\n\tvar reached_timeout: bool = time_left <= 0 \n\t\n\tif reached_timeout:\n\t\tif one_shot:\n\t\t\t_stopped = true\n\t\telse:\n\t\t\ttime_left = wait_time\n\n\t\ttimeout.emit()\n\n\nfunc is_stopped() -> bool:\n\treturn _stopped\n\n\nfunc get_time_left() -> float:\n\treturn time_left\n\n\nfunc get_uid() -> int:\n\treturn _uid\n"
  },
  {
    "path": "src/game_scene/mouse_state.gd",
    "content": "class_name MouseState extends Node\n\n# Central storage for current mouse state. Used for actions\n# which use the mouse and need to disable other actions\n# while the action is in progress.\n\n\nenum enm {\n\tNONE,\n\tBUILD_TOWER,\n\tMOVE_ITEM,\n\tSELECT_TARGET_FOR_CAST,\n\tSELECT_POINT_FOR_CAST,\n}\n\nvar _current_state: MouseState.enm\n\n\nfunc reset():\n\t_current_state = MouseState.enm.NONE\n\n\nfunc set_state(state: MouseState.enm):\n\t_current_state = state\n\n\nfunc get_state() -> MouseState.enm:\n\treturn _current_state\n"
  },
  {
    "path": "src/game_scene/move_item.gd",
    "content": "class_name MoveItem extends Node\n\n# Handles moving items between item stash, horadric stash\n# and tower inventories. Movement is started from various\n# sources in the UI via EventBus. Note that while an item is\n# being moved, it will be parented to this node.\n\nenum InstantMoveType {\n\tNONE,\n\tFROM_ANY_TO_ITEM_STASH,\n\tFROM_ANY_TO_TOWER,\n\tFROM_TOWER_TO_HORADRIC_CUBE,\n\tFROM_ITEM_STASH_TO_HORADRIC_CUBE,\n}\n\n\n# Container from which currently moved item came from. Item\n# will return to this container if the player cancels item\n# movement.\nvar _source_container: ItemContainer = null\nvar _moved_item: Item = null\n\n\n@export var _mouse_state: MouseState\n@export var _world: Node2D\n@export var _game_client: GameClient\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tEventBus.player_clicked_in_item_container.connect(_on_player_clicked_in_item_container)\n\tEventBus.item_flew_to_item_stash.connect(_on_item_flew_to_item_stash)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc cancel():\n\tif !_move_in_progress():\n\t\treturn\n\n\t_end_move_process()\n\n\n# If player started moving an item and then clicked on\n# nothing, remove the item from source and make it fly back\n# to item stash.\nfunc process_click_on_nothing():\n\tif !_move_in_progress():\n\t\treturn\n\t\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar item_uid: int = _moved_item.get_uid()\n\tvar drop_pos: Vector2 = _world.get_global_mouse_position()\n\tvar src_container_uid: int = _source_container.get_uid()\n\n\tvar verify_ok: bool = ActionDropItem.verify(local_player, _moved_item, _source_container)\n\tif !verify_ok:\n\t\t_end_move_process()\n\t\t\n\t\treturn false\n\n\t_end_move_process()\n\n\tvar action: Action = ActionDropItem.make(item_uid, drop_pos, src_container_uid)\n\t_game_client.add_action(action)\n\t\n\tSFX.play_sfx_random_pitch(SfxPaths.DROP_ITEM)\n\n\nfunc process_click_on_tower(tower: Tower):\n\tvar container: ItemContainer = tower.get_item_container()\n\t_item_container_was_clicked(container)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _add_move_action(item: Item, src_item_container: ItemContainer, dest_item_container: ItemContainer, clicked_index: int = -1) -> bool:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t\n\tvar verify_ok: bool = ActionMoveItem.verify(local_player, item, src_item_container, dest_item_container, clicked_index)\n\tif !verify_ok:\n\t\treturn false\n\n\tvar item_uid: int = item.get_uid()\n\tvar src_container_uid: int = src_item_container.get_uid()\n\tvar dest_container_uid: int = dest_item_container.get_uid()\n\n\tSFX.play_sfx_random_pitch(SfxPaths.DROP_ITEM)\n\n\tvar action: Action = ActionMoveItem.make(item_uid, src_container_uid, dest_container_uid, clicked_index)\n\t_game_client.add_action(action)\n\n\treturn true\n\n\nfunc _add_swap_action(item_src: Item, item_dest: Item, src_item_container: ItemContainer, dest_item_container: ItemContainer) -> bool:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\t\n\tvar verify_ok: bool = ActionSwapItems.verify(local_player, item_src, item_dest, src_item_container, dest_item_container)\n\tif !verify_ok:\n\t\treturn false\n\n\tvar item_uid_src: int = item_src.get_uid()\n\tvar item_uid_dest: int = item_dest.get_uid()\n\tvar src_container_uid: int = src_item_container.get_uid()\n\tvar dest_container_uid: int = dest_item_container.get_uid()\n\n\tSFX.play_sfx_random_pitch(SfxPaths.DROP_ITEM)\n\n\tvar action: Action = ActionSwapItems.make(item_uid_src, item_uid_dest, src_container_uid, dest_container_uid)\n\t_game_client.add_action(action)\n\n\treturn true\n\n\nfunc _get_local_item_stash() -> ItemContainer:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_item_stash: ItemContainer = local_player.get_item_stash()\n\n\treturn local_item_stash\n\n\nfunc _get_local_horadric_stash() -> ItemContainer:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\n\treturn local_horadric_stash\n\n\nfunc _get_selected_tower_inventory() -> ItemContainer:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar selected_unit: Unit = local_player.get_selected_unit()\n\t\n\tif !selected_unit is Tower:\n\t\treturn null\n\n\tvar selected_tower: Tower = selected_unit as Tower\n\tvar tower_belongs_to_local_player: bool = selected_tower.belongs_to_local_player()\n\n\tif !tower_belongs_to_local_player:\n\t\treturn null\n\t\n\tvar tower_inventory: ItemContainer = selected_tower.get_item_container()\n\n\treturn tower_inventory\n\n\nfunc _move_in_progress() -> bool:\n\treturn _mouse_state.get_state() == MouseState.enm.MOVE_ITEM\n\n\n# When an item is clicked in an item container, two possible results:\n# \n# 1. If no item is currently being moved, then we start\n#    moving the clicked item.\n# \n# 2. If an item is currently being moved, then we stop\n#    moving the old item and start moving the clicked item.\n# \n# 3. If player shift clicked, item is instantly moved from\n#    current stash to item stash.\n# \n# 4. If player ctrl clicked, item is instantly moved:\n#\t- a) from item stash to selected tower\n# \t- b) from tower to horadric cube\nfunc _item_was_clicked_in_item_container(container: ItemContainer, clicked_item: Item):\n\tif !_can_start_moving():\n\t\treturn\n\t\n\tvar clicked_on_moved_item: bool = _moved_item == clicked_item\n\tif clicked_on_moved_item:\n\t\tcancel()\n\n\t\treturn\n\n#\tIf an item is currently getting moved, swap the items\n\tif _move_in_progress():\n\t\tvar success: bool = _add_swap_action(_moved_item, clicked_item, _source_container, container)\n\n\t\tif success:\n\t\t\t_end_move_process()\n\t\t\tget_viewport().set_input_as_handled()\n\n\t\treturn\n\n\tvar instant_move_type: InstantMoveType = _get_instant_move_type(container)\n\n\tif instant_move_type != InstantMoveType.NONE:\n\t\t_do_instant_move(container, clicked_item, instant_move_type)\n\t\t\n\t\treturn\n\t\n\t_moved_item = clicked_item\n\t_moved_item.tree_exited.connect(_on_moved_item_tree_exited)\n\t_source_container = container\n\t_mouse_state.set_state(MouseState.enm.MOVE_ITEM)\n\t\n\tvar item_cursor_icon: Texture2D = _get_item_cursor_icon(clicked_item)\n\tvar hotspot: Vector2 = item_cursor_icon.get_size() / 2\n\tInput.set_custom_mouse_cursor(item_cursor_icon, Input.CURSOR_ARROW, hotspot)\n\n\tSFX.play_sfx_random_pitch(SfxPaths.PICKUP_ITEM, 0.0)\n\n\tget_viewport().set_input_as_handled()\n\n\nfunc _get_instant_move_type(src_container: ItemContainer) -> InstantMoveType:\n\tvar shift_click: bool = Input.is_action_pressed(\"shift\")\n\tvar ctrl_click: bool = Input.is_action_pressed(\"ctrl\")\n\n\tvar item_stash: ItemContainer = _get_local_item_stash()\n\tvar tower_inventory: ItemContainer = _get_selected_tower_inventory()\n\t\n\tvar item_is_in_item_stash: bool = src_container == item_stash\n\tvar item_is_in_selected_tower: bool = src_container == tower_inventory\n\t\n\tvar instant_move_type: InstantMoveType = InstantMoveType.NONE\n\tif shift_click:\n\t\tif item_is_in_item_stash:\n\t\t\tinstant_move_type = InstantMoveType.FROM_ITEM_STASH_TO_HORADRIC_CUBE\n\t\telse:\n\t\t\tinstant_move_type = InstantMoveType.FROM_ANY_TO_ITEM_STASH\n\telif ctrl_click:\n\t\tif item_is_in_selected_tower:\n\t\t\tinstant_move_type = InstantMoveType.FROM_TOWER_TO_HORADRIC_CUBE\n\t\telif tower_inventory != null:\n\t\t\tinstant_move_type = InstantMoveType.FROM_ANY_TO_TOWER\n\n\treturn instant_move_type\n\n\nfunc _do_instant_move(src_container: ItemContainer, clicked_item: Item, instant_move_type: InstantMoveType):\n\tvar item_stash: ItemContainer = _get_local_item_stash()\n\tvar horadric_cube: ItemContainer = _get_local_horadric_stash()\n\tvar tower_inventory: ItemContainer = _get_selected_tower_inventory()\n\n\tvar dest_container: ItemContainer\n\tmatch instant_move_type:\n\t\tInstantMoveType.NONE: dest_container = null\n\t\tInstantMoveType.FROM_ANY_TO_ITEM_STASH: dest_container = item_stash\n\t\tInstantMoveType.FROM_ANY_TO_TOWER: dest_container = tower_inventory\n\t\tInstantMoveType.FROM_TOWER_TO_HORADRIC_CUBE: dest_container = horadric_cube\n\t\tInstantMoveType.FROM_ITEM_STASH_TO_HORADRIC_CUBE: dest_container = horadric_cube\n\n\tif dest_container == null:\n\t\treturn\n\t\n\t# instant move forces swap with the last slot if target_container is at capacity\n\tvar dest_has_space: bool = dest_container.can_add_item(clicked_item)\n\tvar dest_idx: int = -1\n\tif dest_has_space:\n\t\t_add_move_action(clicked_item, src_container, dest_container)\n\telse:\n\t\tvar dest_item: Item = dest_container.get_item_at_index(dest_idx)\n\t\t_add_swap_action(clicked_item, dest_item, src_container, dest_container)\n\n\n# When an item container is clicked, we add the currently\n# moved item to that container.\nfunc _item_container_was_clicked(container: ItemContainer, clicked_index: int = -1):\n\tif !_move_in_progress():\n\t\treturn\n\n\tvar success: bool = _add_move_action(_moved_item, _source_container, container, clicked_index)\n\n\tif success:\n\t\t_end_move_process()\n\t\tget_viewport().set_input_as_handled()\n\n\nfunc _end_move_process():\n\t_mouse_state.set_state(MouseState.enm.NONE)\n\n\tif _moved_item.tree_exited.is_connected(_on_moved_item_tree_exited):\n\t\t_moved_item.tree_exited.disconnect(_on_moved_item_tree_exited)\n\t_moved_item = null\n\t_source_container = null\n\n#\tNOTE: for some reason need to call this twice to reset\n#\tthe cursor. Calling it once causes the cursor to\n#\tdisappear.\n\tInput.set_custom_mouse_cursor(null)\n\tInput.set_custom_mouse_cursor(null)\n\n\n# NOTE: this function replicates the look of an ItemButton\n# by combining a background image with item icon. Note that\n# item icon needs to be resized to a smaller size and\n# centered on the background - in ItemButton this function\n# is done automatically by the theme.\nfunc _get_item_cursor_icon(item: Item) -> Texture2D:\n#\tNOTE: this value is an estimate to account for margins\n#\tin item buttons\n\tconst ITEM_ICON_SCALE: float = 0.85\n#\tNOTE: make cursor icon smaller than actual item button\n#\tto indicate that item is getting moved\n\tconst CURSOR_ICON_SCALE: float = 0.80\n\n\tvar viewport_scale: Vector2 = get_viewport().get_final_transform().get_scale()\n\tvar cursor_icon_size: Vector2i = Vector2i(Constants.ITEM_BUTTON_SIZE * viewport_scale * CURSOR_ICON_SCALE)\n\tvar item_icon_size: Vector2i = Vector2i(cursor_icon_size * ITEM_ICON_SCALE)\n\n\tvar rarity: Rarity.enm = item.get_rarity()\n\tvar background_texture: Texture2D\n\tmatch rarity:\n\t\tRarity.enm.COMMON: background_texture = load(\"res://resources/ui_textures/common_unit_button_hover.tres\")\n\t\tRarity.enm.UNCOMMON: background_texture = load(\"res://resources/ui_textures/uncommon_unit_button_hover.tres\")\n\t\tRarity.enm.RARE: background_texture = load(\"res://resources/ui_textures/rare_unit_button_hover.tres\")\n\t\tRarity.enm.UNIQUE: background_texture = load(\"res://resources/ui_textures/unique_unit_button_hover.tres\")\n\t\t\n\tvar background_image: Image = background_texture.get_image()\n\tbackground_image.resize(cursor_icon_size.x, cursor_icon_size.y)\n\t\n\tvar atlas_texture: Texture2D = ItemProperties.get_icon(item.get_id())\n\tvar image: Image = atlas_texture.get_image()\n\timage.resize(item_icon_size.x, item_icon_size.y)\n\t\n\tvar src_rect: Rect2i = Rect2i(Vector2i(0, 0), item_icon_size)\n\tvar dst: Vector2i = Vector2i((cursor_icon_size - item_icon_size) / 2)\n\tbackground_image.blend_rect(image, src_rect, dst)\n\n\tvar image_texture: ImageTexture = ImageTexture.create_from_image(background_image)\n\n\treturn image_texture\n\n\n# Can start moving an item if no other mouse action is\n# currently in progress or if we're currently moving an\n# item. Starting to move an item while another one is moved\n# already performs an item swap.\nfunc _can_start_moving() -> bool:\n\tvar can_start: bool = _mouse_state.get_state() == MouseState.enm.NONE || _mouse_state.get_state() == MouseState.enm.MOVE_ITEM\n\n\treturn can_start\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_player_clicked_in_item_container(item_container: ItemContainer, clicked_index: int):\n\tvar clicked_item: Item = item_container.get_item_at_index(clicked_index)\n\t\n\tif clicked_item != null:\n\t\t_item_was_clicked_in_item_container(item_container, clicked_item)\n\telse:\n\t\t_item_container_was_clicked(item_container, clicked_index)\n\n\n# NOTE: add item to item stash at position 0 so that if\n# there are many items and item stash is in scroll mode, the\n# player will see the item appear on the left side of the\n# item stash. Default scroll position for item stash\n# displays the left side.\nfunc _on_player_clicked_main_stash():\n\tvar local_item_stash: ItemContainer = _get_local_item_stash()\n\t_item_container_was_clicked(local_item_stash)\n\n\nfunc _on_item_flew_to_item_stash(item: Item):\n\tvar player: Player = item.get_player()\n\tvar item_stash: ItemContainer = player.get_item_stash()\n\titem_stash.add_item(item)\n\n\n# NOTE: this callback handles the case of needing to cancel\n# item move when item was removed from source container. For\n# example, if item was dropped from tower via code.\nfunc _on_moved_item_tree_exited():\n\tcancel()\n"
  },
  {
    "path": "src/game_scene/select_point_for_cast.gd",
    "content": "class_name SelectPointForCast extends Node\n\n# Implements selection of point when player is casting a\n# tower ability manually, and autocast is POINT type\n\nvar _autocast: Autocast = null\n\nconst _cast_cursor: Texture2D = preload(\"res://assets/misc/cast_cursor.png\")\n\n@export var _mouse_state: MouseState\n@export var _game_client: GameClient\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc finish(map: Map):\n\tif !_in_progress():\n\t\treturn\n\n\tvar target_pos_canvas: Vector2 = map.get_local_mouse_position()\n\n\tvar can_cast: bool = _autocast.can_cast()\n\tif !can_cast:\n\t\t_autocast.add_cast_error_message()\n\n\t\treturn\n\n\tvar target_pos: Vector2 = VectorUtils.canvas_to_wc3_2d(target_pos_canvas)\n\tvar in_range: bool = _autocast.target_pos_is_in_range(target_pos)\n\tif !in_range:\n\t\tUtils.add_ui_error(PlayerManager.get_local_player(), tr(\"MESSAGE_OUT_OF_RANGE\"))\n\n\t\treturn\n\t\n\tvar autocast_uid: int = _autocast.get_uid()\n\tvar target_uid: int = 0\n\tvar action: Action = ActionAutocast.make(autocast_uid, target_uid, target_pos)\n\t_game_client.add_action(action)\n\n\tcancel()\n\n\nfunc start(autocast: Autocast):\n\tvar can_start: bool = _mouse_state.get_state() == MouseState.enm.NONE || _mouse_state.get_state() == MouseState.enm.SELECT_POINT_FOR_CAST\n\tif !can_start:\n\t\treturn\n\n\tcancel()\n\t_autocast = autocast\n\t_mouse_state.set_state(MouseState.enm.SELECT_POINT_FOR_CAST)\n\tvar hotspot: Vector2 = _cast_cursor.get_size() / 2\n\tInput.set_custom_mouse_cursor(_cast_cursor, Input.CURSOR_ARROW, hotspot)\n\n\nfunc cancel():\n\tif !_in_progress():\n\t\treturn\n\n\t_mouse_state.set_state(MouseState.enm.NONE)\n\n\t_autocast = null\n\n#\tNOTE: for some reason need to call this twice to reset\n#\tthe cursor. Calling it once causes the cursor to\n#\tdisappear.\n\tInput.set_custom_mouse_cursor(null)\n\tInput.set_custom_mouse_cursor(null)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _in_progress() -> bool:\n\treturn _mouse_state.get_state() == MouseState.enm.SELECT_POINT_FOR_CAST\n"
  },
  {
    "path": "src/game_scene/select_target_for_cast.gd",
    "content": "class_name SelectTargetForCast extends Node\n\n# Implements selection of target when player is casting a\n# tower ability manually.\n\nvar _autocast: Autocast = null\n\nconst _cast_cursor: Texture2D = preload(\"res://assets/misc/cast_cursor.png\")\n\n@export var _mouse_state: MouseState\n@export var _game_client: GameClient\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc finish(hovered_unit: Unit):\n\tif !_in_progress():\n\t\treturn\n\n\tvar target: Unit = hovered_unit\n\n\tif target == null:\n\t\treturn\n\n\tvar target_is_ok: bool = _autocast.check_target_for_unit_autocast(target)\n\tvar target_error_message: String = _autocast.get_target_error_message(target)\n\n\tif !target_is_ok:\n\t\tUtils.add_ui_error(PlayerManager.get_local_player(), target_error_message)\n\n\t\treturn\n\t\t\n\tvar can_cast: bool = _autocast.can_cast()\n\n\tif !can_cast:\n\t\t_autocast.add_cast_error_message()\n\n\t\treturn\n\n\tvar autocast_uid: int = _autocast.get_uid()\n\tvar target_uid: int = target.get_uid()\n\tvar target_pos: Vector2 = Vector2.ZERO\n\tvar action: Action = ActionAutocast.make(autocast_uid, target_uid, target_pos)\n\t_game_client.add_action(action)\n\n\tcancel()\n\n\nfunc start(autocast: Autocast):\n\tvar can_start: bool = _mouse_state.get_state() == MouseState.enm.NONE || _mouse_state.get_state() == MouseState.enm.SELECT_TARGET_FOR_CAST\n\tif !can_start:\n\t\treturn\n\n\tcancel()\n\t_autocast = autocast\n\t_mouse_state.set_state(MouseState.enm.SELECT_TARGET_FOR_CAST)\n\tvar hotspot: Vector2 = _cast_cursor.get_size() / 2\n\tInput.set_custom_mouse_cursor(_cast_cursor, Input.CURSOR_ARROW, hotspot)\n\n\nfunc cancel():\n\tif !_in_progress():\n\t\treturn\n\n\t_mouse_state.set_state(MouseState.enm.NONE)\n\n\t_autocast = null\n\n#\tNOTE: for some reason need to call this twice to reset\n#\tthe cursor. Calling it once causes the cursor to\n#\tdisappear.\n\tInput.set_custom_mouse_cursor(null)\n\tInput.set_custom_mouse_cursor(null)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _in_progress() -> bool:\n\treturn _mouse_state.get_state() == MouseState.enm.SELECT_TARGET_FOR_CAST\n"
  },
  {
    "path": "src/game_scene/select_unit.gd",
    "content": "class_name SelectUnit extends Node\n\n# Implements logic for hovering and selecting units. Needed\n# because only one unit may be hovered or selected at a\n# time.\n\nsignal selected_unit_changed(prev_unit: Unit)\n\n\nvar _units_under_mouse_list: Array[Unit] = []\nvar _hovered_unit: Unit = null\nvar _selected_unit: Unit = null\n\n@export var _game_client: GameClient\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tEventBus.mouse_entered_unit.connect(_on_mouse_entered_unit)\n\tEventBus.mouse_exited_unit.connect(_on_mouse_exited_unit)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_selected_unit(new_selected_unit: Unit):\n\tvar old_selected_unit: Unit = _selected_unit\n\n\tif old_selected_unit != null:\n\t\told_selected_unit.set_selected(false)\n\t\told_selected_unit.tree_exited.disconnect(_on_selected_unit_tree_exited)\n\n\tif new_selected_unit != null:\n\t\tnew_selected_unit.set_selected(true)\n\n\t\tif !new_selected_unit.tree_exited.is_connected(_on_selected_unit_tree_exited):\n\t\t\tnew_selected_unit.tree_exited.connect(_on_selected_unit_tree_exited.bind(new_selected_unit))\n\n\t_selected_unit = new_selected_unit\n\tselected_unit_changed.emit(old_selected_unit)\n\n# \tNOTE: this part syncs selection in multiplayer\n\tvar unit_id: int\n\tif new_selected_unit != null:\n\t\tunit_id = new_selected_unit.get_uid()\n\telse:\n\t\tunit_id = -1\n\tvar action: Action = ActionSelectUnit.make(unit_id)\n\t_game_client.add_action(action)\n\n\nfunc get_selected_unit() -> Unit:\n\treturn _selected_unit\n\n\nfunc get_hovered_unit() -> Unit:\n\treturn _hovered_unit\n\n\nfunc update_hovered_unit():\n\tvar old_hovered_unit: Unit = _hovered_unit\n\n\tif old_hovered_unit != null:\n\t\told_hovered_unit.set_hovered(false)\n\t\t_hovered_unit = null\n\n#\tNOTE: sort list by y position so that if units overlap,\n#\tthe one in the front (higher y) gets picked\n\t_units_under_mouse_list.sort_custom(func(a, b): return a.get_position_canvas().y > b.get_position_canvas().y)\n\n\tif _units_under_mouse_list.size() > 0:\n\t\tvar new_hovered_unit = _units_under_mouse_list[0]\n\t\tnew_hovered_unit.set_hovered(true)\n\t\t_hovered_unit = new_hovered_unit\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_mouse_entered_unit(unit: Unit):\n\t_units_under_mouse_list.append(unit)\n\tif !unit.tree_exited.is_connected(_on_hovered_unit_tree_exited):\n\t\tunit.tree_exited.connect(_on_hovered_unit_tree_exited.bind(unit))\n\tupdate_hovered_unit()\n\n\nfunc _on_mouse_exited_unit(unit: Unit):\n\t_units_under_mouse_list.erase(unit)\n\tif unit.tree_exited.is_connected(_on_hovered_unit_tree_exited):\n\t\tunit.tree_exited.disconnect(_on_hovered_unit_tree_exited)\n\tupdate_hovered_unit()\n\n\n# NOTE: Need this slot because \"mouse_exited\" signal doesn't\n# get emitted when units exit the tree because of\n# queue_free().\nfunc _on_selected_unit_tree_exited(unit: Unit):\n\tvar selected_unit_is_being_removed: bool = _selected_unit == unit\n\tif selected_unit_is_being_removed:\n\t\tset_selected_unit(null)\n\n\nfunc _on_hovered_unit_tree_exited(unit: Unit):\n\tif _units_under_mouse_list.has(unit):\n\t\t_units_under_mouse_list.erase(unit)\n\t\tupdate_hovered_unit()\n"
  },
  {
    "path": "src/game_scene/team_container.gd",
    "content": "class_name TeamContainer extends Node\n\n\nvar _team_map: Dictionary = {}\nvar _team_id_list: Array[int] = []\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc add_team(team: Team):\n\tvar team_id: int = team.get_id()\n\t_team_map[team_id] = team\n\t\n# \tNOTE: need to sort teams to ensure determinism in\n# \tmultiplayer\n\t_team_id_list.append(team_id)\n\t_team_id_list.sort()\n\tadd_child(team)\n\n\nfunc get_team(id: int) -> Team:\n\tif !_team_map.has(id):\n\t\tpush_error(\"Failed to find team for id \", id)\n\n\t\treturn null\n\n\tvar team: Team = _team_map[id]\n\n\treturn team\n\n\nfunc get_team_list() -> Array[Team]:\n\tvar team_list: Array[Team] = []\n\n\tfor team_id in _team_id_list:\n\t\tvar team: Team = _team_map[team_id]\n\t\tteam_list.append(team)\n\t\n\treturn team_list\n\n\nfunc get_team_id_list() -> Array[int]:\n\treturn _team_id_list.duplicate()\n"
  },
  {
    "path": "src/game_scene/tutorial_controller.gd",
    "content": "class_name TutorialController extends Node\n\n\n# Controls the flow of tutorials. Collects triggers and converts them into tutorials. Note that multiple tutorials can be queued at a time.\n\n\nsignal tutorial_triggered(tutorial_id: TutorialProperties.TutorialId)\n\n\nenum Trigger {\n\tPLAYER_STARTED_BUILD_MODE_GAME,\n\tPLAYER_STARTED_RANDOM_MODE_GAME,\n\tRESEARCH_ELEMENT,\n\tROLLED_TOWERS,\n\tBUILT_A_TOWER,\n\tFIRST_ITEM_DROP,\n\tPORTAL_DAMAGE,\n\tWAVE_1_FINISHED,\n\tWAVE_7_FINISHED,\n\tWAVE_10_FINISHED,\n\tWAVE_15_FINISHED,\n\tUNIT_LEVELED_UP,\n\t\n\tCOUNT,\n}\n\nvar _trigger_to_tutorial_list_map: Dictionary = {\n\tTrigger.PLAYER_STARTED_BUILD_MODE_GAME: [TutorialProperties.TutorialId.INTRO_FOR_BUILD_MODE],\n\tTrigger.PLAYER_STARTED_RANDOM_MODE_GAME: [TutorialProperties.TutorialId.INTRO_FOR_RANDOM_MODE, TutorialProperties.TutorialId.RESEARCH_ELEMENTS],\n\tTrigger.RESEARCH_ELEMENT: [TutorialProperties.TutorialId.ROLL_TOWERS],\n\tTrigger.ROLLED_TOWERS: [TutorialProperties.TutorialId.TOWER_STASH, TutorialProperties.TutorialId.BUILD_TOWER],\n\tTrigger.BUILT_A_TOWER: [TutorialProperties.TutorialId.RESOURCES, TutorialProperties.TutorialId.TOWER_INFO],\n\tTrigger.FIRST_ITEM_DROP: [TutorialProperties.TutorialId.ITEMS],\n\tTrigger.PORTAL_DAMAGE: [TutorialProperties.TutorialId.PORTAL_DAMAGE],\n\tTrigger.WAVE_1_FINISHED: [TutorialProperties.TutorialId.WAVE_1_FINISHED],\n\tTrigger.WAVE_7_FINISHED: [TutorialProperties.TutorialId.CHALLENGE_WAVE],\n\tTrigger.WAVE_10_FINISHED: [TutorialProperties.TutorialId.UPGRADING],\n\tTrigger.WAVE_15_FINISHED: [TutorialProperties.TutorialId.TRANSFORMING],\n\tTrigger.UNIT_LEVELED_UP: [TutorialProperties.TutorialId.TOWER_LEVELS],\n}\n\nvar _trigger_processed_map: Dictionary = {}\nvar _tutorial_queue: Array = []\nvar _tutorial_is_in_progress: bool = false\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tEventBus.finished_tutorial_section.connect(_on_finished_tutorial_section)\n\tEventBus.item_dropped.connect(_on_item_dropped)\n\tEventBus.portal_received_damage.connect(_on_portal_received_damage)\n\tEventBus.built_a_tower.connect(_on_built_a_tower)\n\tEventBus.unit_leveled_up.connect(_on_unit_leveled_up)\n\t\n\tfor trigger in range(0, Trigger.COUNT):\n\t\tvar trigger_is_mapped: bool = _trigger_to_tutorial_list_map.has(trigger)\n\t\t\n\t\tif !trigger_is_mapped:\n\t\t\tpush_error(\"Tutorial trigger is unmapped: %d\" % trigger)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\tlocal_player.selected_builder.connect(_on_local_player_selected_builder)\n\tlocal_player.element_level_changed.connect(_on_local_player_element_level_changed)\n\tlocal_player.rolled_starting_towers.connect(_on_local_player_rolled_towers)\n\tlocal_player.wave_finished.connect(_on_local_player_wave_finished)\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: triggers are processed only once and ignored after\n# that\nfunc _process_trigger(trigger: Trigger):\n\tvar trigger_already_processed: bool = _trigger_processed_map.has(trigger)\n\n\tif !trigger_already_processed:\n\t\t_trigger_processed_map[trigger] = true\n\t\t\n\t\tvar triggered_tutorial_list: Array = _trigger_to_tutorial_list_map[trigger]\n\t\t_tutorial_queue.append_array(triggered_tutorial_list)\n\t\t_process_tutorial_queue()\n\n\nfunc _process_tutorial_queue():\n\tif _tutorial_queue.is_empty() || _tutorial_is_in_progress:\n\t\treturn\n\t\n\tvar tutorial: int = _tutorial_queue.pop_front()\n\t_tutorial_is_in_progress = true\n\ttutorial_triggered.emit(tutorial)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\n# NOTE: some tutorials are followed up by other tutorials so process queue after tutorial is closed\nfunc _on_finished_tutorial_section():\n\t_tutorial_is_in_progress = false\n\t_process_tutorial_queue()\n\n\n# NOTE: this is the first trigger, where the tutorial starts\nfunc _on_local_player_selected_builder():\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\t\n\tif game_mode == GameMode.enm.BUILD:\n\t\t_process_trigger(Trigger.PLAYER_STARTED_BUILD_MODE_GAME)\n\telse:\n\t\t_process_trigger(Trigger.PLAYER_STARTED_RANDOM_MODE_GAME)\n\n\n\nfunc _on_local_player_element_level_changed():\n\t_process_trigger(Trigger.RESEARCH_ELEMENT)\n\n\nfunc _on_local_player_rolled_towers():\n\t_process_trigger(Trigger.ROLLED_TOWERS)\n\n\nfunc _on_item_dropped():\n\t_process_trigger(Trigger.FIRST_ITEM_DROP)\n\n\nfunc _on_portal_received_damage():\n\t_process_trigger(Trigger.PORTAL_DAMAGE)\n\n\nfunc _on_local_player_wave_finished(level: int):\n\tmatch level:\n\t\t1: _process_trigger(Trigger.WAVE_1_FINISHED)\n\t\t7: _process_trigger(Trigger.WAVE_7_FINISHED)\n\t\t10: _process_trigger(Trigger.WAVE_10_FINISHED)\n\t\t15: _process_trigger(Trigger.WAVE_15_FINISHED)\n\n\nfunc _on_built_a_tower():\n\t_process_trigger(Trigger.BUILT_A_TOWER)\n\n\nfunc _on_unit_leveled_up():\n\t_process_trigger(Trigger.UNIT_LEVELED_UP)\n"
  },
  {
    "path": "src/items/README.md",
    "content": "item_behaviors - contains scripts which define behaviors for individual items. These scripts will be attached to the main Item class during runtime.\n"
  },
  {
    "path": "src/items/item.gd",
    "content": "class_name Item\nextends Node\n\n\n# Item represents item when it's attached to a tower.\n# Implements application of item effects on tower.\n\nsignal charges_changed()\nsignal consumed()\nsignal horadric_lock_changed()\nsignal freshness_changed()\n\n\nconst FLY_DURATION: float = 1.0\nconst PRINT_SCRIPT_NOT_FOUND_ERROR: bool = false\nconst FRESHNESS_DURATION: float = 7.0\n\nvar user_int: int = 0\nvar user_int2: int = 0\nvar user_int3: int = 0\nvar user_real: float = 0.0\nvar user_real2: float = 0.0\nvar user_real3: float = 0.0\n\nvar _id: int = 0\nvar _carrier: Tower = null\nvar _charge_count: int = -1\nvar _visible: bool = true\nvar _uses_charges: bool = false\nvar _is_oil_and_was_applied_already: bool = false\nvar _horadric_lock_is_enabled: bool = false\nvar _is_fresh: bool = true\n\nvar _modifier: Modifier\nvar _autocast: Autocast = null\nvar _aura_carrier_bt: BuffType\nvar _triggers_bt: BuffType\nvar _triggers_buff: Buff = null\nvar _inherited_periodic_timers: Dictionary = {}\nvar _player: Player = null\nvar _item_behavior: ItemBehavior\n\nstatic var _uid_max: int = 1\nvar _uid: int = 0\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(id: int, player: Player):\n#\tNOTE: fix \"unused variable\" warning\n\t_is_oil_and_was_applied_already = _is_oil_and_was_applied_already\n\n\t_uid = _uid_max\n\tItem._uid_max += 1\n\tGroupManager.add(\"items\", self, get_uid())\n\n\t_id = id\n\t_player = player\n\n\t_modifier = ItemProperties.get_specials_modifier(_id)\n\n\tvar item_name: String = get_display_name()\n\n#\tNOTE: need to insert item id into bufftype names to make\n#\tthem unique. The uniqueness mechanism inside\n#\tBuffType._init() doesn't work here because script name\n#\tis always \"Item.gd\".\n\t_aura_carrier_bt = BuffType.new(\"item-%d-_aura_carrier_bt\" % _id, 0, 0, true, self)\n\t_aura_carrier_bt.set_buff_tooltip(\"DEBUG Aura carrier buff for item %s\" % item_name)\n\t_aura_carrier_bt.set_hidden()\n\t_aura_carrier_bt.disable_stacking_behavior()\n\t\n\t_triggers_bt = BuffType.new(\"item-%d-_triggers_bt\" % _id, 0, 0, true, self)\n\t_triggers_bt.set_buff_tooltip(\"DEBUG Triggers buff for item %s\" % item_name)\n\t_triggers_bt.set_hidden()\n\t_triggers_bt.disable_stacking_behavior()\n\n\n# NOTE: need to init item behavior inside _ready() because\n# some item scripts access the scene tree inside\n# ItemBehavior.on_create()\nfunc _ready():\n\t#\tNOTE: need to use Timer instead of ManualTimer here because this effect affects only visuals and shouldn't be affected by gamespeed. Otherwise, the freshness indicator would go away too fast when gamespeed is set to fast.\n\tvar freshness_timer: Timer = Timer.new()\n\tfreshness_timer.one_shot = true\n\tfreshness_timer.timeout.connect(_on_freshness_timer_timeout)\n\tadd_child(freshness_timer)\n\tfreshness_timer.start(FRESHNESS_DURATION)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_is_fresh(value: bool):\n\t_is_fresh = value\n\tfreshness_changed.emit()\n\n\nfunc get_is_fresh() -> bool:\n\treturn _is_fresh\n\n\nfunc toggle_horadric_lock():\n\t_horadric_lock_is_enabled = !_horadric_lock_is_enabled\n\thoradric_lock_changed.emit()\n\n\nfunc get_horadric_lock_is_enabled() -> bool:\n\treturn _horadric_lock_is_enabled\n\n\nfunc get_uid() -> int:\n\treturn _uid\n\n\nfunc add_aura(aura_id: int, object_with_buff_var: Object):\n\t_aura_carrier_bt.add_aura(aura_id, object_with_buff_var)\n\n\n# Consume item. Only applicable to items of consumable type.\nfunc consume():\n\t_item_behavior.on_consume()\n\n\tprint_verbose(\"Item was consumed. Removing item from game.\")\n\t\n\tconsumed.emit()\n\n\nfunc get_specials_tooltip_text() -> String:\n\tvar text: String = _modifier.get_tooltip_text()\n\n\treturn text\n\n\n# NOTE: SetItemVisible() in JASS\nfunc set_visible(visible: bool):\n\t_visible = visible\n\n\nfunc is_visible() -> bool:\n\treturn _visible\n\n\nfunc set_autocast(autocast: Autocast):\n\tautocast.set_item_owner(self)\n\t_autocast = autocast\n\tadd_child(autocast)\n\n\nfunc get_autocast() -> Autocast:\n\treturn _autocast\n\n\n# NOTE: item.onTowerDetails() in JASS\nfunc on_tower_details() -> MultiboardValues:\n\treturn _item_behavior.on_tower_details()\n\n\nfunc disable_autocast():\n\tif _autocast != null:\n\t\t_autocast.set_caster(null)\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: item.getItemType() in JASS\n# In JASS engine, getItemType() returns the id.\n# Note that in youtd2 engine, \"item type\" refers to the\n# ItemType enm, not the item id.\nfunc get_id() -> int:\n\treturn _id\n\n\n# NOTE: item.getCarrier() in JASS\nfunc get_carrier() -> Tower:\n\treturn _carrier\n\n\n# NOTE: Need to change name to get_player() because\n# Node.get_owner() is a built-in godot f-n\n# NOTE: item.getOwner() in JASS\nfunc get_player() -> Player:\n\treturn _player\n\n\nfunc belongs_to_local_player() -> bool:\n\tvar result: bool = _player == PlayerManager.get_local_player()\n\t\n\treturn result\n\n\nfunc get_display_name() -> String:\n\tvar display_name: String = ItemProperties.get_display_name(_id)\n\n\treturn display_name\n\n\nfunc get_rarity() -> Rarity.enm:\n\tvar rarity: Rarity.enm = ItemProperties.get_rarity(_id)\n\n\treturn rarity\n\n\nfunc get_item_type() -> ItemType.enm:\n\treturn ItemProperties.get_type(_id)\n\n\nfunc get_required_wave_level() -> int:\n\treturn ItemProperties.get_required_wave_level(_id)\n\n\nfunc is_consumable() -> bool:\n\treturn ItemProperties.is_consumable(_id)\n\n\n# Picks up an item from the ground and moves it to a tower.\n# Item must be in \"dropped\" state before this f-n is called.\n# Returns true if item was picked up successfully.\n# NOTE: item.pickup() in JASS\nfunc pickup(tower: Tower) -> bool:\n\tvar item_drop: ItemDrop = get_parent() as ItemDrop\n\tif item_drop == null:\n\t\tpush_error(\"Called pickup() on item which is not in ItemDrop!\")\n\n\t\treturn false\n\n\tvar is_oil: bool = ItemProperties.get_is_oil(get_id())\n\tvar can_add: bool = tower.have_item_space() || is_oil\n\n\tif !can_add:\n\t\treturn false\n\n\titem_drop.remove_child(self)\n\titem_drop.remove_from_game()\n\n\tvar tower_container: ItemContainer = tower.get_item_container()\n\ttower_container.add_item(self)\n\t\n\treturn true\n\n\n# Drops item from tower inventory onto the ground. This f-n\n# does nothing if item is currently not in tower inventory.\n# NOTE: item.drop() in JASS\nfunc drop():\n\tif _carrier == null:\n\t\treturn\n\n# \tNOTE: save drop_pos before removing because _carrier\n# \twill not be available after removal\n\tvar drop_pos: Vector3 = _carrier.get_position_wc3()\n\n\tvar carrier_container: ItemContainer = _carrier.get_item_container()\n\tcarrier_container.remove_item(self)\n\t\n\tvar item_drop: ItemDrop = ItemDrop.make(self, drop_pos)\n\tUtils.add_object_to_world(item_drop)\n\n\n# Item starts flying to the stash and will get added to\n# stash once the animation finishes. Does nothing if item is\n# not on the ground.\n# NOTE: item.flyToStash() in JASS\nfunc fly_to_stash(_mystery_float: float):\n\tvar parent_item_drop: ItemDrop = get_parent() as ItemDrop\n\tvar is_on_ground: bool = parent_item_drop != null\n\n\tif !is_on_ground:\n\t\treturn\n\n\tvar canvas_pos: Vector2 = parent_item_drop.get_screen_transform().get_origin()\n\tEventBus.item_started_flying_to_item_stash.emit(self, canvas_pos)\n\n#\tNOTE: fly duration has to be a constant value, doesn't\n#\tmatter if fly animation will finish earlier. This is to\n#\tprevent multiplayer desync.\n\tawait Utils.create_manual_timer(FLY_DURATION, self).timeout\n\n#\tAfter item is done flying, we can delete item drop\n\tparent_item_drop.remove_child(self)\n\tparent_item_drop.remove_from_game()\n\n\tEventBus.item_flew_to_item_stash.emit(self)\n\n\n# NOTE: this f-n only applies the effects. Use Item.pickup()\n# or Tower.add_item() to fully add an item to a tower.\nfunc _add_to_tower(tower: Tower):\n\t_carrier = tower\n\n# \tNOTE: call on_pick() after setting carrier so that it's\n# \tavailable inside on_pickup() implementations.\n\t_item_behavior.on_pickup()\n\n\t_carrier.add_modifier(_modifier)\n\n\tif _autocast != null:\n\t\t_autocast.set_caster(_carrier)\n\n\t_triggers_buff = _triggers_bt.apply_to_unit_permanent(_carrier, _carrier, 0)\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_timer_keys: Array = _inherited_periodic_timers.keys()\n\tsorted_timer_keys.sort()\n\tfor key in sorted_timer_keys:\n\t\tvar timer: ManualTimer = _inherited_periodic_timers[key]\n\t\ttimer.set_paused(false)\n\t_triggers_buff.inherit_periodic_timers(_inherited_periodic_timers)\n\t_aura_carrier_bt.apply_to_unit_permanent(_carrier, _carrier, 0)\n\n\n# NOTE: this f-n only removes the effects. Use Item.drop()\n# or Tower.remove_item() to fully remove an item from a\n# tower.\n# \n# NOTE: buffs applied by Item will be automatically removed\n# via Buff._on_buff_type_tree_exited(). This includes\n# _triggers_bt and _aura_carrier_bt.\n# \n# NOTE: the code for _inherited_periodic_timers is a hack to\n# preserve item cooldowns when item is removed from tower.\n# It works like this:\n# 1. When item is first added to a tower, it creates a\n#    \"triggers\" buff which creates timers for periodic\n#    events.\n# 2. When that item is removed from the tower, triggers buff\n#    is deleted but the timers are saved in the item\n#    instance.\n# 3. When the item is added back to a tower, the new\n#    triggers buff \"inherits\" timers from previous buff.\n# 4. Repeat.\n# \n# In other cases, buffs do not inherit timers.\nfunc _remove_from_tower():\n\tif _carrier == null:\n\t\treturn\n\n\t_item_behavior.on_drop()\n\n\t_carrier.remove_modifier(_modifier)\n\n\tif _autocast != null:\n\t\t_autocast.set_caster(null)\n\n\t_inherited_periodic_timers = _triggers_buff.get_periodic_timers()\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_timer_keys: Array = _inherited_periodic_timers.keys()\n\tsorted_timer_keys.sort()\n\tfor key in sorted_timer_keys:\n\t\tvar timer: ManualTimer = _inherited_periodic_timers[key]\n\t\ttimer.reparent(self)\n\t\ttimer.set_paused(true)\n\n\t_carrier = null\n\n\nfunc _on_freshness_timer_timeout():\n\tset_is_fresh(false)\n\n\nfunc _set_item_behavior(item_behavior: ItemBehavior):\n\t_item_behavior = item_behavior\n\t_item_behavior.init(self, _triggers_bt)\n\n\n#########################\n### Setters / Getters ###\n#########################\n\n# Sets the charge count that is displayed on the item icon.\n# NOTE: item.setCharges() in JASS\nfunc set_charges(new_count: int):\n\tvar old_count: int = _charge_count\n\tCombatLog.log_item_charge(self, old_count, new_count)\n\n\t_charge_count = new_count\n\t_uses_charges = true\n\tcharges_changed.emit()\n\n\n# NOTE: item.getCharges() in JASS\nfunc get_charges() -> int:\n\treturn _charge_count\n\n\n# Returns whether this item uses charges. Used to determine\n# whether to draw charges label.\nfunc uses_charges() -> bool:\n\treturn _uses_charges\n\n\n#########################\n###       Static      ###\n#########################\n\n# Creates item on the ground. Item is stored inside an\n# ItemDrop object until it's picked up by a tower or\n# moved to stash.\n# NOTE: Item.create() in JASS\nstatic func create(player: Player, item_id: int, position: Vector3) -> Item:\n\tif player == null:\n\t\tpush_error(\"Player is null\")\n\n\t\treturn null\n\n\tvar item: Item = Item.make(item_id, player)\n\tvar item_drop: ItemDrop = ItemDrop.make(item, position)\n\tUtils.add_object_to_world(item_drop)\n\n\treturn item\n\n\nstatic func make(id: int, player: Player) -> Item:\n\tif player == null:\n\t\tpush_error(\"Player is null\")\n\n\t\treturn null\n\t\n\tvar item_behavior_script_path: String = ItemProperties.get_script_path(id)\n\tvar item_behavior_script = load(item_behavior_script_path)\n\n\tif item_behavior_script == null:\n\t\treturn null\n\n\tvar item: Item = Item.new(id, player)\n\tvar item_behavior: ItemBehavior = item_behavior_script.new()\n\titem._set_item_behavior(item_behavior)\n\titem.add_child(item_behavior)\n\n\treturn item\n"
  },
  {
    "path": "src/items/item_behavior.gd",
    "content": "class_name ItemBehavior extends Node\n\n\n# ItemBehavior is used to implement behavior for a\n# particular item. Each item has it's own ItemBehavior\n# script which is attached to Item base class to create a\n# complete item.\n\n\nvar item: Item\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc init(item_arg: Item, triggers_buff_type: BuffType):\n\titem = item_arg\n\n\titem_init()\n\n#\tNOTE: Order is important here! Auras and autocasts must\n#\tbe loaded after calling item_init() because buffs are\n#\tsetup in item_init() and auras/autocasts rely on buffs.\n\tvar item_id: int = item.get_id()\n\tvar aura_id_list: Array = ItemProperties.get_aura_id_list(item_id)\n\tfor aura_id in aura_id_list:\n\t\titem.add_aura(aura_id, self)\n\n\tvar autocast_id_list: Array = ItemProperties.get_autocast_id_list(item_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast: Autocast = Autocast.make(autocast_id, self)\n\t\titem.set_autocast(autocast)\n\n\tload_triggers(triggers_buff_type)\n\ton_create()\n\n\n# Override this in subclass to attach trigger handlers to\n# triggers buff passed in the argument.\nfunc load_triggers(_triggers: BuffType):\n\tpass\n\n\n# Override in subclass to initialize subclass item\n# NOTE: item.init() in JASS\nfunc item_init():\n\tpass\n\n\n# Override in subclass script to implement the effect that\n# should happen when the item is consumed.\nfunc on_consume():\n\tpass\n\n\n# NOTE: item.onCreate() in JASS\nfunc on_create():\n\tpass\n\n\n# NOTE: item.onPickup() in JASS\nfunc on_pickup():\n\tpass\n\n\n# NOTE: item.onDrop() in JASS\nfunc on_drop():\n\tpass\n\n\n# NOTE: item.onTowerDetails() in JASS\nfunc on_tower_details() -> MultiboardValues:\n\treturn null\n"
  },
  {
    "path": "src/items/item_behaviors/aqueous_vapor.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\n\tif target.get_armor_type() == ArmorType.enm.MYT:\n\t\tevent.damage = event.damage * 1.25\n\t\tEffect.create_simple_at_unit_attached(\"res://src/effects/crushing_wave.tscn\", target)\n"
  },
  {
    "path": "src/items/item_behaviors/arcane_book_of_power.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().add_tomes(8)\n"
  },
  {
    "path": "src/items/item_behaviors/arcane_oil_of_lore.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_pickup():\n\tvar carrier: Tower = item.get_carrier()\n\tcarrier.add_exp_flat(120)\n"
  },
  {
    "path": "src/items/item_behaviors/arcane_script.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_spell_casted(on_spell_cast)\n\n\nfunc on_spell_cast(event: Event):\n\tvar cd: float = event.get_autocast_type().get_cooldown()\n\n\tif !event.get_autocast_type().is_item_autocast():\n\t\titem.get_carrier().add_exp(0.2 * cd)\n\t\titem.get_carrier().get_player().give_gold(0.5 * cd, item.get_carrier(), false, true)\n"
  },
  {
    "path": "src/items/item_behaviors/arms_dealer.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 600, TargetType.new(TargetType.CREEPS + TargetType.SIZE_BOSS))\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar arms_sold_label: String = tr(\"YQK4\")\n\tmultiboard.set_key(0, arms_sold_label)\n\n\nfunc on_create():\n\titem.user_int = 0\n\titem.user_int2 = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar arms_sold_text: String = Utils.format_float(item.user_int2, 0)\n\tmultiboard.set_value(0, arms_sold_text)\n\n\treturn multiboard\n\n\nfunc on_unit_in_range(event: Event):\n\tvar t: Tower = item.get_carrier() \n\tvar c: Creep = event.get_target()\n\tvar p: Player = t.get_player()\n\tvar boss_level: int = c.get_spawn_level()\n\tvar reward_value: int\n\n\tif item.user_int < boss_level && t.calc_chance(0.25):\n\t\tCombatLog.log_item_ability(item, null, \"The Customer Is Boss\")\n\t\t\n\t\treward_value = t.get_level() + boss_level + 25\n\t\tp.give_gold(reward_value, t, true, false)\n\t\tvar arms_sold_text: String = \"%s %d\" % [tr(\"YQK4\"), reward_value]\n\t\tp.display_floating_text(arms_sold_text, t, Color8(0, 255, 0))\n\t\titem.user_int = boss_level\n\t\titem.user_int2 = item.user_int2 + reward_value\n"
  },
  {
    "path": "src/items/item_behaviors/artifact_of_skadi.gd",
    "content": "extends ItemBehavior\n\n\nvar slow_bt: BuffType\n\n\nfunc item_init():\n\tslow_bt = BuffType.create_aura_effect_type(\"slow_bt\", false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"BZT7\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.14, 0.0)\n\tslow_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/backpack.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: original script saves item reference in buff's\n# user_int. We don't need to save it because ItemBehavior\n# has access to item reference.\n\nvar backpack_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc on_autocast(_event: Event):\n\tvar tower: Unit = item.get_carrier()\n\tbackpack_bt.apply_only_timed(tower, tower, 1000)\n\n\nfunc item_init():\n\tbackpack_bt = BuffType.new(\"backpack_bt\", 0, 0, true, self)\n\tbackpack_bt.set_buff_icon(\"res://resources/icons/generic_icons/pokecog.tres\")\n\tbackpack_bt.set_buff_tooltip(tr(\"XNNT\"))\n\tbackpack_bt.add_event_on_kill(backpack_bt_on_kill)\n\t\n\tmultiboard = MultiboardValues.new(1)\n\tvar items_backpacked_label: String = tr(\"DRQK\")\n\tmultiboard.set_key(0, items_backpacked_label)\n\n\n# NOTE: backpackKill() in original script\nfunc backpack_bt_on_kill(event: Event):\n\tvar B: Buff = event.get_buff()\n\tvar tower: Tower = B.get_buffed_unit()\n\tvar creep: Creep = event.get_target()\n\n\tcreep.drop_item(tower, false)\n\tvar backpacked_text: String = tr(\"UEGM\")\n\ttower.get_player().display_small_floating_text(backpacked_text, tower, Color8(255, 165, 0), 30)\n\titem.user_int = item.user_int + 1\n\tB.remove_buff()\n\n\nfunc on_create():\n#\tTotal items found\n\titem.user_int = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar items_backpacked_text: String = Utils.format_float(item.user_int, 0)\n\tmultiboard.set_value(0, items_backpacked_text)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/ball_lightning.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: had to use instance_from_id() to convert user_int to\n# item\n\n\nvar lightning_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 3.0)\n\n\n# NOTE: BallLightningJump() in original script\nfunc lightning_pt_on_cleanup(ball: Projectile):\n\tvar tower: Tower = ball.get_caster()\n\tvar towers_in_range: Iterate \n\tvar ball_item: Item = instance_from_id(ball.user_int) as Item\n\tvar target_tower: Tower = instance_from_id(ball.user_int2) as Tower\n\tvar tower_in_range: Tower\n\n\tif ball_item == null:\n\t\tpush_error(\"ball_item is null: \", ball_item, target_tower)\n\t\n\t\treturn\n\t\n#\tNOTE: target tower may become invalid if target tower is\n#\tsold or transformed while Ball Lightning is flying to\n#\tit.\n\tvar target_tower_is_valid: bool = target_tower != null && Utils.unit_is_valid(target_tower)\n\tif !target_tower_is_valid:\n\t\tball_item.set_visible(true)\n\t\tball_item.fly_to_stash(0.0)\n\n\t\treturn\n\n\tif !ball_item.pickup(target_tower):\n\t\ttowers_in_range = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.PLAYER_TOWERS), 1500.00)\n\n\t\twhile true:\n\t\t\ttower_in_range = towers_in_range.next_random()\n\n\t\t\tif tower_in_range == null:\n\t\t\t\tbreak\n\n\t\t\tif tower_in_range != tower && tower_in_range != target_tower && tower_in_range.count_free_slots() > 0:\n\t\t\t\tbreak\n\n\t\tif tower_in_range != null:\n\t\t\tvar ball_2 = Projectile.create_bezier_interpolation_from_unit_to_unit(lightning_pt, tower, 0, 0, target_tower, tower_in_range, 1.2, 0.0, 0.5, false)\n\t\t\tball_2.user_int = ball_item.get_instance_id()\n\t\t\tball_2.user_int2 = tower_in_range.get_instance_id()\n\t\telse:\n\t\t\tball_item.set_visible(true)\n\t\t\tball_item.fly_to_stash(0.0)\n\n\nfunc item_init():\n\tlightning_pt = ProjectileType.create_interpolate(\"res://src/projectiles/projectile_visuals/ball_lightning_projectile.tscn\", 300, self)\n\tlightning_pt.set_event_on_cleanup(lightning_pt_on_cleanup)\n\n\nfunc periodic(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar ball: Projectile\n\tvar towers_in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.PLAYER_TOWERS), 1500.00)\n\tvar tower_in_range: Tower\n\n\titem.drop()\n\n\tvar found_tower: bool = false\n\n\tif towers_in_range.count() == 0:\n\t\titem.fly_to_stash(0.0)\n\n\t\treturn\n\n\twhile true:\n\t\ttower_in_range = towers_in_range.next_random()\n\n\t\tif tower_in_range == null:\n\t\t\tbreak\n\n\t\tif tower_in_range != tower && tower_in_range.count_free_slots() > 0:\n\t\t\titem.set_visible(false)\n\t\t\tball = Projectile.create_bezier_interpolation_from_unit_to_unit(lightning_pt, tower, 0, 0, tower, tower_in_range, 1.2, 0.0, 0.5, false)\n\t\t\tball.user_int = item.get_instance_id()\n\t\t\tball.user_int2 = tower_in_range.get_instance_id()\n\n\t\t\tfound_tower = true\n\n\t\t\tbreak\n\n\tif !found_tower:\n\t\titem.fly_to_stash(0.0)\n"
  },
  {
    "path": "src/items/item_behaviors/bartucs_spirit.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\titem.user_int = item.user_int + 1\n\n\tif item.user_int == 10:\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Bartuc's Spirit\")\n\t\ttower.do_spell_damage_aoe_unit(event.get_target(), 300, 2000 + (tower.get_level() * 80), tower.calc_spell_crit_no_bonus(), 0.0)\n\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/warstomp_caster.tscn\", event.get_target())\n\t\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\t\titem.user_int = 0\n\n\nfunc on_pickup():\n\titem.user_int = 0\n"
  },
  {
    "path": "src/items/item_behaviors/basics_of_calculus.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_autocast(event: Event):\n\tevent.get_target().add_exp(1.0 + item.get_carrier().get_level() * 0.04)\n"
  },
  {
    "path": "src/items/item_behaviors/bhaals_essence.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where slow debuff\n# wasn't attached to aura. This caused the item to not slow\n# the creeps.\n\n\nvar fright_bt: BuffType\n\n\nfunc item_init():\n\tfright_bt = BuffType.create_aura_effect_type(\"fright_bt\", true, self)\n\tfright_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\tfright_bt.set_buff_tooltip(tr(\"ND86\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.10, -0.0020)\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR, -4.00, -0.2)\n\tfright_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/blaster_staff.gd",
    "content": "extends ItemBehavior\n\n\nvar staff_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\n# NOTE: Collision() in original script\nfunc staff_pt_on_hit(P: Projectile, targ: Unit):\n\tif targ == null:\n\t\treturn\n\n\tP.get_caster().do_spell_damage(targ, 60.00, P.get_caster().calc_spell_crit_no_bonus()) \n\n\nfunc item_init():\n\tstaff_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4.00, 1400.00, self)\n\tstaff_pt.enable_homing(staff_pt_on_hit, 0.0)\n\n\nfunc periodic(_event: Event):\n\tvar U: Unit = item.get_carrier()\n\tvar I: Iterate = Iterate.over_units_in_range_of_unit(U, TargetType.new(TargetType.CREEPS), U, 1000.0)\n\tvar T: Unit = I.next()\n\n\tif T != null:\n\t\tProjectile.create_from_unit_to_unit(staff_pt, U, 1.00, U.calc_spell_crit_no_bonus(), U, T, true, false, false)\n"
  },
  {
    "path": "src/items/item_behaviors/bloodthirsty_wheel_of_fortune.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar fortune_bonus_label: String = tr(\"ILG6\")\n\tmultiboard.set_key(0, fortune_bonus_label)\n\n\nfunc on_create():\n\titem.user_real = 0.0\n\n\nfunc on_drop():\n\tif item.user_real != 0.0:\n\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, -1 * item.user_real)\n\n\nfunc on_pickup():\n\tif item.user_real != 0.0:\n\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, item.user_real)\n\n\nfunc on_kill(_event: Event):\n\tvar t: Tower\n\tt = item.get_carrier()\n\n\tif t.calc_chance(0.25):\t\t\n\t\tif Utils.rand_chance(Globals.synced_rng, 0.33):\n\t\t\tif item.user_real >= -0.20:\n\t\t\t\tCombatLog.log_item_ability(item, null, \"Lower Item Chance\")\n\t\t\t\t\n\t\t\t\titem.user_real = item.user_real - 0.04\n\t\t\t\tt.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, -0.04)\n\t\t\t\tvar item_chance_lowered_text: String = tr(\"GZ82\")\n\t\t\t\tt.get_player().display_small_floating_text(item_chance_lowered_text, t, Color8(255, 0, 0), 30)\n\t\telse:\n\t\t\tif item.user_real <= 0.44:\n\t\t\t\tCombatLog.log_item_ability(item, null, \"Raise Item Chance\")\n\t\t\t\t\n\t\t\t\titem.user_real = item.user_real + 0.04\n\t\t\t\tt.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.04)\n\t\t\t\tvar item_chance_raised_text: String = tr(\"GZ82\")\n\t\t\t\tt.get_player().display_small_floating_text(item_chance_raised_text, t, Color8(0, 0, 255), 30)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_percent_add_color(item.user_real, 0))\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/bloody_key.gd",
    "content": "extends ItemBehavior\n\n\nvar bestial_bt: BuffType\n\n\nfunc item_init():\n\tbestial_bt = BuffType.create_aura_effect_type(\"bestial_bt\", true, self)\n\tbestial_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tbestial_bt.set_buff_tooltip(tr(\"UEUU\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_HUMANOID, 0.12, 0.0024)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_ORC, 0.12, 0.0024)\n\tmod.add_modification(ModificationType.enm.MOD_DPS_ADD, 100, 6)\n\tbestial_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/bones_of_essence.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\n\tif target.get_armor_type() == ArmorType.enm.SIF:\n\t\tevent.damage = event.damage * 1.25\n\t\tEffect.create_simple_at_unit(\"res://src/effects/banshee_missile.tscn\", target, Unit.BodyPart.CHEST)\n"
  },
  {
    "path": "src/items/item_behaviors/bonks_face.gd",
    "content": "extends ItemBehavior\n\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar twr: Unit = item.get_carrier()\n\tvar target_effect: int\n\n\tif creep.is_stunned():\n\t\tCombatLog.log_item_ability(item, creep, \"Crush\")\n\t\ttwr.do_spell_damage_aoe_unit(creep, 250, twr.get_current_attack_damage_with_bonus() * 0.2, twr.calc_spell_crit_no_bonus(), 0)\n\t\ttarget_effect = Effect.create_animated(\"res://src/effects/impale_target_dust.tscn\", Vector3(creep.get_x(), creep.get_y(), 0.0), 0)\n\t\tEffect.set_scale(target_effect, 0.5)\n"
  },
  {
    "path": "src/items/item_behaviors/book_of_force.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\tprint_verbose(\"Book of Force was used. Adding 3 tomes.\")\n\t\n\titem.get_player().add_tomes(3)\n"
  },
  {
    "path": "src/items/item_behaviors/book_of_knowledge.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar cd: float = tower.get_base_attack_speed()\n\tvar tower_range: float = tower.get_base_range()\n\n\tif event.is_main_target():\n\t\ttower.add_exp(0.2 * cd * (800 / tower_range))\n"
  },
  {
    "path": "src/items/item_behaviors/brimstone_helmet.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_attack(_event: Event):\n\titem.user_real = item.user_real + 50.0 + 1.0 * item.get_carrier().get_level()\n\titem.set_charges(int(item.user_real))\n\n\nfunc on_damage(event: Event):\n\tvar T: Tower = item.get_carrier()\n\tvar C: Creep = event.get_target()\n\n\tif item.user_real >= 100.0:\n\t\tevent.damage = event.damage / AttackType.get_damage_against(T.get_attack_type(), C.get_armor_type()) * AttackType.get_damage_against(AttackType.enm.ELEMENTAL, C.get_armor_type())\n\t\tSFX.sfx_at_unit(SfxPaths.FIRE_BALL, C)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/incinerate.tscn\", C)\n\t\titem.user_real = item.user_real - 100.0\n\t\titem.set_charges(int(item.user_real))\n\n\nfunc on_pickup():\n\titem.user_real = 0.0\n\titem.set_charges(0)\n"
  },
  {
    "path": "src/items/item_behaviors/chameleon_glaive.gd",
    "content": "extends ItemBehavior\n\n\nvar chameleon_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n# NOTE: hit() in original script\nfunc chameleon_pt_on_hit(p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar tower: Tower = p.get_caster()\n\ttower.do_attack_damage(creep, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit(0, 0, 0))\n\n\nfunc item_init():\n\tchameleon_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 1000, self)\n\tchameleon_pt.enable_homing(chameleon_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar creep: Unit = event.get_target()\n\tvar p: Projectile\n\n\tif !tower.calc_chance(0.4 + 0.004 * tower.get_level()):\n\t\treturn\n\n\tCombatLog.log_item_ability(item, null, \"Launch Glaive!\")\n\n\tawait Utils.create_manual_timer(0.1, self).timeout\n\n\tif !Utils.unit_is_valid(tower) || !Utils.unit_is_valid(creep):\n\t\treturn\n\n\tp = Projectile.create_from_unit_to_unit(chameleon_pt, tower, 1, 0, tower, creep, true, false, false)\n\tp.set_projectile_scale(0.75)\n"
  },
  {
    "path": "src/items/item_behaviors/chameleons_soul.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_drop():\n\tvar tower: Tower = item.get_carrier()\n\n\tif tower.get_element() == Element.enm.ASTRAL:\n\t\ttower.modify_property(ModificationType.enm.MOD_EXP_RECEIVED, -1.00)\n\telif tower.get_element() == Element.enm.DARKNESS:\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -0.45)\n\telif tower.get_element() == Element.enm.NATURE:\n\t\ttower.modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, -0.10)\n\telif tower.get_element() == Element.enm.FIRE:\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -0.40)\n\telif tower.get_element() == Element.enm.ICE:\n\t\ttower.modify_property(ModificationType.enm.MOD_BUFF_DURATION, -0.50)\n\telif tower.get_element() == Element.enm.STORM:\n\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -0.25)\n\telif tower.get_element() == Element.enm.IRON:\n\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, -0.30)\n\n\nfunc on_pickup():\n\tvar tower: Tower = item.get_carrier()\n\n\tif tower.get_element() == Element.enm.ASTRAL:\n\t\ttower.modify_property(ModificationType.enm.MOD_EXP_RECEIVED, 1.00)\n\telif tower.get_element() == Element.enm.DARKNESS:\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.45)\n\telif tower.get_element() == Element.enm.NATURE:\n\t\ttower.modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.10)\n\telif tower.get_element() == Element.enm.FIRE:\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.40)\n\telif tower.get_element() == Element.enm.ICE:\n\t\ttower.modify_property(ModificationType.enm.MOD_BUFF_DURATION, 0.50)\n\telif tower.get_element() == Element.enm.STORM:\n\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.25)\n\telif tower.get_element() == Element.enm.IRON:\n\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.30)\n"
  },
  {
    "path": "src/items/item_behaviors/charged_disk.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar twr: Tower = item.get_carrier() \n\n\tif event.is_main_target():\n\t\ttwr.do_spell_damage(event.get_target(), (0.08 + 0.001 * twr.get_level()) * twr.get_gold_cost() * twr.get_base_attack_speed(), twr.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/items/item_behaviors/chrono_jumper.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: this item is complicated and has multiple edge\n# cases:\n# - Jump to position, transform/upgrade tower while tower is\n#   at jump position. Handled by not allowing\n#   transform/upgrade while tower is jumping.\n# - Buildable state at original position. When tower jumps,\n#   previous position stays as \"occupied\" so it's not\n#   possible to build a new tower on old position while\n#   tower is jumping.\n# - Buildable state at jump position. This is intentionally\n#   not modified in any way. It is possible to build a tower\n#   on top of jumping tower but that doesn't cause any\n#   problems.\n\n\nconst JUMP_DURATION: float = 10.0\nconst ATTACKSPEED_BONUS: float = 0.10\n\nvar jumper_bt: BuffType\nvar original_pos: Vector2 = Vector2.ZERO\n\n\nfunc item_init():\n\tjumper_bt = BuffType.new(\"jumper_bt\", JUMP_DURATION, 0, true, self)\n\tvar jumper_bt_mod: Modifier = Modifier.new()\n\tjumper_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, ATTACKSPEED_BONUS, 0.0)\n\tjumper_bt.set_buff_modifier(jumper_bt_mod)\n\tjumper_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\tjumper_bt.set_buff_tooltip(tr(\"1UM5\"))\n\tjumper_bt.add_event_on_create(jumper_bt_on_create)\n\tjumper_bt.add_event_on_cleanup(jumper_bt_on_cleanup)\n\n\n# NOTE: there are convoluted conversions between wc3 and\n# canvas positions because some API's accept only canvas\n# positions. Be careful if you decide to fix this by adding\n# API's for wc3 positions, it's easy to make a mistake.\nfunc on_autocast(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar player: Player = tower.get_player()\n\n\tvar tower_already_jumping: bool = tower.get_buff_of_type(jumper_bt) != null\n\n\tif tower_already_jumping:\n\t\tvar cannot_jump_right_now_text: String = tr(\"MB3D\")\n\t\tplayer.display_floating_text(cannot_jump_right_now_text, tower, Color.PURPLE)\n\n\t\treturn\n\n\toriginal_pos = tower.get_position_wc3_2d()\n\tvar original_pos_3d: Vector3 = tower.get_position_wc3()\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar target_pos_wc3: Vector2 = autocast.get_target_pos()\n\tvar target_pos_canvas: Vector2 = VectorUtils.wc3_2d_to_canvas(target_pos_wc3)\n\tvar target_pos_canvas_snapped: Vector2 = VectorUtils.snap_canvas_pos_to_buildable_pos(target_pos_canvas)\n\t\n\tvar game_scene: GameScene = get_tree().get_root().get_node(\"GameScene\")\n\tvar build_space: BuildSpace = game_scene.get_build_space()\n\tvar can_build_at_pos: bool = build_space.can_build_at_pos(player, target_pos_canvas_snapped)\n\n\tvar dest_pos_canvas: Vector2\n\n\tif can_build_at_pos:\n\t\tdest_pos_canvas = target_pos_canvas_snapped\n\telse:\n\t\tvar nearby_buildable_pos: Vector2 = find_nearby_buildable_pos(player, target_pos_wc3)\n\t\tvar found_buildable_pos: bool = nearby_buildable_pos != Vector2.INF\n\n\t\tif found_buildable_pos:\n\t\t\tdest_pos_canvas = nearby_buildable_pos\n\t\telse:\n\t\t\tvar cannot_jump_to_position_text: String = tr(\"FJ63\")\n\t\t\tplayer.display_floating_text_at_pos(cannot_jump_to_position_text, target_pos_wc3, Color.PURPLE)\n\t\t\t\n\t\t\treturn\n\n\tdest_pos_canvas.y += Constants.TILE_SIZE.y\n\tvar dest_pos_wc3: Vector2 = VectorUtils.canvas_to_wc3_2d(dest_pos_canvas)\n\t\n\tEffect.create_simple_at_unit(\"res://src/effects/mass_teleport_caster.tscn\", tower)\n\tSFX.sfx_at_unit(SfxPaths.WARP, tower)\n\ttower.set_position_wc3_2d(dest_pos_wc3)\n\tEffect.create_simple_at_unit(\"res://src/effects/mass_teleport_target.tscn\", tower)\n\tSFX.sfx_at_unit(SfxPaths.TELEPORT_BASS, tower)\n\tjumper_bt.apply(tower, tower, 0)\n\n\tvar effect: int = Effect.create_animated(\"res://src/effects/vampiric_aura.tscn\", original_pos_3d, 0)\n\tEffect.set_color(effect, Color.ROYAL_BLUE)\n\tEffect.set_lifetime(effect, JUMP_DURATION)\n\n\n# NOTE: need to disable transform while jumping to prevent\n# unintended behavior\nfunc jumper_bt_on_create(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\ttower.set_transform_is_allowed(false)\n\n\n# NOTE: need 0.1s delay to handle Distorted Idol + Chrono\n# Jumper interaction. The intended interaction is that\n# player can:\n# - Equip 5 items on tower with 6 inventory slots\n# - Equip Chrono Jumper\n# - Use Chrono Jumper to a corner\n# - While tower is on corner, swap Distorted Idol and Chrono Jumper\n# - Result is that Distorted Idol copied 5 items\n# \n# If there's no delay, then sequence would be:\n# - Chrono Jumper is removed from tower\n# - Chrono Jump buff is removed\n# - Tower is moved to original position\n# - Distorted Idol is equipped\n# - Distorted Idol is uneqipped because tower is not on corner!\n# \n# This problem happens because in youtd2 engine, when items\n# are unequipped, all item buffs are removed. In youtd1,\n# item buffs stay until expiry. Item buffs are removed in\n# youtd2 to ensure null reference safety. In youtd1, null\n# reference safety can be disregarded because JASS scripts\n# can handle them without crashes.\n# \n# Thanks to this delay, Distorted Idol is equipped\n# successfully and stays on tower.\n# \n# NOTE: chrono_jumper_onCleanup() in original script\nfunc jumper_bt_on_cleanup(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n#\tNOTE: need to call on tower because item is\n#\toutside tree during CLEANUP callback\n\tawait Utils.create_manual_timer(0.1, tower).timeout\n\n\tif !Utils.unit_is_valid(tower):\n\t\treturn\n\t\n\tEffect.create_simple_at_unit(\"res://src/effects/mass_teleport_caster.tscn\", tower)\n\tSFX.sfx_at_unit(SfxPaths.WARP, tower)\n\ttower.set_position_wc3_2d(original_pos)\n\tEffect.create_simple_at_unit(\"res://src/effects/mass_teleport_target.tscn\", tower)\n\tSFX.sfx_at_unit(SfxPaths.TELEPORT_BASS, tower)\n\n\ttower.set_transform_is_allowed(true)\n\n\nfunc find_nearby_buildable_pos(player: Player, target_pos: Vector2):\n\tvar game_scene: GameScene = get_tree().get_root().get_node(\"GameScene\")\n\tvar build_space: BuildSpace = game_scene.get_build_space()\n\n\tvar neighbor_list: Array = []\n\n\tfor dx in range(-1, 2):\n\t\tfor dy in range(-1, 2):\n\t\t\tvar offset: Vector2 = Vector2(dx, dy) * 0.5 * Constants.TILE_SIZE_WC3\n\t\t\tvar neighbor: Vector2 = target_pos + offset\n\n\t\t\tif neighbor_list.has(neighbor):\n\t\t\t\tcontinue\n\n\t\t\tneighbor_list.append(neighbor)\n\n\tneighbor_list.sort_custom(\n\t\tfunc (a: Vector2, b: Vector2) -> bool:\n\t\t\tvar dist_a: float = target_pos.distance_squared_to(a)\n\t\t\tvar dist_b: float = target_pos.distance_squared_to(b)\n\n\t\t\treturn dist_a < dist_b\n\t\t\t)\n\n\tfor neighbor in neighbor_list:\n\t\tvar neighbor_canvas: Vector2 = VectorUtils.wc3_2d_to_canvas(neighbor)\n\t\tvar can_build_at_neighbor: bool = build_space.can_build_at_pos(player, neighbor_canvas)\n\n\t\tif can_build_at_neighbor:\n\t\t\treturn neighbor_canvas\n\n\tvar value_if_not_found: Vector2 = Vector2.INF\n\n\treturn value_if_not_found\n"
  },
  {
    "path": "src/items/item_behaviors/circle_of_power.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 5)\n\n\n\nfunc on_pickup():\n\titem.user_real = item.get_carrier().get_mana()\n\n\nfunc periodic(_event: Event):\n\tvar u: Unit = item.get_carrier()\n\tvar cur_mana: float = u.get_mana()\n\n\tif cur_mana < item.user_real && u.calc_chance(0.25):\n\t\tCombatLog.log_item_ability(item, null, \"Circle of Power\")\n\t\tu.set_mana(item.user_real)\n\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/spell_aima.tscn\", u)\n\t\tEffect.set_color(effect, Color.GOLD)\n\telse:\n\t\titem.user_real = cur_mana\n"
  },
  {
    "path": "src/items/item_behaviors/commander.gd",
    "content": "extends ItemBehavior\n\n\nvar attack_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tattack_bt = BuffType.new(\"attack_bt\", 4, 0.1, true, self)\n\tattack_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\tattack_bt.set_buff_tooltip(tr(\"W1NC\"))\n\tvar mod: Modifier = Modifier.new() \n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.50, 0) \n\tattack_bt.set_buff_modifier(mod) \n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier() \n\tvar in_range: Iterate\n\tvar nxt: Tower\n\tvar spieler: Player = tower.get_player()\n\tvar speed: float = tower.get_base_attack_speed()\n\n\tif tower.calc_chance(speed * (0.02 + 0.001 * tower.get_level())):\n\t\tCombatLog.log_item_ability(item, null, \"Attack!\")\n\t\t\n\t\tvar attack_text: String = tr(\"HY2D\")\n\t\tspieler.display_floating_text(attack_text, tower, Color8(255, 0, 0))\n\t\tEffect.create_simple_at_unit_attached(\"res://src/effects/roar.tscn\", tower, Unit.BodyPart.ORIGIN)\n\t\tin_range = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 350)\n\n\t\twhile true:\n\t\t\tnxt = in_range.next()\n\n\t\t\tif nxt == null:\n\t\t\t\tbreak\n\n\t\t\tattack_bt.apply_custom_timed(tower, nxt, tower.get_level(), 4 + 0.2 * tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/consumable_chicken.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().modify_food_cap(2)\n"
  },
  {
    "path": "src/items/item_behaviors/consumable_hobbit.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().modify_food_cap(8)\n\titem.get_player().add_tomes(20)\n\titem.get_player().modify_income_rate(0.06)\n\titem.get_player().get_team().modify_lives(2)\n"
  },
  {
    "path": "src/items/item_behaviors/consumable_piggy.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().modify_food_cap(5)\n"
  },
  {
    "path": "src/items/item_behaviors/consumable_plant.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().modify_food_cap(1)\n"
  },
  {
    "path": "src/items/item_behaviors/crescent_stone.gd",
    "content": "extends ItemBehavior\n\n\nvar earth_and_moon_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 15)\n\n\nfunc item_init():\n\tearth_and_moon_bt = BuffType.new(\"earth_and_moon_bt\", 5, 0, true, self)\n\tearth_and_moon_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\tearth_and_moon_bt.set_buff_tooltip(tr(\"O4EP\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.25, 0.01)\n\tearth_and_moon_bt.set_buff_modifier(mod)\n\n\nfunc periodic(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tCombatLog.log_item_ability(item, null, \"Earth and Moon\")\n\tearth_and_moon_bt.apply(tower, tower, tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/crit_blade.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar crit_gained_label: String = tr(\"E3XG\")\n\tmultiboard.set_key(0, crit_gained_label)\n\n\nfunc on_attack(event: Event):\n\tif event.get_number_of_crits() > 0:\n\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, -item.user_real)\n\t\titem.user_real = 0\n\telse:\n\t\tif item.user_real < 0.40:\n\t\t\titem.user_real = item.user_real + 0.02\n\t\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.02)\n\n\nfunc on_create():\n\titem.user_real = 0.00\n\n\nfunc on_drop():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, -item.user_real)\n\n\nfunc on_pickup():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, item.user_real)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar crit_chance_bonus_text: String = Utils.format_percent(item.user_real, 0)\n\tmultiboard.set_value(0, crit_chance_bonus_text)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/cruel_torch.gd",
    "content": "extends ItemBehavior\n\n\nvar flames_bt: BuffType\n\n\nfunc item_init():\n\tflames_bt = BuffType.create_aura_effect_type(\"flames_bt\", true, self)\n\tflames_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tflames_bt.set_buff_tooltip(tr(\"KT5P\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.035, 0.0008)\n\tflames_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/currency_converter.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(on_periodic, 1.0)\n\n\nfunc on_periodic(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar lvl: int = tower.get_level()\n\tevent.enable_advanced(15 - lvl * 0.3, false)\n\tif tower.get_exp() >= 2.0:\n\t\tCombatLog.log_item_ability(item, null, \"Exchange\")\n\t\ttower.remove_exp_flat(2)\n\t\ttower.get_player().give_gold(7, tower, true, true)\n\telse:\n\t\tvar not_enough_credits_text: String = tr(\"LOO6\")\n\t\ttower.get_player().display_floating_text(not_enough_credits_text, tower, Color8(255, 0, 0))\n"
  },
  {
    "path": "src/items/item_behaviors/cursed_claw.gd",
    "content": "extends ItemBehavior\n\n\nvar cripple_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tcripple_bt = BuffType.new(\"cripple_bt\", 5, 0, false, self)\n\tcripple_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tcripple_bt.set_buff_tooltip(tr(\"ARXM\"))\n\tvar mod: Modifier = Modifier.new() \n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.10, -0.004) \n\tcripple_bt.set_buff_modifier(mod) \n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tcripple_bt.apply(tower, target, level)\n"
  },
  {
    "path": "src/items/item_behaviors/dagger_of_bane.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: in original, tower is saved in buff's user_int.\n# Changed it so that tower's get_instance_id() is saved instead\n# because we can't convert references to ints in gdscript.\n\n\nvar poison_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: dealDamage() in original script\nfunc poison_bt_periodic(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar tower: Tower = b.get_caster()\n\n\tif tower.get_instance_id() == b.user_int:\n\t\ttower.do_spell_damage(b.get_buffed_unit(), tower.get_current_attack_damage_base() * 0.15, tower.get_spell_crit_damage())\n\telse:\n\t\tb.remove_buff()\n\n\nfunc item_init():\n#\t+ 0.01 seconds is a dirty hack to make damage tick 4 times with 100% duration\n\tpoison_bt = BuffType.new(\"poison_bt\", 4.01, 0, false, self)\n\tpoison_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tpoison_bt.set_buff_tooltip(tr(\"IF2L\"))\n\tpoison_bt.add_periodic_event(poison_bt_periodic, 1)\n\n\nfunc on_damage(event: Event):\n\tvar P: Buff\n\tvar u: Unit\n\n\tif event.is_main_target():\n\t\tu = event.get_target()\n\t\tP = u.get_buff_of_type(poison_bt)\n\n\t\tif P != null:\n\t\t\tpoison_bt.apply(item.get_carrier(), event.get_target(), 0)\n\t\telse:\n\t\t\tpoison_bt.apply(item.get_carrier(), event.get_target(), 0).user_int = item.get_carrier().get_instance_id()\n"
  },
  {
    "path": "src/items/item_behaviors/dark_matter_trident.gd",
    "content": "extends ItemBehavior\n\n\nvar boost_bt: BuffType\nvar drain_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc item_init():\n\tboost_bt = BuffType.new(\"boost_bt\", 2.5, 0.0, true, self)\n\tboost_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tboost_bt.set_buff_tooltip(tr(\"2MER\"))\n\tvar boost_bt_mod: Modifier = Modifier.new()\n\tboost_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.0002)\n\tboost_bt.set_buff_modifier(boost_bt_mod)\n\n\tdrain_bt = BuffType.new(\"drain_bt\", 2.5, 0.0, false, self)\n\tdrain_bt.set_buff_icon(\"res://resources/icons/generic_icons/energy_breath.tres\")\n\tdrain_bt.set_buff_tooltip(tr(\"3KMZ\"))\n\tvar drain_bt_mod: Modifier = Modifier.new()\n\tdrain_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.0002)\n\tdrain_bt.set_buff_modifier(drain_bt_mod)\n\n\nfunc on_damage(event: Event):\n\tif !event.is_main_target():\n\t\treturn\n\n\tvar tower: Tower = item.get_carrier()\n\tvar creep: Creep = event.get_target()\n\tvar level_add: int = int(100.0 * tower.get_current_attack_speed())\n\tvar duration: float = 5 + 0.1 * tower.get_level()\n\n\tvar positive_buff: Buff = tower.get_buff_of_type(boost_bt)\n\tif positive_buff != null:\n\t\tboost_bt.apply_custom_timed(tower, tower, min(level_add + positive_buff.get_level(), 2000), duration)\n\telse:\n\t\tboost_bt.apply_custom_timed(tower, tower, level_add, duration)\n\n\tpositive_buff = tower.get_buff_of_type(boost_bt)\n\tif positive_buff != null:\n\t\tvar stack_count: int = positive_buff.get_level() / 100\n\t\tpositive_buff.set_displayed_stacks(stack_count)\n\n\tvar negative_buff: Buff = creep.get_buff_of_type(drain_bt)\n\tif negative_buff != null:\n\t\tdrain_bt.apply_custom_timed(tower, creep, min(level_add + negative_buff.get_level(), 2000), duration)\n\telse:\n\t\tdrain_bt.apply_custom_timed(tower, creep, level_add, duration)\n\n\tnegative_buff = creep.get_buff_of_type(drain_bt)\n\tif negative_buff != null:\n\t\tvar stack_count: int = negative_buff.get_level() / 100\n\t\tnegative_buff.set_displayed_stacks(stack_count)\n"
  },
  {
    "path": "src/items/item_behaviors/deep_shadows.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\n\tif target.get_armor_type() == ArmorType.enm.SOL:\n\t\tevent.damage = event.damage * 1.25\n\t\n\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/frag_boom_spawn.tscn\", target)\n\t\tEffect.set_color(effect, Color.DARK_BLUE)\n"
  },
  {
    "path": "src/items/item_behaviors/distorted_idol.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\nvar copied_item_list: Array[Item] = []\n\n\nfunc create_multiboard(size: int):\n\tmultiboard = MultiboardValues.new(size)\n\tfor i in range(size):\n\t\tvar distorted_item_label: String = tr(\"BHLE\").format({NUMBER = i})\n\t\tmultiboard.set_key(i, distorted_item_label)\n\nfunc item_init():\n\tcreate_multiboard(1)\n\nfunc on_pickup():\n\tvar carrier: Tower = item.get_carrier()\n\tvar player: Player = item.get_player()\n\t\n\tvar carrier_is_on_corner: bool = get_carrier_is_on_corner()\n\n#\tNOTE: need delay before dropping item because\n#\timmediately dropping after adding to inventory\n#\tcauses problems\n\tif !carrier_is_on_corner:\n\t\tvar tower_must_be_on_corner_text: String = tr(\"E8DP\")\n\t\tplayer.display_floating_text(tower_must_be_on_corner_text, carrier, Color.PURPLE)\n\n\t\tawait Utils.create_manual_timer(0.1, self).timeout\n\t\t\n\t\titem.drop()\n\t\titem.fly_to_stash(0.0)\n\n\t\treturn\n\n\tvar item_list: Array[Item] = carrier.get_items()\n\tvar distorted_idol_id: int = item.get_id()\n\n\tfor original_item in item_list:\n\t\tvar copied_item_id: int = original_item.get_id()\n\t\tvar is_distorted_idol: bool = copied_item_id == distorted_idol_id\n\n\t\tif is_distorted_idol:\n\t\t\tcontinue\n\n#       NOTE: adding item to tower without adding to\n#       inventory. This applies all item effects without\n#       occupying a slot in inventory.\n# \n#       NOTE: need to use make() instead of create() because\n#       ItemDrop is not needed here.\n\t\tvar copied_item: Item = Item.make(copied_item_id, player)\n\t\tcopied_item._add_to_tower(carrier)\n\t\tcopied_item.disable_autocast()\n\t\titem.add_child(copied_item)\n\t\tcopied_item_list.append(copied_item)\n\t\n\tcreate_multiboard(len(copied_item_list))\n\n\nfunc on_drop():\n\tfor copied_item in copied_item_list:\n\t\tcopied_item._remove_from_tower()\n\t\titem.remove_child(copied_item)\n\t\tcopied_item.queue_free()\n\n\tcopied_item_list.clear()\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar index: int = 0\n\n\tfor copied_item in copied_item_list:\n\t\tvar copied_item_name: String = copied_item.get_display_name()\n\t\tmultiboard.set_value(index, copied_item_name)\n\t\n\t\tindex += 1\n\n\treturn multiboard\n\n\nfunc get_carrier_is_on_corner() -> bool:\n\tvar game_scene: GameScene = get_tree().get_root().get_node(\"GameScene\")\n\tvar build_space: BuildSpace = game_scene.get_build_space()\n\n\tvar carrier: Tower = item.get_carrier()\n\tvar carrier_pos_canvas: Vector2 = carrier.get_visual_position()\n\tvar carrier_pos_map: Vector2i = build_space._convert_pos_canvas_to_map(carrier_pos_canvas)\n\tvar player: Player = carrier.get_player()\n\t\n\tvar offset_list: Array[Vector2i] = [\n\t\tVector2i(2, 0),\n\t\tVector2i(-2, 0),\n\t\tVector2i(0, 2),\n\t\tVector2i(0, -2),\n\t]\n\n\tvar non_buildable_count: int = 0\n\n\tfor offset in offset_list:\n\t\tvar neighbor_pos: Vector2i = carrier_pos_map + offset\n\t\tvar is_buildable: bool = build_space.buildable_cell_exists_at_pos(player, neighbor_pos)\n\n\t\tif !is_buildable:\n\t\t\tnon_buildable_count += 1\n\n\tvar is_corner: bool = non_buildable_count >= 2\n\n\treturn is_corner\n"
  },
  {
    "path": "src/items/item_behaviors/divine_book_of_omnipotence.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().add_tomes(15)\n"
  },
  {
    "path": "src/items/item_behaviors/dooms_ensign.gd",
    "content": "extends ItemBehavior\n\n\nvar ensign_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc item_init():\n\tensign_bt = BuffType.new(\"ensign_bt\", 5, 0, false, self)\n\tensign_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tensign_bt.set_buff_tooltip(tr(\"QCSJ\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, -0.10, -0.006)\n\tensign_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n\tif event.is_main_target():\n\t\tensign_bt.apply(item.get_carrier(), event.get_target(), item.get_carrier().get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/elunes_bow.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar dmg: float = item.get_carrier().get_current_attack_damage_base()\n\n\tif event.damage < dmg && event.is_main_target():\n\t\tevent.damage = dmg\n"
  },
  {
    "path": "src/items/item_behaviors/empty_item_behavior.gd",
    "content": "extends ItemBehavior\n\n# NOTE: this is an empty script to be used for items which\n# don't have any behavior to put in a script.\n"
  },
  {
    "path": "src/items/item_behaviors/enchanted_knives.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_drop():\n    var tower: Tower = item.get_carrier()\n    var target_count: int = tower.get_target_count_from_item()\n    tower.set_target_count_from_item(target_count - 3)\n\n\nfunc on_pickup():\n    var tower: Tower = item.get_carrier()\n    var target_count: int = tower.get_target_count_from_item()\n    tower.set_target_count_from_item(target_count + 3)\n"
  },
  {
    "path": "src/items/item_behaviors/essence_of_rot.gd",
    "content": "extends ItemBehavior\n\n\nvar presence_tower_bt: BuffType\nvar presence_creep_bt: BuffType\n\n\nfunc item_init():\n\tpresence_tower_bt = BuffType.create_aura_effect_type(\"presence_tower_bt\", false, self)\n\tpresence_tower_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tpresence_tower_bt.set_buff_tooltip(tr(\"7COB\"))\n\tvar presence_tower_bt_mod: Modifier = Modifier.new()\n\tpresence_tower_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.2, 0.002)\n\tpresence_tower_bt.set_buff_modifier(presence_tower_bt_mod)\n\n\tpresence_creep_bt = BuffType.create_aura_effect_type(\"presence_creep_bt\", false, self)\n\tpresence_creep_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tpresence_creep_bt.set_buff_tooltip(tr(\"H3NT\"))\n\tvar presence_creep_bt_mod: Modifier = Modifier.new()\n\tpresence_creep_bt_mod.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, 0.2, 0.004)\n\tpresence_creep_bt_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.2, 0.004)\n\tpresence_creep_bt.set_buff_modifier(presence_creep_bt_mod)\n"
  },
  {
    "path": "src/items/item_behaviors/even_more_magical_hammer.gd",
    "content": "extends ItemBehavior\n\n\nvar mark_bt: BuffType\nvar aura_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 2000, TargetType.new(TargetType.CREEPS))\n\n\n# NOTE: Mark_Setup() in original script\nfunc mark_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\n\tbuff.user_int = 5\n\tbuff.user_int2 = 5\n\tbuff.user_int3 = 5\n\n\tbuff.user_real = 50\n\tbuff.user_real2 = 50\n\tbuff.user_real3 = 50\n\n\n# NOTE: Hammer_Aura_Trig() in original script\nfunc aura_bt_on_damaged(event: Event):\n\tif !event.is_spell_damage():\n\t\treturn\n\n#\tHas attacker the mark buff?\n\tvar tower: Tower = event.get_target()\n\tvar buff: Buff = tower.get_buff_of_type(mark_bt)\n\n\tif buff == null:\n\t\treturn\n\n\tvar lvl: int = buff.get_level()\n\n#\tAttacking tower carries a hammer\n#\tHammer 1\n\tbuff.user_int = buff.user_int - 1\n\tif buff.user_int <= 0:\n\t\tbuff.user_int = 5\n\t\ttower.add_spell_crit()\n\n#\tHammer 2\n\tif lvl >= 2:\n\t\tbuff.user_int2 = buff.user_int2 - 1\n\t\tif buff.user_int2 <= 0:\n\t\t\tbuff.user_int2 = 5\n\t\t\ttower.add_spell_crit()\n\telse:\n#\t\tOnly 1 hammer\n\t\treturn\n\n#\tHammer 3\n\tif lvl >= 3:\n\t\tbuff.user_int3 = buff.user_int3 - 1\n\t\tif buff.user_int3 <= 0:\n\t\t\tbuff.user_int3 = 5\n\t\t\ttower.add_spell_crit()\n\telse:\n#\t\tOnly 2 hammer\n\t\treturn\n\n#\tHammer 4\n\tif lvl >= 4:\n\t\tbuff.user_real = buff.user_real - 10\n#\t\tBecause real are realy not accurate at all.\n\t\tif buff.user_real < 5:\n\t\t\tbuff.user_real = 50\n\t\t\ttower.add_spell_crit()\n\telse:\n#\t\tOnly 3 hammer\n\t\treturn\n\n#\tHammer 5\n\tif lvl >= 5:\n\t\tbuff.user_real2 = buff.user_real2 - 10\n#\t\tBecause real are realy not accurate at all.\n\t\tif buff.user_real2 < 5:\n\t\t\tbuff.user_real2 = 50\n\t\t\ttower.add_spell_crit()\n\telse:\n#\t\tOnly 4 hammer\n\t\treturn\n\n#\tHammer 6\n\tif lvl >= 6:\n\t\tbuff.user_real3 = buff.user_real3 - 10\n#\t\tBecause real are realy not accurate at all.\n\t\tif buff.user_real3 < 5:\n\t\t\tbuff.user_real3 = 50\n\t\t\ttower.add_spell_crit()\n\n\nfunc item_init():\n\tmark_bt = BuffType.new(\"mark_bt\", -1, 0, true, self)\n\tmark_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\tmark_bt.add_event_on_create(mark_bt_on_create)\n\tmark_bt.set_hidden()\n\n\taura_bt = BuffType.new(\"aura_bt\", -1, 0, true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\taura_bt.add_event_on_damaged(aura_bt_on_damaged)\n\taura_bt.set_hidden()\n\n\nfunc on_drop():\n\tvar tower: Tower = item.get_carrier()\n\tvar buff: Buff = tower.get_buff_of_type(mark_bt)\n\n\tif buff != null:\n#\t\tFirst hammer on tower\n\t\tif buff.get_level() == 1:\n#\t\t\tOnly one hammer was on tower\n\t\t\tbuff.remove_buff()\n\t\telse:\n\t\t\tbuff.set_level(buff.get_level() - 1)\n\telse:\n#\t\tNo buff, although there is still a hammer on the tower! Shit happened!\n\t\treturn\n\n\nfunc on_pickup():\n\tvar tower: Tower = item.get_carrier()\n\tvar buff: Buff = tower.get_buff_of_type(mark_bt)\n\n\tif buff == null:\n#\t\tFirst hammer on tower\n\t\tmark_bt.apply(tower, tower, 1)\n\telse:\n#\t\tAlready a hammer on the tower\n\t\tbuff.set_level(buff.get_level() + 1)\n\n\nfunc on_unit_in_range(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif target.get_buff_of_type(aura_bt) == null:\n\t\taura_bt.apply(item.get_carrier(), target, 0)\n"
  },
  {
    "path": "src/items/item_behaviors/excalibur.gd",
    "content": "extends ItemBehavior\n\n\nvar power_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n    triggers.add_event_on_damage(on_damage)\n\n\nfunc item_init():\n    power_bt = BuffType.new(\"power_bt\", 5, 0, false, self)\n    power_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n    power_bt.set_buff_tooltip(tr(\"F9SA\"))\n    var mod: Modifier = Modifier.new()\n    mod.add_modification(ModificationType.enm.MOD_ARMOR, 0.0, -0.2)\n    power_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n    var tower: Tower = item.get_carrier()\n\n    if event.is_main_target() == true:\n        if Utils.rand_chance(Globals.synced_rng, 0.5):\n            power_bt.apply(tower, event.get_target(), 25 + tower.get_level())\n        else:\n            power_bt.apply(tower, event.get_target(), 50 + tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/eye_of_true_sight.gd",
    "content": "extends ItemBehavior\n\n\n# var true_sight_bt: BuffType\n\n\n# func item_init():\n# \ttrue_sight_bt = MagicalSightBuff.new(\"true_sight_bt\", 900, self)\n# \ttrue_sight_bt.set_buff_tooltip(tr(\"SH63\"))\n\n\n# func load_triggers(triggers: BuffType):\n# \ttriggers.add_event_on_damage(on_damage)\n\n\n# func on_damage(event: Event):\n# \tif event.get_target().is_invisible():\n# \t\tevent.damage = event.damage * (1.2 + 0.008 * item.get_carrier().get_level())\n\n\n# func on_pickup():\n# \tvar carrier: Unit = item.get_carrier()\n# \ttrue_sight_bt.apply_to_unit_permanent(carrier, carrier, 0)\t\n"
  },
  {
    "path": "src/items/item_behaviors/faithful_staff.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_spell_casted(on_spell_cast)\n\n\nfunc on_spell_cast(event: Event):\n\tvar tower: Unit = item.get_carrier()\n\tvar target_unit: Unit = event.get_target()\n\n\tif target_unit is Tower:\n\t\tCombatLog.log_item_ability(item, null, \"Reward the Faithful\")\n\t\t\n\t\ttarget_unit.add_exp(1)\n\t\ttower.add_exp(1)\n"
  },
  {
    "path": "src/items/item_behaviors/fist_of_doom.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 10)\n\n\nfunc periodic(_event: Event):\n\tCombatLog.log_item_ability(item, null, \"Pay With Blood\")\n\titem.get_carrier().remove_exp(2)\n"
  },
  {
    "path": "src/items/item_behaviors/flag_of_the_allegiance.gd",
    "content": "extends ItemBehavior\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Flag of the Alliance\"=>\"Flag of the Allegiance\"\n\nvar motivation_bt: BuffType\n\n\nfunc item_init():\n\tmotivation_bt = BuffType.create_aura_effect_type(\"motivation_bt\", true, self) \n\tmotivation_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tmotivation_bt.set_buff_tooltip(tr(\"7NOD\"))\n\tvar mod: Modifier = Modifier.new() \n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.05, 0.001) \n\tmotivation_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/forcefield_generator.gd",
    "content": "extends ItemBehavior\n\n\nvar forcefield_bt: BuffType\n\n\nfunc item_init():\n\tforcefield_bt = BuffType.create_aura_effect_type(\"forcefield_bt\", true, self)\n\tforcefield_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tforcefield_bt.set_buff_tooltip(tr(\"X440\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.15, -0.01)\n\tforcefield_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/fragmentation_round.gd",
    "content": "extends ItemBehavior\n\n\nvar frag_pt: ProjectileType\nvar frag_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: PT_Hit() in original script\nfunc frag_pt_on_hit(P: Projectile, U: Unit):\n\tif U == null:\n\t\treturn\n\n\tvar T: Tower = P.get_caster()\n\tvar B: Buff = U.get_buff_of_type(frag_bt)\n\n\tif B != null:\n\t\tP.user_real = P.user_real * 1.40\n\n\tvar buff_level: int\n\tif B != null:\n\t\tbuff_level = B.get_level()\n\telse:\n\t\tbuff_level = 0\n\t\n\tT.do_attack_damage(U, P.user_real * 0.45, 1.0)\n\n\tfrag_bt.apply(T, U, buff_level)\n\n\n# NOTE: BT_DMG() in original script\nfunc frag_bt_on_damaged(event: Event):\n\tif event.is_main_target() == false && event.is_spell_damage() == false:\n\t\tevent.damage = event.damage * 1.40\n\n\nfunc item_init():\n\tfrag_pt = ProjectileType.create(\"path_to_projectile_sprite\", 0.0, 1000.0, self)\n\tfrag_pt.enable_homing(frag_pt_on_hit, 0.1)\n\n\tfrag_bt = BuffType.new(\"frag_bt\", 5.0, 0.0, false, self)\n\tfrag_bt.set_buff_icon(\"res://resources/icons/generic_icons/mine_explosion.tres\")\n\tfrag_bt.set_buff_tooltip(tr(\"7ZPH\"))\n\tfrag_bt.add_event_on_damaged(frag_bt_on_damaged)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Unit = item.get_carrier()\n\n\tvar fragmentation_round_chance: float = 0.40\n\n\tif !tower.calc_chance(fragmentation_round_chance):\n\t\treturn\n\n\tCombatLog.log_item_ability(item, null, \"Fragmentation Round\")\n\n\tvar I: Iterate\n\tvar U: Unit\n\tvar Targ: Unit\n\tvar i: int = 2\n\n\tif event.is_main_target():\n\t\tTarg = event.get_target()\n\t\tI = Iterate.over_units_in_range_of_unit(item.get_carrier(), TargetType.new(TargetType.CREEPS), Targ, 500)\n\n\t\twhile true:\n\t\t\tU = I.next()\n\n\t\t\tif U == null:\n\t\t\t\tbreak\n\n\t\t\tif U != Targ:\n\t\t\t\tvar projectile: Projectile = Projectile.create_from_unit_to_unit(frag_pt, item.get_carrier(), 1.0, 1.0, Targ, U, true, false, true)\n\t\t\t\tprojectile.user_real = event.damage\n\t\t\t\ti = i - 1\n\n\t\t\t\tif i == 0:\n\t\t\t\t\tbreak\n"
  },
  {
    "path": "src/items/item_behaviors/frog_pipe.gd",
    "content": "extends ItemBehavior\n\n# NOTE: in original script, collision range was defined by\n# calling setCollisionParameters. Removed that because it's\n# not needed. Can define when set_collision_enabled() is\n# called.\n\n# NOTE: I modified the coloring of projectiles. Set initial\n# color to blue and then when projectile starts homing make\n# it bluer. Original script uses a green frog model which\n# turns blueish later.\n\n\nvar frog_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n# NOTE: deem_FrogAttack() in original script\nfunc daem_frog_attack(tower: Tower, target: Unit, temp: int):\n\tvar x: float = tower.get_x()\n\tvar y: float = tower.get_y()\n\n\tvar angle: float = rad_to_deg(atan2(target.get_y() - y, target.get_x() - x))\n\n\tvar p: Projectile = Projectile.create(frog_pt, tower, 0, 0, Vector3(x + Globals.synced_rng.randi_range(-40, 40), y + Globals.synced_rng.randi_range(-40, 40), 5.0), angle + temp)\n\tp.set_color(Color8(100, 255, 100, 255))\n\tp.user_int = temp\n\tp.user_real = tower.get_current_attack_damage_with_bonus()\n\tp.user_real2 = tower.calc_attack_multicrit_no_bonus()\n\n\n# NOTE: deem_FrogCollision() in original script\nfunc frog_pt_on_hit(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar tower: Tower = p.get_caster()\n\ttower.do_attack_damage(target, p.user_real, p.user_real2)\n\n\nfunc item_init():\n\tfrog_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 3700.0, 500.0, self)\n\tfrog_pt.enable_collision(frog_pt_on_collision, 190, TargetType.new(TargetType.CREEPS), false)\n\tfrog_pt.enable_homing(frog_pt_on_hit, 0)\n\tfrog_pt.enable_periodic(frog_pt_periodic, 0.60)\n\tfrog_pt.set_acceleration(-36)\n\tfrog_pt.disable_explode_on_hit()\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar target: Unit = event.get_target()\n\tvar frog_chance: float = 0.2\n\n\tif !tower.calc_chance(frog_chance):\n\t\treturn\n\n\tif target.get_size() != CreepSize.enm.AIR:\n\t\tCombatLog.log_ability(tower, target, \"Frog Piper\")\n\t\t\n\t\tdaem_frog_attack(item.get_carrier(), target, Globals.synced_rng.randi_range(-40, -20))\n\t\tdaem_frog_attack(item.get_carrier(), target, Globals.synced_rng.randi_range(-20, -0))\n\t\tdaem_frog_attack(item.get_carrier(), target, Globals.synced_rng.randi_range(0, 20))\n\t\tdaem_frog_attack(item.get_carrier(), target, Globals.synced_rng.randi_range(20, 40))\n\n\n# NOTE: deem_FrogHome() in original script\nfunc frog_pt_on_collision(p: Projectile, target: Unit):\n\tif target.get_size() == CreepSize.enm.AIR:\n\t\treturn\n\n\tp.set_speed(500)\n\tp.set_collision_enabled(false)\n\tp.set_homing_target(target)\n\tp.set_acceleration(8)\n\tp.set_color(Color8(100, 220, 150, 255))\n\tp.disable_periodic()\n\tp.set_remaining_lifetime(3.0)\n\n\n# NOTE: deem_FrogPeriodic() in original script\nfunc frog_pt_periodic(projectile: Projectile):\n\tprojectile.user_int *= -1\n\tprojectile.set_speed(500)\n\tprojectile.set_direction(projectile.get_direction() + projectile.user_int)\n"
  },
  {
    "path": "src/items/item_behaviors/glaive_of_supreme_follow_up.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: original script uses buff.userInt as a flag so that\n# attack() f-n does nothing the first time it is called and\n# does something the second time it is called. This is to\n# solve some issue which exists in original script engine.\n# In current engine this is not needed and causes a bug\n# where follow up attack to happen twice. So it was removed.\n\n\nvar followup_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n# NOTE: attack() in original\nfunc followup_bt_on_attack(event: Event):\n\tvar B: Buff = event.get_buff()\n\tvar t: Tower = B.get_buffed_unit()\n\n\tt.add_modified_attack_crit(0.00, 0.5 + t.get_level() / 100.0)\n\tB.remove_buff()\n\n\nfunc item_init():\n\tfollowup_bt = BuffType.new(\"followup_bt\", 30, 0, true, self)\n\tfollowup_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\tfollowup_bt.set_buff_tooltip(tr(\"F6D7\"))\n\tfollowup_bt.add_event_on_attack(followup_bt_on_attack)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 3.0, 0.04)\n\tfollowup_bt.set_buff_modifier(mod)\n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif !tower.calc_chance(0.1 + 0.004 * tower.get_level()):\n\t\treturn\n\n\tCombatLog.log_item_ability(item, null, \"Follow up\")\n\n\tfollowup_bt.apply(item.get_carrier(), item.get_carrier(), item.get_carrier().get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/golden_decoration.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar interest_bonus_label: String = tr(\"Q7IE\")\n\tmultiboard.set_key(0, interest_bonus_label)\n\n\nfunc on_create():\n\titem.user_real = 0\n\n\nfunc on_drop():\n\titem.get_player().modify_interest_rate(-item.user_real)\n\n\nfunc on_pickup():\n\tvar tower: Tower = item.get_carrier()\n\titem.user_real = 0.004 * (tower.get_gold_cost() / 2500.0)\n\titem.get_player().modify_interest_rate(item.user_real)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_percent(item.user_real, 3))\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/golden_trident.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar gold_bonus_label: String = tr(\"VA0V\")\n\tmultiboard.set_key(1, gold_bonus_label)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar gold_bonus: float = 2.0\n\n\tif event.get_number_of_crits() > 0:\n\t\tgold_bonus = gold_bonus * event.get_number_of_crits() * tower.get_base_attack_speed() * tower.get_prop_bounty_received()\n\n\t\ttower.get_player().give_gold(int(gold_bonus), tower, true, true)\n\t\titem.user_real += gold_bonus\n\n\nfunc on_create():\n\titem.user_real = 0.00\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_float(item.user_real, 1))\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/granite_hammer.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\titem.user_int = item.user_int + 1\n\n\tif item.user_int == 5:\n\t\tCombatLog.log_item_ability(item, null, \"Heavy Weapon\")\n\t\t\n\t\ttower.add_attack_crit()\n\n\t\titem.user_int = 0\n\n\nfunc on_pickup():\n\titem.user_int = 1\n"
  },
  {
    "path": "src/items/item_behaviors/grounding_gloves.gd",
    "content": "extends ItemBehavior\n\n\nvar roots_bt: BuffType\nvar cooldown_bt: BuffType\nvar blizzard_st: SpellType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: overgrowth_dmg() in original script\nfunc blizzard_st_on_damage(event: Event, dummy: DummyUnit):\n\tvar target: Creep = event.get_target()\n\tvar tower: Tower = dummy.get_caster()\n\tevent.damage = 0\n\n\tif target.get_buff_of_type(cooldown_bt) == null:\n\t\troots_bt.apply(tower, target, 0)\n\n\t\tif target.get_size() < CreepSize.enm.BOSS:\n\t\t\tcooldown_bt.apply(tower, target, 0)\n\t\telse:\n\t\t\tcooldown_bt.apply_only_timed(tower, target, -1)\n\n\nfunc periodic_dmg(event: Event):\n\tvar B: Buff = event.get_buff()\n\tB.get_caster().do_spell_damage(B.get_buffed_unit(), 4500, B.get_caster().calc_spell_crit_no_bonus())\n\n\nfunc item_init():\n\troots_bt = CbStun.new(\"roots_bt\", 1.8, 0, false, self)\n\troots_bt.add_periodic_event(periodic_dmg, 1.0)\n\troots_bt.set_buff_icon(\"res://resources/icons/generic_icons/perpendicular_rings.tres\")\n\n\tcooldown_bt = BuffType.new(\"cooldown_bt\", 4.8, 0.0, false, self)\n\tcooldown_bt.set_hidden()\n\n\tblizzard_st = SpellType.new(SpellType.Name.BLIZZARD, 4.0, self)\n\tblizzard_st.set_damage_event(blizzard_st_on_damage)\n\tblizzard_st.data.blizzard.damage = 0\n\tblizzard_st.data.blizzard.radius = 200\n\tblizzard_st.data.blizzard.wave_count = 3\n\t\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar tower: Tower = item.get_carrier()\n\n\tif event.is_main_target() && tower.calc_chance(tower.get_base_attack_speed() * 0.06):\n\t\tCombatLog.log_item_ability(item, null, \"Entangling Roots\")\n\t\n\t\tblizzard_st.point_cast_from_target_on_target(tower, target, 1.0, 1.0)\n\t\tvar effect: int = Effect.create_animated(\"res://src/effects/flower_aura.tscn\", Vector3(target.get_x(), target.get_y(), 0), 0)\n\t\tEffect.set_scale(effect, 1.5)\n\t\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\t\tEffect.set_lifetime(effect, 2.5)\n"
  },
  {
    "path": "src/items/item_behaviors/haunted_hand.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: reworked original script. Used the same logic as in\n# \"RottedFlashingGrave\" tower which also attacks random\n# targets.\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc load_specials(modifier: Modifier):\n\tmodifier.add_modification(ModificationType.enm.MOD_DMG_TO_MAGIC, 0.10, 0.01)\n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar iterator: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), tower.get_range())\n\tvar random_unit: Unit = iterator.next_random()\n\n\tif random_unit == null:\n\t\treturn\n\n\ttower.issue_target_order(random_unit)\n"
  },
  {
    "path": "src/items/item_behaviors/helm_of_insanity.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_autocast(_event: Event):\n\titem.user_int = 0\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif item.user_int >= 12 && item.user_int < 28:\n\t\tevent.damage = event.damage * 0.5\n\n\t\tif event.is_main_target():\n\t\t\tvar exhausted_text: String = tr(\"LW28\")\n\t\t\ttower.get_player().display_small_floating_text(exhausted_text, tower, Color8(255, 150, 0), 30)\n\t\t\titem.user_int = item.user_int + 1\n\n\tif item.user_int < 12:\n\t\tevent.damage = event.damage * 2\n\n\t\tif event.is_main_target():\n\t\t\tvar insane_text: String = tr(\"ELMO\")\n\t\t\ttower.get_player().display_small_floating_text(insane_text, tower, Color8(255, 150, 0), 30)\n\t\t\titem.user_int = item.user_int + 1\n\n\nfunc on_create():\n\titem.user_int = 50\n\n\nfunc on_drop():\n\titem.user_int = 50\n"
  },
  {
    "path": "src/items/item_behaviors/hippogryph_egg.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where\n# do_spell_damage_aoe() received args in incorrect order.\n# \"crit_ratio\" and \"sides_ratio\" were swapped. This caused\n# the damage from this item to always crit.\n\n\nvar hippo_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n# NOTE: hippoHit() in original script\nfunc hippo_pt_on_hit(p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar caster: Unit = p.get_caster()\n\n\tif creep.is_immune() == false:\n\t\tcaster.do_spell_damage_aoe(Vector2(p.get_x(), p.get_y()), 200, 1250 + caster.get_level() * 50, caster.calc_spell_crit_no_bonus(), 1.0)\n\t\tEffect.create_scaled(\"res://src/effects/ancient_protector_missile.tscn\", p.get_position_wc3(), 0, 2)\n\n\nfunc item_init():\n\thippo_pt = ProjectileType.create(\"path_to_projectile_sprite\", 20, 800, self)\n\thippo_pt.disable_explode_on_hit()\n\thippo_pt.disable_explode_on_expiration()\n\thippo_pt.enable_homing(hippo_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar twr: Tower = item.get_carrier()\n\tvar p: Projectile\n\n\tif twr.calc_chance((0.15 * twr.get_base_attack_speed())):\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Hippogryph Young\")\n\t\tp = Projectile.create_from_unit_to_unit(hippo_pt, twr, 1, twr.calc_spell_crit_no_bonus(), twr, event.get_target(), true, false, false)\n\t\tp.set_projectile_scale(0.6)\n"
  },
  {
    "path": "src/items/item_behaviors/holy_hand_grenade.gd",
    "content": "extends ItemBehavior\n\n\nvar grenade_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: hit() in original script\nfunc grenade_pt_on_hit(P: Projectile, U: Unit):\n\tif U == null:\n\t\treturn\n\n\tvar C: Tower = P.get_caster()\n\n\tC.do_spell_damage_aoe_unit(U, 400, P.user_real, C.calc_spell_crit_no_bonus(), 0)\n\tEffect.create_scaled(\"res://src/effects/faerie_dragon_missile.tscn\", Vector3(U.get_x(), U.get_y(), 8), 0, 1)\n\n\nfunc item_init():\n\tgrenade_pt = ProjectileType.create(\"path_to_projectile_sprite\", 50.0, 1000.0, self)\n\tgrenade_pt.enable_homing(grenade_pt_on_hit, 0.0)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar chance: float = 0.15\n\tvar r: float = event.damage * (0.75 + 0.01 * tower.get_level())\n\tvar P: Projectile\n\tvar target: Creep = event.get_target()\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tif event.is_main_target():\n\t\tCombatLog.log_item_ability(item, null, \"Big Badaboom\")\n\t\t\n\t\tif target.get_category() == CreepCategory.enm.UNDEAD:\n\t\t\tr = r * 1.5\n\n\t\tP = Projectile.create_from_unit_to_unit(grenade_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, event.get_target(), true, false, false)\n\t\tP.user_real = r\n"
  },
  {
    "path": "src/items/item_behaviors/item_template_advanced.gd",
    "content": "extends ItemBehavior\n\n# NOTE: not a real item script, used as a template for item\n# scripts. Use for advanced items that have special effects.\n\n\n# func load_triggers(triggers: BuffType):\n# \ttriggers.add_event_on_damage(on_damage)\n# \ttriggers.add_periodic_event(periodic, 5)\n\n\n# func item_init():\n# \texample_bt = BuffType.new(\"example_bt\", 5, 0, true, self)\n# \texample_bt.set_buff_icon(\"res://resources/icons/generic_icons/egg.tres\")\n# \texample_bt.set_buff_tooltip(tr(\"AAAA\"))\n# \tvar mod: Modifier = Modifier.new()\n# \tmod.add_modification(ModificationType.enm.MOD_ARMOR, 0.0, 0.0)\n# \texample_bt.set_buff_modifier(mod)\n\n\n# func on_damage(event: Event):\n#\tpass\n\n\n# func on_autocast(event: Event):\n#\tpass\n"
  },
  {
    "path": "src/items/item_behaviors/jah_rakals_fury.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar attack_speed_increase_label: String = tr(\"RWPC\")\n\tmultiboard.set_key(0, attack_speed_increase_label)\n\n\nfunc on_attack(event: Event):\n\tif item.user_int == event.get_target().get_instance_id():\n# \t\t100% attack speed limit\n\t\tif item.user_real != 1.00 && item.user_real + 0.02 > 1.00:\n#\t\t\tAdd the remaining bonus (99% -> 101%; limit -> 100%; add 100% - 99% = 1%)\n\t\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATTACKSPEED, 1.00 - item.user_real)\n\t\t\titem.user_real = 1.00\n\t\telse:\n#\t\t\tAdd bonus\n\t\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.02)\n\t\t\titem.user_real = item.user_real + 0.02\n\telse:\n#\t\tSave current target\n\t\titem.user_int = event.get_target().get_instance_id()\n#\t\tTemp variable to store the current bonus\n\t\titem.user_real2 = item.user_real\n#\t\tCalculate the new bonus (Current bonus * (50% + towerlevel%))\n\t\titem.user_real = item.user_real * (50.0 + item.get_carrier().get_level()) / 100\n#\t\tChange the bonus (new Bonus - current Bonus)\n\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATTACKSPEED, item.user_real - item.user_real2)\n\n\nfunc on_create():\n\titem.user_real = 0.00\n\titem.user_int = 0\n\n\nfunc on_drop():\n# \tRemove bonus\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATTACKSPEED, -item.user_real)\n\n\nfunc on_pickup():\n#\tAdd bonus\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATTACKSPEED, item.user_real)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar attack_speed_bonus_text: String = Utils.format_percent(item.user_real, 0)\n\tmultiboard.set_value(0, attack_speed_bonus_text)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/jewels_of_the_moon.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Day/night mechanic is not\n# implemented so changed this item effect to be average\n# between day and night. Original script gives 2 during day\n# and 4 at night, so average it down to 3.\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 15)\n\n\nfunc periodic(_event: Event):\n\tvar target_effect: int\n\tvar tower: Unit = item.get_carrier()\n\n\ttarget_effect = Effect.create_scaled(\"res://src/effects/dispel_magic_target.tscn\", tower.get_position_wc3(), 0, 2)\n\tEffect.set_lifetime(target_effect, 2.0)\n\n\tCombatLog.log_item_ability(item, null, \"Celestial Wisdom\")\n\ttower.add_exp(3.0)\n"
  },
  {
    "path": "src/items/item_behaviors/jungle_stalkers_doll.gd",
    "content": "extends ItemBehavior\n\n\nvar enraged_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\tenraged_bt = BuffType.new(\"enraged_bt\", 0, 0, true, self)\n\tenraged_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tenraged_bt.set_buff_tooltip(tr(\"JE2F\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.20, 0.004)\n\tenraged_bt.set_buff_modifier(mod)\n\n\nfunc on_kill(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif tower.get_buff_of_type(enraged_bt) == null:\n\t\tSFX.sfx_at_unit(SfxPaths.TELEPORT_BASS, event.get_target())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/stampede_missile_death.tscn\", event.get_target())\n\t\tenraged_bt.apply_custom_timed(tower, tower, tower.get_level(), 3.0)\n"
  },
  {
    "path": "src/items/item_behaviors/libram_of_grace.gd",
    "content": "extends ItemBehavior\n\n\nvar grace_bt: BuffType\n\n\nfunc item_init():\n\tgrace_bt = BuffType.create_aura_effect_type(\"grace_bt\", true, self)\n\tgrace_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\tgrace_bt.set_buff_tooltip(tr(\"I4A3\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, 0.1, 0.004)\n\tgrace_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/lich_mask.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_attack(_event: Event):\n\titem.user_real = item.user_real + 50.0 + 1.0 * item.get_carrier().get_level()\n\titem.set_charges(int(item.user_real))\n\n\nfunc on_damage(event: Event):\n\tvar T: Tower = item.get_carrier()\n\tvar C: Creep = event.get_target()\n\n\tif item.user_real >= 100.0:\n\t\tevent.damage = event.damage / AttackType.get_damage_against(T.get_attack_type(), C.get_armor_type()) * AttackType.get_damage_against(AttackType.enm.DECAY, C.get_armor_type())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/death_and_decay.tscn\", C)\n\t\tSFX.sfx_at_unit(SfxPaths.GHOST_EXHALE, C)\n\t\titem.user_real = item.user_real - 100.0\n\t\titem.set_charges(int(item.user_real))\n\n\nfunc on_pickup():\n\titem.user_real = 0.0\n\titem.set_charges(0)\n"
  },
  {
    "path": "src/items/item_behaviors/liquid_gold.gd",
    "content": "extends ItemBehavior\n\n\nvar drunk_bt: BuffType\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n# NOTE: drolDrunk() in original script\nfunc drunk_bt_on_expire(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar tower: Unit = b.get_caster()\n\tstun_bt.apply_only_timed(tower, tower, 3 - tower.get_level() * 0.1)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\t\n\tdrunk_bt = BuffType.new(\"drunk_bt\", 8, 0, false, self)\n\tdrunk_bt.set_buff_icon(\"res://resources/icons/generic_icons/perpendicular_rings.tres\")\n\tdrunk_bt.set_buff_tooltip(tr(\"W9YO\"))\n\tdrunk_bt.add_event_on_expire(drunk_bt_on_expire)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.30, 0.01)\n\tdrunk_bt.set_buff_modifier(mod)\n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar speed: float = tower.get_base_attack_speed()\n\n\tif tower.calc_bad_chance(0.1 * speed):\n\t\tCombatLog.log_item_ability(item, null, \"Hangover\")\n\t\tdrunk_bt.apply(tower, tower, tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/lucky_gem.gd",
    "content": "extends ItemBehavior\n\n\nvar stun_bt: BuffType\nvar slow_bt: BuffType\nvar armor_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\t\n\tslow_bt = BuffType.new(\"slow_bt\", 0, 0, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"KRA1\"))\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0, -0.001)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\n\tarmor_bt = BuffType.new(\"armor_bt\", 0, 0, false, self)\n\tarmor_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tarmor_bt.set_buff_tooltip(tr(\"PJYW\"))\n\tvar armor_bt_mod: Modifier = Modifier.new()\n\tarmor_bt_mod.add_modification(ModificationType.enm.MOD_ARMOR, 0, -1)\n\tarmor_bt.set_buff_modifier(armor_bt_mod)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar a: int = Globals.synced_rng.randi_range(0, 4)\n\tvar tower: Tower = item.get_carrier()\n\tvar speed: float = tower.get_base_attack_speed()\n\n\tif tower.calc_chance(0.20 * speed) && event.is_main_target() == true:\n\t\t\n\t\tif a < 1:\n\t\t\tCombatLog.log_item_ability(item, null, \"Stun!\")\n\t\t\tstun_bt.apply_only_timed(tower, target, 0.5)\n\t\t\tvar stun_text: String = tr(\"NMYW\")\n\t\t\ttower.get_player().display_small_floating_text(stun_text, tower, Color8(255, 165, 0), 30)\n\t\telif a < 2:\n\t\t\tCombatLog.log_item_ability(item, null, \"Slow!\")\n\t\t\tslow_bt.apply_custom_timed(tower, target, 100, 3)\n\t\t\tvar slow_text: String = tr(\"Z5NR\")\n\t\t\ttower.get_player().display_small_floating_text(slow_text, tower, Color8(255, 165, 0), 30)\n\t\telif a < 3:\n\t\t\tCombatLog.log_item_ability(item, null, \"Gold!\")\n\t\t\ttower.get_player().give_gold(10, tower, true, true)\n\t\t\tvar gold_text: String = tr(\"S88X\")\n\t\t\ttower.get_player().display_small_floating_text(gold_text, tower, Color8(255, 165, 0), 30)\n\t\telif a < 4:\n\t\t\tCombatLog.log_item_ability(item, null, \"Exp!\")\n\t\t\ttower.add_exp(1.0)\n\t\t\tvar exp_text: String = tr(\"NUE1\")\n\t\t\ttower.get_player().display_small_floating_text(exp_text, tower, Color8(255, 165, 0), 30)\n\t\telif a < 5:\n\t\t\tCombatLog.log_item_ability(item, null, \"Armor!\")\n\t\t\tarmor_bt.apply_custom_timed(tower, target, 5, 3)\n\t\t\tvar armor_text: String = tr(\"CC5X\")\n\t\t\ttower.get_player().display_small_floating_text(armor_text, tower, Color8(255, 165, 0), 30)\n"
  },
  {
    "path": "src/items/item_behaviors/lunar_essence.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_create():\n\titem.user_real = 200\n\n\nfunc on_drop():\n\tvar tower: Tower = item.get_carrier()\n\titem.user_real = tower.remove_exp_flat(200)\n\n\nfunc on_pickup():\n\tvar tower: Tower = item.get_carrier()\n\tvar r: float = item.user_real\n\tif r > 0:\n\t\ttower.add_exp_flat(r)\n"
  },
  {
    "path": "src/items/item_behaviors/magic_conductor.gd",
    "content": "extends ItemBehavior\n\nvar conduction_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_spell_targeted(on_spell_target)\n\n\nfunc item_init():\n\tconduction_bt = BuffType.new(\"conduction_bt\", 0.0, 0.0, true, self)\n\tconduction_bt.set_buff_icon(\"res://resources/icons/generic_icons/rolling_energy.tres\")\n\tconduction_bt.set_buff_tooltip(tr(\"0IQV\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.20, 0.005)\n\tconduction_bt.set_buff_modifier(mod)\n\n\nfunc on_spell_target(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar lvl: int = tower.get_level()\n\n\tCombatLog.log_item_ability(item, null, \"Conduct Magic\")\n\tconduction_bt.apply_custom_timed(tower, tower, lvl, 10.0)\n"
  },
  {
    "path": "src/items/item_behaviors/magic_gloves.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\ttower.do_spell_damage(event.get_target(), (100 + (tower.get_level() * 5)) * tower.get_base_attack_speed(), tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/items/item_behaviors/magic_hammer.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_spell_casted(on_spell_cast)\n\n\nfunc on_pickup():\n\titem.user_int = 0\n\n\nfunc on_spell_cast(_event: Event):\n\titem.user_int = item.user_int + 1\n\n\tif item.user_int >= 5:\n\t\tCombatLog.log_item_ability(item, null, \"Magic Weapon\")\n\t\titem.get_carrier().add_spell_crit()\n\t\titem.user_int = 0\n"
  },
  {
    "path": "src/items/item_behaviors/magic_link.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_autocast(event: Event):\n\tevent.get_target().add_exp_flat(item.get_carrier().remove_exp_flat(30))\n"
  },
  {
    "path": "src/items/item_behaviors/magnetic_field.gd",
    "content": "extends ItemBehavior\n\n\nvar magnetic_bt: BuffType\n\n\nfunc item_init():\n\tmagnetic_bt = BuffType.create_aura_effect_type(\"magnetic_bt\", true, self)\n\tmagnetic_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tmagnetic_bt.set_buff_tooltip(tr(\"C14B\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.15, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_BUFF_DURATION, 0.1, 0.0)\n\tmagnetic_bt.set_buff_modifier(mod)\n\t"
  },
  {
    "path": "src/items/item_behaviors/mana_stone.gd",
    "content": "extends ItemBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/rolling_energy.tres\")\n\taura_bt.set_buff_tooltip(tr(\"2UJE\"))\n\tvar mod: Modifier = Modifier.new() \n\tmod.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, 0.075, 0.0) \n\taura_bt.set_buff_modifier(mod)\n\n\nfunc on_attack(_event: Event):\n\titem.user_int = item.user_int + 1\n\n\tif item.user_int == 3:\n\t\titem.get_carrier().add_mana_perc(0.01)\n\t\titem.user_int = 0\n\n\nfunc on_pickup():\n\titem.user_int = 0\n\n\nfunc on_kill(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tEffect.create_scaled(\"res://src/effects/replenish_mana.tscn\", tower.get_position_wc3(), 0.0, 1)\n\n"
  },
  {
    "path": "src/items/item_behaviors/medallion_of_opulence.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier() \n\tvar speed: float = tower.get_base_attack_speed()\n\n\tif tower.calc_chance(0.2 * speed) == true:\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Greed Is Good\")\n\t\ttower.do_spell_damage(event.get_target(), item.get_player().get_gold() * (0.10), tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/items/item_behaviors/mefis_rocket.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] changed the 2nd \"one_shot\"\n# arg passed to enable_advanced(). Original script passes\n# \"true\" but this causes the tower to not fire projectiles\n# in youtd2 engine. Not sure if the JASS engine processes\n# the \"one_shot\" arg in some weird way.\n\n\nvar rocket_pt: ProjectileType\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 0.1)\n\n\n# NOTE: hitPT() in original script\nfunc rocket_pt_on_hit(P: Projectile, U: Unit):\n\tif U == null:\n\t\treturn\n\n\tvar T: Tower = P.get_caster()\n\tT.do_custom_attack_damage(U, P.user_real, T.calc_attack_multicrit(0, 0, 0), P.user_int)\n\n\nfunc item_init():\n\trocket_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\trocket_pt.set_event_on_interpolation_finished(rocket_pt_on_hit)\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar damage_label: String = tr(\"VLPO\")\n\tmultiboard.set_key(0, damage_label)\n\n\nfunc on_pickup():\n\tvar T: Tower = item.get_carrier()\n\n\tif T.get_attack_type() != AttackType.enm.ARCANE:\n\t\titem.user_int = T.get_attack_type()\n\telse:\n\t\titem.user_int = AttackType.enm.ESSENCE\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar tower: Tower = item.get_carrier()\n\tvar dmg: float = tower.get_current_attack_damage_with_bonus() * ( tower.get_prop_spell_damage_dealt() * (0.2 + 0.008 * tower.get_level()))\n\tmultiboard.set_value(0, Utils.format_float(dmg, 0))\n\n\treturn multiboard\n\n\nfunc periodic(event: Event):\n\tvar T: Tower = item.get_carrier()\n\tvar I: Iterate = Iterate.over_units_in_range_of_caster(T, TargetType.new(TargetType.CREEPS), T.get_range())\n\tvar U: Unit\n\tvar dmg: float\n\tvar P: Projectile\n\n\tevent.enable_advanced(T.get_current_attack_speed(), false)\n\n\twhile true:\n\t\tU = I.next()\n\n\t\tif U == null:\n\t\t\treturn\n\n\t\tif U.is_immune():\n\t\t\tbreak\n\n\tdmg = T.get_current_attack_damage_with_bonus() * (T.get_prop_spell_damage_dealt() * (0.2 + 0.008 * T.get_level()))\n\tP = Projectile.create_linear_interpolation_from_unit_to_unit(rocket_pt, T, 1.0, 1.0, T, U, 0.35, true)\n\tP.user_real = dmg\n\tP.user_int = item.user_int\n"
  },
  {
    "path": "src/items/item_behaviors/mighty_trees_acorns.gd",
    "content": "extends ItemBehavior\n\n\nvar charitable_bt: BuffType\n\n\nfunc item_init():\n\tcharitable_bt = BuffType.create_aura_effect_type(\"charitable_bt\", true, self)\n\tcharitable_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\tcharitable_bt.set_buff_tooltip(tr(\"FCP1\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.02, 0.004)\n\tmod.add_modification(ModificationType.enm.MOD_MANA_PERC, 0.02, 0.004)\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.02, 0.004)\n\tcharitable_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/mindleecher.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_autocast(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 450)\n\tvar next: Unit\n\n\twhile true:\n\t\tnext = it.next_random()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next != tower && next.get_exp() > 0:\n\t\t\tbreak\n\n\tif next != null:\n\t\ttower.add_exp_flat(next.remove_exp_flat(Globals.synced_rng.randi_range(15, 60)))\n\t\tEffect.create_simple_at_unit(\"res://src/effects/animated_dead_target.tscn\", next, Unit.BodyPart.HEAD)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", next, Unit.BodyPart.HEAD)\n"
  },
  {
    "path": "src/items/item_behaviors/mine_cart.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_consume():\n\titem.get_player().modify_income_rate(0.10)\n"
  },
  {
    "path": "src/items/item_behaviors/mini_forest_troll.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Mini Furbolg\"=>\"Mini Forest Troll\"\n\n\nvar rampage_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\trampage_bt = BuffType.new(\"rampage_bt\", 4, 0, true, self)\n\trampage_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\trampage_bt.set_buff_tooltip(tr(\"R5MU\"))\n\tvar mod: Modifier = Modifier.new() \n\tmod.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 1.00, 0.0) \n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.25, 0.0) \n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.05, 0.0) \n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.40, 0.0) \n\trampage_bt.set_buff_modifier(mod) \n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif !(tower.get_buff_of_type(rampage_bt) != null) && tower.calc_chance(0.14 * tower.get_base_attack_speed()):\n\t\tCombatLog.log_item_ability(item, null, \"Rampage\")\n\t\trampage_bt.apply(tower, tower, tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/mining_tools.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 15)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar gold_found_label: String = tr(\"H12F\")\n\tmultiboard.set_key(0, gold_found_label)\n\n\nfunc on_create():\n\titem.user_int = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar gold_found_text: String = Utils.format_float(item.user_int, 0)\n\tmultiboard.set_value(0, gold_found_text)\n\n\treturn multiboard\n\n\nfunc periodic(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar target_effect: int\n\n\ttarget_effect = Effect.create_scaled(\"res://src/effects/ancient_protector_missile.tscn\", tower.get_position_wc3(), 0, 2)\n\tEffect.set_lifetime(target_effect, 0.1)\n\t\n\tif tower.calc_chance(0.40 + tower.get_level() * 0.02):\n\t\tCombatLog.log_item_ability(item, null, \"Mining Success\")\n\t\t\n\t\tif tower.get_level() < 25:\n\t\t\ttower.get_player().give_gold(3, tower, false, true)\n\t\t\titem.user_int = item.user_int + 3\n\t\telse:\n\t\t\ttower.get_player().give_gold(4, tower, false, true)\n\t\t\titem.user_int = item.user_int + 4\n\telse:\n\t\tCombatLog.log_item_ability(item, null, \"Mining Fail\")\n"
  },
  {
    "path": "src/items/item_behaviors/mystical_shell.gd",
    "content": "extends ItemBehavior\n\n\nvar resonance_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tresonance_bt = BuffType.new(\"resonance_bt\", 5, 0, false, self)\n\tresonance_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tresonance_bt.set_buff_tooltip(tr(\"CRZY\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.15, 0.0)\n\tresonance_bt.set_buff_modifier(mod)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif tower.calc_chance(0.10 * tower.get_base_attack_speed()):\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Resonance\")\n\t\tresonance_bt.apply(tower, event.get_target(), tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/nerminds_eye.gd",
    "content": "extends ItemBehavior\n\n\n# var nermind_bt: BuffType\n\n\n# func item_init():\n# \tnermind_bt = MagicalSightBuff.new(\"nermind_bt\", 750, self)\n# \tnermind_bt.set_buff_tooltip(tr(\"L2EN\"))\n\n\n# func on_pickup():\n# \tvar carrier: Unit = item.get_carrier()\n# \tnermind_bt.apply_to_unit_permanent(carrier, carrier, 0)\t\n"
  },
  {
    "path": "src/items/item_behaviors/never-ending_keg.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tif Utils.rand_chance(Globals.synced_rng, 0.10):\n\t\tCombatLog.log_item_ability(item, null, \"Drunk!\")\n\t\titem.get_carrier().get_player().display_small_floating_text(tr(\"FLOATING_TEXT_MISS\"), item.get_carrier(), Color8(255, 0, 0), 40.0)\n\t\tevent.damage = 0\n"
  },
  {
    "path": "src/items/item_behaviors/oil_of_lore.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_pickup():\n\tvar carrier: Tower = item.get_carrier()\n\tcarrier.add_exp_flat(60)\n"
  },
  {
    "path": "src/items/item_behaviors/old_hunter.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_damage)\n\n\nfunc on_damage(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar next: Tower\n\tvar in_range: Iterate\n\tvar count: int\n\n#\ttest if tower is minimum lvl 5\n\tif tower.get_level() >= 5:\n#\t\ttest, if there are towers in range\n\t\tin_range = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\t\tcount = min(5, in_range.count())\n\n\t\tif count > 0:\n\t\t\ttower.remove_exp_flat(count)\n\n\t\t\twhile true:\n\t\t\t\tnext = in_range.next_random()\n\n\t\t\t\tif next == null:\n\t\t\t\t\tbreak\n\n\t\t\t\tnext.add_exp_flat(1)\n\t\t\t\tEffect.create_simple_at_unit(\"res://src/effects/animated_dead_target.tscn\", next)\n\t\t\t\tcount = count - 1\n\n\t\t\t\tif count == 0:\n\t\t\t\t\tbreak\n"
  },
  {
    "path": "src/items/item_behaviors/optimists_preserved_face.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar health_ratio: float = target.get_health() / target.get_overall_health()\n\tevent.damage = event.damage * (1.75 - (1.25 * (1 - health_ratio)))\n"
  },
  {
    "path": "src/items/item_behaviors/orb_of_souls.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_create():\n\titem.user_real = 50\n\n\nfunc on_drop():\n\tvar tower: Tower = item.get_carrier()\n\titem.user_real = tower.remove_exp_flat(50)\n\n\nfunc on_pickup():\n\tvar tower: Unit = item.get_carrier()\n\tvar r: float = item.user_real\n\tif r > 0:\n\t\ttower.add_exp_flat(r)\n"
  },
  {
    "path": "src/items/item_behaviors/overcharge_shot.gd",
    "content": "extends ItemBehavior\n\n\nvar overcharge_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: PT_Hit() in original script\nfunc overcharge_pt_on_collision(P: Projectile, U: Unit):\n\tvar T: Tower\n\n\tif U.get_instance_id() != P.user_int:\n#\t\tNot the original target\n\t\tT = P.get_caster()\n\t\tT.do_attack_damage(U, P.user_real, T.calc_attack_multicrit(0, 0, 0))\n\n\nfunc item_init():\n\tovercharge_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 350.0, 1000.0, self)\n\tovercharge_pt.enable_collision(overcharge_pt_on_collision, 75.0, TargetType.new(TargetType.CREEPS), false)\n\n\nfunc on_damage(event: Event):\n\tvar angle: float\n\tvar C: Creep\n\tvar T: Tower\n\tvar P: Projectile\n\n\tif event.is_main_target():\n\t\tT = item.get_carrier()\n\t\tC = event.get_target()\n\t\tangle = rad_to_deg(atan2(C.get_y() - T.get_y(), C.get_x() - T.get_x()))\n\t\tP = Projectile.create_from_unit(overcharge_pt, T, C, angle, 1.0, 1.0)\n\t\tP.user_int = C.get_instance_id()\n\t\tP.user_real = T.get_current_attack_damage_with_bonus() * (0.35 + 0.006 * T.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/pendant_of_mana_supremacy.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_spell_casted(on_spell_cast)\n\n\nfunc on_create():\n\titem.user_int = 0\n\n\nfunc on_spell_cast(event: Event):\n\tvar T: Tower = item.get_carrier()\n\tvar t: Unit = T\n\n\tif !event.get_autocast_type().get_mana_cost() > 0.45:\n#\t  No cheating\n\t\treturn\n\n\tif item.user_int + 10.0 < Utils.get_time():\n\t\tif T.calc_chance(0.2):\n\t\t\tCombatLog.log_item_ability(item, null, \"Magical Greed\")\n\n\t\t\tt.set_mana(t.get_mana() + t.get_overall_mana() * (0.15 + T.get_level() * 0.006))\n\t\t\tEffect.create_simple_at_unit(\"res://src/effects/replenish_mana.tscn\", T)\n\t\t\titem.user_int = roundi(Utils.get_time())\n"
  },
  {
    "path": "src/items/item_behaviors/pendant_of_promptness.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif tower.subtract_mana(0.05 * tower.get_overall_mana(), false) == 0:\n\t\ttower.order_stop()\n"
  },
  {
    "path": "src/items/item_behaviors/phase_gloves.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar damage: float = event.damage\n\tvar creep: Unit = event.get_target()\n\tvar tower: Tower = item.get_carrier()\n\n\tevent.damage = damage * 0.7\n\ttower.do_spell_damage(creep, damage * 0.3, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/items/item_behaviors/plain_staff.gd",
    "content": "extends ItemBehavior\n\n"
  },
  {
    "path": "src/items/item_behaviors/pocket_emporium.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where this item would\n# accumulate hidden charges above 5. Bug happened because\n# the charge count was capped to 5 but the \"accumulator\"\n# variable was uncapped and would accumulate and then get\n# converted to real charges when item was used.\n\n\nvar wave_accumulator: int = 0\nvar charge_counter: int = 0\nvar last_accumulated_level: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 10)\n\n\nfunc on_autocast(_event: Event):\n\tvar i: int = item.get_charges()\n\tvar tower: Tower = item.get_carrier()\n\tvar p: Player = item.get_player()\n\tvar new: Item\n\tvar rnd: float = Globals.synced_rng.randi_range(0, 24)\n\tvar rarity: int = 1\n\n\tif rnd < 2:\n\t\trarity = 3\n\telif rnd < 6:\n\t\trarity = 2\n\n\tif i > 0 && item.get_player().get_gold() >= 500:\n\t\tvar random_item: int = ItemDropCalc.get_random_item_at_rarity_bounded(rarity, 14, 25)\n\t\t\n\t\tif random_item != 0:\n\t\t\tcharge_counter -= 1\n\t\t\tp.give_gold(-500, tower, false, true)\n\t\t\tnew = Item.create(tower.get_player(), random_item, tower.get_position_wc3())\n\t\t\tnew.fly_to_stash(0.0)\n\n\tcheck_level()\n\n\nfunc check_level():\n\tvar cur_level: int = item.get_player().get_team().get_level()\n\n\tif cur_level > last_accumulated_level:\n\t\twave_accumulator = wave_accumulator + (cur_level - last_accumulated_level)\n\n#\t\tNOTE: need to set accumulator to 0 here because if\n#\t\tcharge count is at 5, then it's capped out and we\n#\t\tneed to stop accumulating charges from waves.\n\t\tif charge_counter == 5:\n\t\t\twave_accumulator = 0\n\n\t\tlast_accumulated_level = cur_level\n\n\twhile true:\n\t\tif wave_accumulator < 5 || charge_counter >= 5:\n\t\t\tbreak\n\n\t\twave_accumulator = wave_accumulator - 5\n\t\tcharge_counter += 1\n\n\titem.set_charges(charge_counter)\n\n\nfunc on_create():\n\titem.set_charges(1)\n\twave_accumulator = 0\n\tcharge_counter = 1\n\tlast_accumulated_level = item.get_player().get_team().get_level()\n\tcheck_level()\n\n\nfunc on_drop():\n\tcheck_level()\n\n\nfunc on_pickup():\n\tcheck_level()\n\n\nfunc periodic(_event: Event):\n\tcheck_level()\n"
  },
  {
    "path": "src/items/item_behaviors/polarisator.gd",
    "content": "extends ItemBehavior\n\n\n"
  },
  {
    "path": "src/items/item_behaviors/portable_tombstone.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar kill_count_label: String = tr(\"UICO\")\n\tmultiboard.set_key(0, kill_count_label)\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar creep: Unit = event.get_target()\n\n\tif creep.get_size() < CreepSize.enm.CHAMPION && tower.calc_chance((0.0025 + (tower.get_level() * 0.0001)) * tower.get_base_attack_speed()):\n\t\tCombatLog.log_item_ability(item, null, \"Curse of the Grave\")\n\n\t\ttower.kill_instantly(creep)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", creep)\n\t\tSFX.sfx_at_unit(SfxPaths.WATER_SLASH, creep)\n\t\titem.user_int = item.user_int + 1\n\n\nfunc on_create():\n#\tnumber of innocent creeps slaughtered mercilessly.\n\titem.user_int = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar tombstone_kills_text: String = Utils.format_float(item.user_int, 0)\n\tmultiboard.set_value(0, tombstone_kills_text)\n\t\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/priest_figurine.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier() \n\tvar speed: float = tower.get_base_attack_speed()  \n\n\tif event.is_main_target() && tower.calc_chance(0.2 * speed) == true:\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Enlighten\")\n\t\tevent.get_target().modify_property(ModificationType.enm.MOD_EXP_GRANTED, 0.05)\n"
  },
  {
    "path": "src/items/item_behaviors/purifying_gloves.gd",
    "content": "extends ItemBehavior\n\n\nvar chain_lightning_st: SpellType\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n# NOTE: drol_chainStun() in original script\nfunc chain_lightning_st_on_damage(event: Event, d: DummyUnit):\n\tvar creep: Creep = event.get_target()\n\tvar creep_category: CreepCategory.enm = creep.get_category()\n\n\tif creep_category == CreepCategory.enm.UNDEAD || creep_category == CreepCategory.enm.ORC:\n\t\tstun_bt.apply_only_timed(d.get_caster(), event.get_target(), 0.5)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\t\n\tchain_lightning_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 5.0, self)\n\tchain_lightning_st.set_damage_event(chain_lightning_st_on_damage)\n\tchain_lightning_st.data.chain_lightning.damage = 250\n\tchain_lightning_st.data.chain_lightning.damage_reduction = 0.25\n\tchain_lightning_st.data.chain_lightning.chain_count = 3\n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar speed: float = tower.get_base_attack_speed()\n\n\tif tower.calc_chance(0.125 * speed):\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Purify\")\n\t\tchain_lightning_st.target_cast_from_caster(tower, event.get_target(), 1, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/items/item_behaviors/ritual_talisman.gd",
    "content": "extends ItemBehavior\n\n\nvar ritual_bt: BuffType\n\n\nfunc item_init():\n\tritual_bt = BuffType.new(\"ritual_bt\", 10, 0, true, self)\n\tritual_bt.set_buff_icon(\"res://resources/icons/generic_icons/moebius_trefoil.tres\")\n\tritual_bt.set_buff_tooltip(tr(\"49QO\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, 0.2, 0.008)\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.1, 0.002)\n\tritual_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/scroll_of_piercing_magic.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar t: Creep = event.get_target()\n\n\tif t.get_armor_type() == ArmorType.enm.SIF:\n\t\titem.get_carrier().do_spell_damage(t, event.damage * 0.25, item.get_carrier().calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/spell_breaker_target.tscn\", t)\n"
  },
  {
    "path": "src/items/item_behaviors/scroll_of_speed.gd",
    "content": "extends ItemBehavior\n\n\nvar speed_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 40)\n\n\nfunc item_init():\n\tspeed_bt = BuffType.new(\"speed_bt\", 0.0, 0.0, true, self)\n\tspeed_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\tspeed_bt.set_buff_tooltip(tr(\"P7Z5\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.1, 0)\n\tspeed_bt.set_buff_modifier(mod)\n\n\nfunc on_autocast(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar lvl: int = tower.get_level()\n\tvar it: Iterate\n\tvar next: Unit\n\n\tif item.user_int > 0:\n\t\tit = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 350)\n\n\t\twhile true:\n\t\t\tnext = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tspeed_bt.apply_custom_timed(tower, next, lvl * 2, 4.0)\n\n\t\titem.user_int = item.user_int - 1\n\n\titem.set_charges(item.user_int)\n\tawait Utils.create_manual_timer(0.1, self).timeout\n\titem.set_charges(item.user_int)\n\n\nfunc on_create():\n\titem.set_charges(10)\n#\tThe item will use the userInt for charges, cause charges are bugged.\n\titem.user_int = 10\n\n\nfunc periodic(_event: Event):\n\titem.user_int = item.user_int + 3\n\n\tif item.user_int >= 11:\n\t\titem.user_int = 10\n\n\titem.set_charges(item.user_int)\n\tawait Utils.create_manual_timer(0.1, self).timeout\n\titem.set_charges(item.user_int)\n"
  },
  {
    "path": "src/items/item_behaviors/scroll_of_strength.gd",
    "content": "extends ItemBehavior\n\n\nvar strength_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 40)\n\n\nfunc item_init():\n\tstrength_bt = BuffType.new(\"strength_bt\", 0.0, 0.0, true, self)\n\tstrength_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tstrength_bt.set_buff_tooltip(tr(\"0I23\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.1, 0)\n\tstrength_bt.set_buff_modifier(mod)\n\n\nfunc on_autocast(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar lvl: int = tower.get_level()\n\tvar it: Iterate\n\tvar next: Unit\n\n\tif item.user_int > 0:\n\t\tit = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 350)\n\n\t\twhile true:\n\t\t\tnext = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tstrength_bt.apply_custom_timed(tower, next, lvl * 2, 4.0)\n\n\t\titem.user_int = item.user_int - 1\n\n\titem.set_charges(item.user_int)\n\tawait Utils.create_manual_timer(0.1, self).timeout\n\titem.set_charges(item.user_int)\n\n\nfunc on_create():\n\titem.set_charges(10)\n#\tThe item will use the userInt for charges, cause charges are bugged.\n\titem.user_int = 10\n\n\nfunc periodic(_event: Event):\n\titem.user_int = item.user_int + 3\n\n\tif item.user_int >= 11:\n\t\titem.user_int = 10\n\n\titem.set_charges(item.user_int)\n\tawait Utils.create_manual_timer(0.1, self).timeout\n\titem.set_charges(item.user_int)\n"
  },
  {
    "path": "src/items/item_behaviors/seekers_arcane_oil.gd",
    "content": "extends ItemBehavior\n\n\nconst SEEKER_ARCANE_OIL_ID: int = 1019\n\n\nfunc on_pickup():\n\tSeekersOil.seeker_oil_on_pickup(item, SEEKER_ARCANE_OIL_ID)\n"
  },
  {
    "path": "src/items/item_behaviors/seekers_oil.gd",
    "content": "class_name SeekersOil extends ItemBehavior\n\n\n# NOTE: this range is a hand-picked value which hits 3x3\n# grid of towers around the main tower or 4+3+4 towers built\n# in honeycomb pattern.\n# \n# Distance to tower 2 tiles away = 128 * 2 = 256\n# -RANGE_CHECK_BONUS_FOR_TOWERS(72) to account for Iterate\n# adding it during range checking.\n# 256 - 72 = 184\n# and then additional -4 so that the oil doesn't hit tower 2\n# tiles away but hits a tower on the edge of honeycomb\n# pattern.\nstatic var SEEKER_OIL_RANGE: float = 2 * Constants.TILE_SIZE_WC3 - Constants.RANGE_CHECK_BONUS_FOR_TOWERS - 4\nconst SEEKER_OIL_ID: int = 1018\n\n\nfunc on_pickup():\n\tSeekersOil.seeker_oil_on_pickup(item, SEEKER_OIL_ID)\n\n\nstatic func seeker_oil_on_pickup(original_oil: Item, oil_id: int):\n# \tNOTE: hackfix alert! The _is_oil_and_was_applied_already\n# \tflag is used to know when we are transferring oils from\n# \tone tower to another, either when towers get upgraded or\n# \ttransformed. In such cases, we do not do the aoe effect\n# \tof seeker oil again - we only transfer the oil from old\n# \ttower to new tower.\n\tif original_oil._is_oil_and_was_applied_already:\n\t\treturn\n\n\tvar is_original_oil: bool = original_oil.user_int == 0\n\n\tif !is_original_oil:\n\t\treturn\n\n\tvar carrier: Tower = original_oil.get_carrier()\n\n\tvar towers_in_range: Iterate = Iterate.over_units_in_range_of_caster(carrier, TargetType.new(TargetType.TOWERS), SEEKER_OIL_RANGE)\n\n\twhile towers_in_range.count() > 0:\n\t\tvar neighbor: Tower = towers_in_range.next()\n\n\t\tif neighbor == carrier:\n\t\t\tcontinue\n\n\t\tvar oil_for_neighbor: Item = Item.create(original_oil.get_player(), oil_id, carrier.get_position_wc3())\n\n#\t\tNOTE: set user_int to 1 to mark this oil to stop recursion\n\t\toil_for_neighbor.user_int = 1\n\n\t\toil_for_neighbor.pickup(neighbor)\n"
  },
  {
    "path": "src/items/item_behaviors/share_knowledge.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 15)\n\n\nfunc periodic(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar next: Tower\n\tvar in_range: Iterate\n\tvar count: int\n\tvar experience: float\n\n#\ttest if tower is level 2 or higher\n\tif tower.get_level() > 1:\t\t\n#\t\ttest, if there are towers in range\n\t\tin_range = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 400)\n\t\tcount = min(5, in_range.count())\n\n\t\tif count > 0:\n\t\t\tCombatLog.log_item_ability(item, null, \"Share Knowledge\")\n\n# \t\t\t(8 + number of towers) / number of towers\n\t\t\texperience = (8.0 + count) / count\n\t\t\ttower.remove_exp_flat(10)\n\n\t\t\twhile true:\n\t\t\t\tnext = in_range.next_random()\n\n\t\t\t\tif next == null:\n\t\t\t\t\tbreak\n\n\t\t\t\tnext.add_exp_flat(experience)\n\t\t\t\tEffect.create_simple_at_unit(\"res://src/effects/polymorph_target.tscn\", next)\n\t\t\t\tcount = count - 1\n\n\t\t\t\tif count == 0:\n\t\t\t\t\tbreak\n"
  },
  {
    "path": "src/items/item_behaviors/shining_rock.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_create():\n\titem.user_real = 100\n\n\nfunc on_drop():\n\tvar tower: Tower = item.get_carrier()\n\titem.user_real = tower.remove_exp_flat(100)\n\n\nfunc on_pickup():\n\tvar tower: Unit = item.get_carrier()\n\tvar r: float = item.user_real\n\tif r > 0:\n\t\ttower.add_exp_flat(r)\n"
  },
  {
    "path": "src/items/item_behaviors/shrapnel_ammunition.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar T: Creep = event.get_target()\n\n\tif T.get_armor_type() == ArmorType.enm.LUA:\n\t\tevent.damage = event.damage * 1.25\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frag_boom_spawn.tscn\", T)\n"
  },
  {
    "path": "src/items/item_behaviors/sign_of_energy_infusion.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar carrier: Tower = item.get_carrier()\n\tvar regen: float = carrier.get_base_mana_regen_bonus_percent()\n\t\n\titem.user_int = item.user_int + 1\n\n\tif item.user_int >= 5:\n\t\tCombatLog.log_item_ability(item, null, \"Infuse with Regeneration\")\n\t\t\n#\t\tNOTE: original script multiplies damage by (2.0 +\n#\t\tregen). Changed it to (1.0 + regen) because of\n#\t\tdifferences in how\n#\t\tget_base_mana_regen_bonus_percent() works.\n#\t\t- In original youtd, that f-n returns 0.0 by\n#\t\t  default.\n#\t\t- In youtd2, it returns 1.0 by default.\n#\t\t\n#\t\tSo in original game damage was multiplied by 2.0 for\n#\t\ta default tower. max(0.0, ...) allows for damage\n#\t\tpenalty when mana regen is reduced by i.e. mana\n#\t\tdrain aura creeps while preventing it from turning\n#\t\tnegative.\n#\t\t\n#\t\tNOTE: damage is multiplied by 2.0 for a default\n#\t\ttower because by default, towers have 100%\n#\t\t\"percentual mana regeneration\". This is different\n#\t\tfrom \"percentual mana regeneration bonus\" stat which\n#\t\tstarts at +0%.\n\t\tevent.damage *= max(0.0, 1.0 + regen)\n\t\titem.user_int = 0\n\t\tvar damage_text: String = Utils.format_float(event.damage, 0)\n\t\tcarrier.get_player().display_small_floating_text(damage_text, carrier, Color8(255, 0, 255), 40.0)\n\n\nfunc on_create():\n\titem.user_int = 0\n"
  },
  {
    "path": "src/items/item_behaviors/silver_armor.gd",
    "content": "extends ItemBehavior\n\n\nfunc on_drop():\n    var tower: Tower = item.get_carrier()\n\n    tower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -tower.get_gold_cost() * 0.0001)\n\n\nfunc on_pickup():\n    var tower: Tower = item.get_carrier()\n\n    tower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, tower.get_gold_cost() * 0.0001)\n"
  },
  {
    "path": "src/items/item_behaviors/sleeve_of_rage.gd",
    "content": "extends ItemBehavior\n\n\nvar enraged_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tenraged_bt = BuffType.new(\"enraged_bt\", 1.5, 0, true, self)\n\tenraged_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tenraged_bt.set_buff_tooltip(tr(\"0JUJ\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.005)\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.0, 0.0025)\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.01)\n\tenraged_bt.set_buff_modifier(mod)\n\n\nfunc on_attack(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar buff: Buff = tower.get_buff_of_type(enraged_bt)\n\n\tvar active_stacks: int\n\tif buff != null:\n\t\tactive_stacks = buff.get_level()\n\telse:\n\t\tactive_stacks = 0\n\n\tvar new_stacks: int = active_stacks + 1\n\tnew_stacks = min(new_stacks, 120)\n\n\tbuff = enraged_bt.apply(tower, tower, new_stacks)\n\tbuff.set_displayed_stacks(new_stacks)\n"
  },
  {
    "path": "src/items/item_behaviors/soul_collectors_cloak.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar dps_gained_label: String = tr(\"HI9K\")\n\tmultiboard.set_key(0, dps_gained_label)\n\n\nfunc on_create():\n\titem.user_int = 0\n\n\nfunc on_drop():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_DPS_ADD, -item.user_int)\n\n\nfunc on_pickup():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_DPS_ADD, item.user_int)\n\n\nfunc on_kill(_event: Event):\n\tif item.user_int < 4000:\n\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_DPS_ADD, 10)\n\t\titem.user_int = item.user_int + 10\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar dps_gained_text: String = Utils.format_float(item.user_int, 0)\n\tmultiboard.set_value(0, dps_gained_text)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/soul_collectors_scythe.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar crit_bonus_label: String = tr(\"YA2C\")\n\tmultiboard.set_key(0, crit_bonus_label)\n\n\nfunc on_create():\n\titem.user_real = 0\n\n\nfunc on_drop():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, -item.user_real)\n\n\nfunc on_pickup():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, item.user_real)\n\n\nfunc on_kill(_event: Event):\n\tif item.user_real < 3:\n\t\titem.get_carrier().modify_property(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.005)\n\t\titem.user_real = item.user_real + 0.005\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar crit_damage_bonus_text: String = \"x\" + Utils.format_float(item.user_real, 3)\n\tmultiboard.set_value(0, crit_damage_bonus_text)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/soul_extractor.gd",
    "content": "extends ItemBehavior\n\n\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif item.user_int > 0:\n\t\tstun_bt.apply_only_timed(item.get_carrier(), target, 1.5)\n\t\titem.user_int = item.user_int - 1\n\t\titem.set_charges(item.user_int)\n\n\nfunc on_pickup():\n\titem.user_int = 0\n\n\nfunc on_kill(_event: Event):\n\titem.user_int = item.user_int + 2\n\titem.set_charges(item.user_int)\n"
  },
  {
    "path": "src/items/item_behaviors/spear_of_loki.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: in original script, item is used as caster for\n# stun_bt. Changed to tower itself because in our engine\n# Item is not a Unit.\n\n\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_attack(_event: Event):\n\tvar twr: Tower = item.get_carrier()\n\n\tif Utils.rand_chance(Globals.synced_rng, 0.15 / twr.get_prop_trigger_chances()):\n\t\tCombatLog.log_item_ability(item, null, \"Tricky Weapon\")\n\n\t\tstun_bt.apply_only_timed(twr, twr, 1)\n"
  },
  {
    "path": "src/items/item_behaviors/speed_demons_reward.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar gold_awarded_label: String = tr(\"R9SJ\")\n\tmultiboard.set_key(0, gold_awarded_label)\n\n\nfunc on_attack(event: Event):\n\tvar c: Creep = event.get_target()\n\tvar creep_level: int = c.get_spawn_level()\n\tvar reward_value: float\n\tvar t: Unit\n\n\tif item.user_int > 0 && item.user_int < creep_level:\n\t\treward_value = 12.0 - (Utils.get_time() - item.user_int2)\n\n\t\tif reward_value > 0:\n\t\t\tCombatLog.log_item_ability(item, null, \"Reward\")\n\t\t\tt = item.get_carrier()\n\t\t\tt.get_player().give_gold(reward_value, t, true, true)\n\t\t\tt.add_exp(reward_value / 2)\n\t\t\titem.user_real = item.user_real + reward_value\n\n\titem.user_int = max(item.user_int, creep_level)\n\titem.user_int2 = roundi(Utils.get_time())\n\n\nfunc on_create():\n\titem.user_int = -101\n\titem.user_int2 = -101\n\titem.user_real = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_float(item.user_real, 1))\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/spellbook_of_item_mastery.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_periodic_event(periodic, 5)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(3)\n\tvar waves_left_label: String = tr(\"L3GS\")\n\tvar item_quality_label: String = tr(\"L71R\")\n\tvar item_chance_label: String = tr(\"SK6C\")\n\tmultiboard.set_key(0, waves_left_label)\n\tmultiboard.set_key(1, item_quality_label)\n\tmultiboard.set_key(2, item_chance_label)\n\n\nfunc on_attack(event: Event):\n\tvar choose: int\n\tvar target: Creep\n\tvar tower: Tower\n\tvar player: Player\n\n\tif item.user_int <= 0:\n\t\titem.user_int = 15\n\t\t\n\t\ttower = item.get_carrier()\n\t\tplayer = item.get_player()\n\t\tchoose = Globals.synced_rng.randi_range(1, 6)\n\n\t\tif choose <= 4:\n\t\t\ttarget = event.get_target()\n\n\t\tif choose == 1:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 1)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -1)\n\t\t\tvar one_item_text: String = tr(\"NJ6M\")\n\t\t\tplayer.display_floating_text(one_item_text, tower, Color8(0, 0, 255))\n\t\telif choose == 2:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.5)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -0.5)\n\t\t\tvar two_items_text: String = tr(\"VVB4\")\n\t\t\tplayer.display_floating_text(two_items_text, tower, Color8(0, 0, 255))\n\t\telif choose == 3:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.25)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -0.25)\n\t\t\tvar three_items_text: String = tr(\"MMDP\")\n\t\t\tplayer.display_floating_text(three_items_text, tower, Color8(0, 0, 255))\n\t\telif choose == 4:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.25)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttarget.drop_item(tower, false)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -0.25)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.1)\n\t\t\titem.user_real = item.user_real + 0.1\n\t\t\titem.user_real2 = item.user_real2 + 0.1\n\t\t\tvar two_items_and_bonus_text: String = tr(\"MKEI\")\n\t\t\tplayer.display_floating_text(two_items_and_bonus_text, tower, Color8(0, 0, 255))\n\t\telif choose == 5:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, 0.25)\n\t\t\titem.user_real2 = item.user_real2 + 0.25\n\t\t\tvar item_chance_text: String = tr(\"JQ7S\")\n\t\t\tplayer.display_floating_text(item_chance_text, tower, Color8(0, 255, 0))\n\t\telif choose == 6:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.25)\n\t\t\titem.user_real = item.user_real + 0.25\n\t\t\tvar item_quality_text: String = tr(\"M64K\")\n\t\t\tplayer.display_floating_text(item_quality_text, tower, Color8(0, 255, 0))\n\n\nfunc on_create():\n\titem.user_int = 0\n\titem.user_int2 = item.get_player().get_team().get_level()\n\titem.user_real = 0\n\titem.user_real2 = 0\n\n\nfunc on_drop():\n\tvar tower: Tower = item.get_carrier()\n\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -item.user_real)\n\ttower.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, -item.user_real2)\n\n\nfunc on_pickup():\n\tvar tower: Tower = item.get_carrier()\n\ttower.modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, item.user_real)\n\ttower.modify_property(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL, item.user_real2)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar waves_left_text: String = Utils.format_float(item.user_int, 2)\n\tvar item_quality_text: String = Utils.format_percent(item.user_real, 0)\n\tvar item_chance_text: String = Utils.format_percent(item.user_real2, 0)\n\tmultiboard.set_value(0, waves_left_text)\n\tmultiboard.set_value(1, item_quality_text)\n\tmultiboard.set_value(2, item_chance_text)\n\t\n\treturn multiboard\n\n\nfunc periodic(_event: Event):\n\tvar level: int = item.get_player().get_team().get_level()\n\n\tif item.user_int2 < level:\n\t\titem.user_int = item.user_int - (level - item.user_int2)\n\t\titem.user_int2 = level\n"
  },
  {
    "path": "src/items/item_behaviors/spider_broach.gd",
    "content": "extends ItemBehavior\n\n\nvar threads_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc item_init():\n\tthreads_bt = BuffType.new(\"threads_bt\", 5.0, 0.1, false, self)\n\tthreads_bt.set_buff_icon(\"res://resources/icons/generic_icons/spider_web.tres\")\n\tthreads_bt.set_buff_tooltip(tr(\"A8WN\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH, 0.4, 0.01)\n\tthreads_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\n\tif tower.calc_chance(0.15 * tower.get_base_attack_speed()):\n\t\tCombatLog.log_item_ability(item, null, \"Silver Threads\")\n\t\tthreads_bt.apply(tower, event.get_target(), tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/spiderling.gd",
    "content": "extends ItemBehavior\n\n\nvar slow_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc item_init():\n\tslow_bt = BuffType.new(\"slow_bt\", 4, 0, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/spider_web.tres\") \n\tslow_bt.set_buff_tooltip(tr(\"Y2QA\"))\n\tvar mod: Modifier = Modifier.new() \n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.05, 0) \n\tslow_bt.set_buff_modifier(mod) \n\n\nfunc on_attack(event: Event):\n\tvar tower: Tower = item.get_carrier() \n\tvar speed: float = tower.get_base_attack_speed()  \n\n\tif tower.calc_chance(0.25 * speed) == true:\n\t\tCombatLog.log_item_ability(item, event.get_target(), \"Spiderling Poison\")\n\t\tslow_bt.apply(tower, event.get_target(), 1)\n"
  },
  {
    "path": "src/items/item_behaviors/staff_of_essence.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar T: Tower = item.get_carrier()\n\tvar AT: AttackType.enm = T.get_attack_type()\n\tvar C: Creep = event.get_target()\n\tvar r: float = AttackType.get_damage_against(AT, C.get_armor_type())\n\n#\tNOTE: this check is actually not needed because DAMAGE\n#\tevent is not called for spell damage\n\tif event.is_spell_damage() == false:\n\t\tevent.damage = event.damage / r\n"
  },
  {
    "path": "src/items/item_behaviors/staff_of_the_wild_equus.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Original script moves\n# lifted creeps a little by random offset. Removed it\n# because youtd2 creeps are supposed to always be \"on\n# rails\", on creep path.\n\n\nvar ascended_bt: BuffType\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\n# NOTE: drol_lift_up() in original script\nfunc ascended_bt_on_create(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar c: Unit = b.get_buffed_unit()\n\tb.user_int = Effect.create_simple_at_unit_attached(\"res://src/effects/cyclone_target.tscn\", c, Unit.BodyPart.ORIGIN)\n\tEffect.set_auto_destroy_enabled(b.user_int, false)\n\tc.adjust_height(300, 150)\n\n\n# NOTE: drol_lift_period() in original script\nfunc ascended_bt_periodic(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar c: Unit = b.get_buffed_unit()\n\tc.set_unit_facing(c.get_unit_facing() + 125)\n\n\n# NOTE: drol_lift_down() in original script\nfunc ascended_bt_on_cleanup(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar c: Unit = b.get_buffed_unit()\n\tc.adjust_height(-300, 2500)\n\tEffect.destroy_effect(b.user_int)\n\t\n\tSFX.sfx_at_unit(SfxPaths.CLOUD_POOF, c)\n\tvar creep_pos: Vector2 = c.get_position_wc3_2d()\n\tvar effect: int = Effect.create_simple(\"res://src/effects/warstomp_caster.tscn\", creep_pos)\n\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\n\nfunc item_init():\n\tascended_bt = CbStun.new(\"ascended_bt\", 2.0, 0, false, self)\n\tascended_bt.set_buff_icon(\"res://resources/icons/generic_icons/rolling_energy.tres\")\n\tascended_bt.set_buff_tooltip(tr(\"MJ83\"))\n\tascended_bt.add_event_on_create(ascended_bt_on_create)\n\tascended_bt.add_periodic_event(ascended_bt_periodic, 0.1)\n\tascended_bt.add_event_on_cleanup(ascended_bt_on_cleanup)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_EXP_GRANTED, 0.2, 0.008)\n\tascended_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar size: CreepSize.enm = event.get_target().get_size()\n\n\tif event.is_main_target() && tower.calc_chance(0.08 * tower.get_base_attack_speed()) && (size == CreepSize.enm.MASS || size == CreepSize.enm.CHALLENGE_MASS || size == CreepSize.enm.NORMAL):\n\t\tCombatLog.log_item_ability(item, null, \"Ascension\")\n\t\tascended_bt.apply(tower, event.get_target(), tower.get_level())\n"
  },
  {
    "path": "src/items/item_behaviors/stasis_trap.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: reworked this script a bit because it seems that the\n# original was coded when Iterate didn't have next_random()\n# yet so the original script had to do a bunch of extra\n# stuff.\n\n\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 8)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\tstun_bt.set_special_effect(\"res://src/effects/purge_buff_target.tscn\", 50, 1.0, Color(Color.GREEN, 0.75))\n\n\nfunc periodic(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar iterate: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\tvar loop_counter: int = 3\n\n\tCombatLog.log_item_ability(item, null, \"Activate Trap\")\n\n\twhile true:\n\t\tvar creep: Unit = iterate.next_random()\n\n\t\tif creep == null:\n\t\t\tbreak\n\n\t\tloop_counter = loop_counter - 1\n\n\t\tif tower.get_level() == 25:\n\t\t\tstun_bt.apply_only_timed(tower, creep, 1.0)\n\t\telse:\n\t\t\tstun_bt.apply_only_timed(tower, creep, 0.5)\n\n\t\tif loop_counter == 0:\n\t\t\tbreak\n"
  },
  {
    "path": "src/items/item_behaviors/strange_item.gd",
    "content": "extends ItemBehavior\n\n\n# [ORIGINAL_GAME_DEVIATION] Removed auto-dropping behavior\n# to make Strange Item usable during bonus waves.\n# \n# In youtd1, Strange Item would automatically drop from\n# towers during bonus waves. Note that in youtd1, bonus\n# waves did not have individual wave numbers - they were all\n# part of wave \"241\". So Strange Item would not work during\n# bonus waves, even if it didn't get auto-removed from\n# towers.\n# \n# In youtd2, bonus waves have their own wave numbers so\n# Strange Item can work during bonus waves.\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 5)\n\n\nfunc on_create():\n\titem.user_int2 = 12\n\titem.user_int = item.user_int2\n\titem.set_charges(item.user_int)\n\n\nfunc on_drop():\n\tvar tower: Tower\n\tvar cur_level: int = item.get_player().get_team().get_level()\n\n\tif cur_level > item.user_int3:\n\t\titem.user_int = item.user_int - (cur_level - item.user_int3)\n\t\titem.user_int3 = cur_level\n\n\t\tif item.user_int <= 0:\n\t\t\tCombatLog.log_item_ability(item, null, \"Duplication\")\n\t\t\t\n\t\t\ttower = item.get_carrier()\n\t\t\tvar new: Item = Item.create(tower.get_player(), item.get_id(), tower.get_position_wc3())\n\n\t\t\tnew.user_int2 = item.user_int2 + 6\n\t\t\tnew.user_int = new.user_int2\n\t\t\tnew.set_charges(new.user_int)\n\t\t\titem.user_int = item.user_int + item.user_int2\n\n\t\t\tnew.fly_to_stash(0.0)\n\n\t\titem.set_charges(item.user_int)\n\n\nfunc on_pickup():\n\titem.user_int3 = item.get_player().get_team().get_level()\n\titem.set_charges(item.user_int)\n\n\nfunc periodic(_event: Event):\n\tvar tower: Tower\n\tvar cur_level: int = item.get_player().get_team().get_level()\n\n\tif cur_level > item.user_int3:\n\t\titem.user_int = item.user_int - (cur_level - item.user_int3)\n\t\titem.user_int3 = cur_level\n\n\t\tif item.user_int <= 0:\n\t\t\ttower = item.get_carrier()\n\t\t\tvar new: Item = Item.create(tower.get_player(), item.get_id(), tower.get_position_wc3())\n\n\t\t\tnew.user_int2 = item.user_int2 + 6\n\t\t\tnew.user_int = new.user_int2\n\t\t\tnew.set_charges(new.user_int)\n\t\t\titem.user_int = item.user_int + item.user_int2\n\n\t\t\tif !new.pickup(tower):\n\t\t\t\tnew.fly_to_stash(0.0)\n\n\t\titem.set_charges(item.user_int)\n"
  },
  {
    "path": "src/items/item_behaviors/stunner.gd",
    "content": "extends ItemBehavior\n\n\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc item_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar size: int = target.get_size()\n\tvar tower: Tower = item.get_carrier()\n\tvar speed: float = tower.get_base_attack_speed()\n\n\tif !event.is_main_target():\n\t\treturn\n\n\tif size < CreepSize.enm.BOSS:\n\t\tif tower.calc_chance((0.15 + tower.get_level() * 0.0025) * speed) && event.is_main_target() == true:\n\t\t\tCombatLog.log_item_ability(item, null, \"Stun\")\n\t\t\tstun_bt.apply_only_timed(tower, target, 1)\n\telse:\n\t\tif tower.calc_chance((0.15 + tower.get_level() * 0.0025) / 3 * speed) && event.is_main_target() == true:\n\t\t\tCombatLog.log_item_ability(item, null, \"Stun\")\n\t\t\tstun_bt.apply_only_timed(tower, target, 1)\n"
  },
  {
    "path": "src/items/item_behaviors/sword_of_decay.gd",
    "content": "extends ItemBehavior\n\n\nvar rot_bt: BuffType\n\n\nfunc item_init():\n\trot_bt = BuffType.create_aura_effect_type(\"rot_bt\", true, self)\n\trot_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\trot_bt.set_buff_tooltip(tr(\"RI8B\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_NATURE, 0.12, 0.0024)\n\trot_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/sword_of_reckoning.gd",
    "content": "extends ItemBehavior\n\n\nvar holy_wrath_bt: BuffType\n\n\nfunc item_init():\n\tholy_wrath_bt = BuffType.create_aura_effect_type(\"holy_wrath_bt\", true, self)\n\tholy_wrath_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tholy_wrath_bt.set_buff_tooltip(tr(\"8CD3\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_UNDEAD, 0.12, 0.0024)\n\tholy_wrath_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/the_divine_wings_of_tragedy.gd",
    "content": "extends ItemBehavior\n\n\nvar divine_wings_bt: BuffType\n\n\nfunc item_init():\n\tdivine_wings_bt = BuffType.create_aura_effect_type(\"item230_divine_wings_bt\", true, self)\n\tdivine_wings_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\tdivine_wings_bt.set_buff_tooltip(tr(\"HFBQ\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.15, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.15, 0.0)\n\tdivine_wings_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/toy_boy.gd",
    "content": "extends ItemBehavior\n\n\nvar playtime_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 10)\n\n\nfunc item_init():\n\tplaytime_bt = BuffType.new(\"playtime_bt\", 2.0, 0, false, self)\n\tplaytime_bt.set_buff_icon(\"res://resources/icons/generic_icons/pokecog.tres\")\n\tplaytime_bt.set_buff_tooltip(tr(\"QYT7\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.5, 0.0)\n\tplaytime_bt.set_buff_modifier(mod)\n\n\nfunc periodic(_event: Event):\n\tCombatLog.log_item_ability(item, null, \"Play with me!\")\n\tplaytime_bt.apply(item.get_carrier(), item.get_carrier(), 1)\n"
  },
  {
    "path": "src/items/item_behaviors/unstable_current.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar T: Creep = event.get_target()\n\n\tif T.get_armor_type() == ArmorType.enm.HEL:\n\t\tevent.damage = event.damage * 1.25\n\t\tEffect.create_simple_at_unit(\"res://src/effects/dispel_magic_target.tscn\", T)\n"
  },
  {
    "path": "src/items/item_behaviors/unyielding_maul.gd",
    "content": "extends ItemBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] original script\n# implemented miss effect via \"attack\" event. Not sure how\n# that's supposed to work because setting event.damage to 0\n# in attack event should have no effect. At least it has no\n# effect in the godot engine, so I changed to this script to\n# use \"damage\" event. Maybe it does work in JASS engine that\n# way, need to test this item in original game and change\n# how attack event is handled in godot engine if needed.\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Unit = item.get_carrier()\n\n\tif !tower.calc_chance(0.90):\n\t\tCombatLog.log_item_ability(item, null, \"Miss\")\n\n\t\tevent.damage = 0\n\t\tvar miss_text: String = tr(\"FLOATING_TEXT_MISS\")\n\t\ttower.get_player().display_floating_text_x(miss_text, tower, Color8(255, 0, 0, 255), 0.05, 0.0, 2.0)\n"
  },
  {
    "path": "src/items/item_behaviors/vampiric_skull.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc on_kill(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\ttower.add_mana_perc(0.07)\n\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/replenish_mana.tscn\", tower)\n\tEffect.set_color(effect, Color.RED)\n"
  },
  {
    "path": "src/items/item_behaviors/wand_of_mana_zap.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tvar creep: Creep = event.get_target()\n\n\t# var l: Lightning\n\n\tif event.is_main_target():\n\t\tif creep.subtract_mana((8 + 0.6 * tower.get_level() * tower.get_base_attack_speed()) * (55 / pow(tower.get_base_range(), 0.6)), true) > 0:\n\t\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, tower, creep)\n\t\t\tlightning.modulate = Color.LIGHT_GREEN\n\t\t\tlightning.set_lifetime(0.1)\n\t\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/arcane_tower_attack.tscn\", creep)\n\t\t\tEffect.set_color(effect, Color.LIGHT_BLUE)\n"
  },
  {
    "path": "src/items/item_behaviors/wanted_list.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc on_kill(_event: Event):\n\tvar tower: Tower = item.get_carrier()\n\tCombatLog.log_item_ability(item, null, \"Headhunt\")\n\titem.get_carrier().get_player().give_gold(2, tower, true, true)\n"
  },
  {
    "path": "src/items/item_behaviors/war_drum.gd",
    "content": "extends ItemBehavior\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Warsong Double Bass\"=>\"War Drum\"\n\n\nvar drum_bt: BuffType\n\n\nfunc item_init():\n\tdrum_bt = BuffType.create_aura_effect_type(\"drum_bt\", true, self)\n\tdrum_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tdrum_bt.set_buff_tooltip(tr(\"LBDS\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.075, 0.001)\n\tdrum_bt.set_buff_modifier(mod)\n"
  },
  {
    "path": "src/items/item_behaviors/wise_mans_cooking_recipe.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc on_kill(_event: Event):\n\titem.get_carrier().add_exp(1)\n"
  },
  {
    "path": "src/items/item_behaviors/wizards_soul.gd",
    "content": "extends ItemBehavior\n\n"
  },
  {
    "path": "src/items/item_behaviors/wooden_leg.gd",
    "content": "extends ItemBehavior\n\n"
  },
  {
    "path": "src/items/item_behaviors/workbench.gd",
    "content": "extends ItemBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc item_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar item_quality_label: String = tr(\"ZF07\")\n\tmultiboard.set_key(0, item_quality_label)\n\n\nfunc on_create():\n\titem.user_real = 0.00\n\n\nfunc on_drop():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -item.user_real)\n\n\nfunc on_pickup():\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, item.user_real)\n\n\nfunc on_kill(_event: Event):\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, -item.user_real)\n\titem.user_real = item.user_real + 0.0015\n\titem.get_carrier().modify_property(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, item.user_real)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_percent(item.user_real, 2))\n\treturn multiboard\n"
  },
  {
    "path": "src/items/item_behaviors/writers_knowledge.gd",
    "content": "extends ItemBehavior\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 12)\n\n\nfunc periodic(_event: Event):\n\tCombatLog.log_item_ability(item, null, \"Learn\")\n\t\n\tvar tower: Unit = item.get_carrier()\n\ttower.add_exp(1)\n"
  },
  {
    "path": "src/items/item_container.gd",
    "content": "class_name ItemContainer extends Node\n\n\n# Generic item container which stores items. Used by towers,\n# item stash and horadric cube.\n\n\nsignal items_changed()\n\n\nvar _item_list: Array[Item] = []\nvar _item_list_with_slots: Array[Item] = []\nvar _item_to_index_map: Dictionary = {}\n@export var _capacity: int = 0\n\nstatic var _uid_max: int = 1\nvar _uid: int = 0\nvar _highest_index: int = 0\nvar _player: Player = null\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_uid = _uid_max\n\tItemContainer._uid_max += 1\n\tGroupManager.add(\"item_containers\", self, get_uid())\n\t\n\tset_capacity(_capacity)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_player(player: Player):\n\t_player = player\n\n\nfunc get_player() -> Player:\n\treturn _player\n\n\nfunc get_uid() -> int:\n\treturn _uid\n\n\nfunc set_capacity(new_capacity: int):\n\tif new_capacity < _capacity:\n\t\tpush_error(\"Tried to decrease capacity of item container!\")\n\n\t\treturn\n\n\t_capacity = new_capacity\n\t_item_list_with_slots.resize(new_capacity)\n\n\nfunc have_item_space() -> bool:\n\tvar item_count: int = get_item_count()\n\tvar result: bool = item_count < _capacity\n\n\treturn result\n\n\nfunc can_add_item(_item: Item) -> bool:\n\treturn have_item_space()\n\n\nfunc add_item(item: Item, insert_index: int = -1):\n\tif !have_item_space():\n\t\tpush_error(\"Tried to put items over capacity. Use have_item_space() before adding items.\")\n\n\t\treturn\n\t\n#\tIf no index was defined, find first free slot\n\tif insert_index == -1:\n\t\tfor i in range(0, _item_list_with_slots.size()):\n\t\t\tvar slot_is_free: bool = _item_list_with_slots[i] == null\n\t\t\t\n\t\t\tif slot_is_free:\n\t\t\t\tinsert_index = i\n\t\t\t\t\n\t\t\t\tbreak\n\t\t\n\t\tvar failed_to_find_free_index: bool = insert_index == -1\n\t\tif failed_to_find_free_index:\n\t\t\tpush_error(\"Failed to find free index.\")\n\t\t\t\n\t\t\treturn\n\n\t_item_list.append(item)\n\t_item_list_with_slots[insert_index] = item\n\t_item_to_index_map[item] = insert_index\n\n\tif insert_index > _highest_index:\n\t\t_highest_index = insert_index\n\n\titem.consumed.connect(_on_item_consumed.bind(item))\n\tadd_child(item)\n\titems_changed.emit()\n\n\nfunc remove_item(item: Item):\n\tvar item_index: int = get_item_index(item)\n\tvar item_not_found: bool = item_index == -1\n\n\tif item_not_found:\n\t\tvar item_name: String = ItemProperties.get_display_name(item.get_id())\n\t\tpush_error(\"Attempted to remove item from item container but it is not in container. Item: \", item_name)\n\n\t\treturn\n\n\t_item_list.erase(item)\n\t_item_list_with_slots[item_index] = null\n\t_item_to_index_map.erase(item)\n\titem.consumed.disconnect(_on_item_consumed)\n\tif item.is_inside_tree():\n\t\tremove_child(item)\n\titems_changed.emit()\n\n\nfunc has(item: Item) -> bool:\n\tvar has_item: bool = _item_to_index_map.has(item)\n\n\treturn has_item\n\n\n# NOTE: this f-n returns a contiguous item list without\n# empty slots. The order of this list doesn't match the real\n# order. To get items in real order, iterate over indexes\n# and use get_item_at_index().\nfunc get_item_list() -> Array[Item]:\n\treturn _item_list.duplicate()\n\n\nfunc get_item_count() -> int:\n\tvar item_count: int = _item_list.size()\n\n\treturn item_count\n\n\nfunc get_capacity() -> int:\n\treturn _capacity\n\n\nfunc get_item_index(item: Item) -> int:\n\tvar index: int = _item_to_index_map.get(item, -1)\n\n\treturn index\n\n\nfunc get_item_at_index(index: int) -> Item:\n\tvar within_bounds: bool = index < _item_list_with_slots.size()\n\n\tif within_bounds:\n\t\tvar item: Item = _item_list_with_slots[index]\n\n\t\treturn item\n\telse:\n\t\treturn null\n\n\n# Returns highest occupied index (ever). This value doesn't\n# decrease if items are removed.\nfunc get_highest_index() -> int:\n\treturn _highest_index\n\n\nfunc _item_value_func(item: Item):\n\tvar value: int = 0\n\t\n\tvalue += item.get_id()\n\t# below assumes max values of ids, level and rarity with safe margins\n\tvalue += item.get_required_wave_level() * int(1e+6)\n\tvalue += item.get_rarity() * int(1e+10)\n\tvalue += int(item.get_item_type() == ItemType.enm.REGULAR) * int(1e+12)\n\treturn value\n\n\n# NOTE: this function MUST be called only by\n# ActionSortItemStash.execute(). Otherwise, desyncs in\n# multiplayer are possible.\nfunc sort_items_by_type_rarity_and_levels():\n\tvar new_item_list_with_slots: Array[Item] = []\n\tnew_item_list_with_slots.resize(_item_list_with_slots.size())\n\tvar new_item_to_index_map: Dictionary = {}\n\t\n\tvar item_values: Dictionary = {}\n\tfor item in _item_list:\n\t\titem_values[item] = _item_value_func(item)\n\t\n\tvar _sorting_func = func(item1: Item, item2: Item):\n\t\treturn item_values[item1] < item_values[item2]\n\t\t\n\t_item_list.sort_custom(_sorting_func)\n\t\n\tvar index: int = 0\n\tfor item in _item_list:\n\t\tnew_item_list_with_slots[index] = item\n\t\tnew_item_to_index_map[item] = index\n\t\tindex += 1\n\t\t\n\t_item_list_with_slots = new_item_list_with_slots\n\t_item_to_index_map = new_item_to_index_map\n\titems_changed.emit()\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_item_consumed(item: Item):\n\tremove_item(item)\n\titem.queue_free()\n"
  },
  {
    "path": "src/items/item_drop.gd",
    "content": "class_name ItemDrop extends Unit\n\n\n# ItemDrop is the storage for the item when it is dropped on\n# the ground. Contains item instance as child. Note that\n# this class is basically a vestigial thing from original\n# youtd because in youtd2 it's always invisible. In original\n# youtd, items could be moved around on the ground but in\n# youtd2, items are always either in item stash or tower\n# inventory. The only functional thing this class does in\n# youtd2 is storing the item while it's flying to item stash\n# and also if it somehow becomes visible then that's a\n# signal that something went wrong.\n\n\n@export var _visual: Node2D\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tsuper()\n\n\t_set_visual_node(_visual)\n\n# \tNOTE: use 100 so that item drops is drawn in front of\n# \tall units. Not important because ItemDrops are almost\n# \tnever visible.\n\tz_index = 100\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(item: Item, drop_pos: Vector3) -> ItemDrop:\n\tif item.get_parent() != null:\n\t\tpush_error(\"ItemDrop.make() was called on an item which still has a parent. Item must be unparented before being added to ItemDrop. Forcefully removing item from parent to proceed.\")\n\t\titem.get_parent().remove_child(item)\n\t\n\tvar item_drop_scene: PackedScene = preload(\"res://src/items/item_drop.tscn\")\n\tvar item_drop: ItemDrop = item_drop_scene.instantiate()\n\titem_drop.set_position_wc3(drop_pos)\n#\tNOTE: in youtd2, item drops are always invisible\n\titem_drop.visible = false\n\titem_drop.set_player(item.get_player())\n\titem_drop.add_child(item)\n\n\treturn item_drop\n"
  },
  {
    "path": "src/items/item_drop.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dby8dpgvxybfr\"]\n\n[ext_resource type=\"Script\" path=\"res://src/items/item_drop.gd\" id=\"1_id1fy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://itq2i72y2h0w\" path=\"res://resources/misc/barrel.tres\" id=\"2_0jryt\"]\n\n[node name=\"ItemDrop\" type=\"Node2D\" node_paths=PackedStringArray(\"_visual\")]\nscript = ExtResource(\"1_id1fy\")\n_visual = NodePath(\"Visual\")\n\n[node name=\"Visual\" type=\"Node2D\" parent=\".\"]\n\n[node name=\"Sprite2D\" type=\"Sprite2D\" parent=\"Visual\"]\ntexture = ExtResource(\"2_0jryt\")\n\n[connection signal=\"selected_changed\" from=\".\" to=\".\" method=\"_on_selected_changed\"]\n"
  },
  {
    "path": "src/items/tower_item_container.gd",
    "content": "class_name TowerItemContainer extends ItemContainer\n\n\n# This is a subclass of ItemContainer used by Tower.\n# Implements additional functionality for storing oils and\n# applying item effects on tower when items are in the\n# container.\n\n\n# NOTE: oils go into a separate list which has unlimited\n# capacity\nvar _oil_list: Array[Item] = []\nvar _tower: Tower\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(capacity: int, tower: Tower):\n\tset_capacity(capacity)\n\t_tower = tower\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc add_item(item: Item, insert_index: int = -1):\n\tvar is_oil: bool = ItemProperties.get_is_oil(item.get_id())\n\n\tif is_oil:\n\t\t_oil_list.append(item)\n\t\tadd_child(item)\n\telse:\n\t\tsuper.add_item(item, insert_index)\n\n#\tNOTE: order is important here. Need to call add_item()\n#\tto do add_child() before calling _add_to_tower()\n\titem._add_to_tower(_tower)\n\n# \tNOTE: hackfix alert! The _is_oil_and_was_applied_already\n# \tflag is used to know when we are transferring oils from\n# \tone tower to another, either when towers get upgraded or\n# \ttransformed. In such cases, we do not show the application\n# \tEffect again.\n\tif is_oil && !item._is_oil_and_was_applied_already:\n\t\tvar effect_pos: Vector3 = _tower.get_position_wc3()\n\t\teffect_pos.z += Constants.TILE_SIZE_WC3 * 0.25\t\n\t\tEffect.create_animated(\"res://src/effects/apply_potion.tscn\", effect_pos, 0)\n\n\t\titem._is_oil_and_was_applied_already = true\n\n\n# NOTE: order is important here. Need to call\n# _remove_from_tower() last so that item properties like\n# _carrier are available before that point.\n# _remove_from_tower() clears those properties.\nfunc remove_item(item: Item):\n\tvar item_id: int = item.get_id()\n\tvar is_oil: bool = ItemProperties.get_is_oil(item_id)\n\n\tif is_oil:\n\t\t_oil_list.erase(item)\n\t\tremove_child(item)\n\telse:\n\t\tsuper.remove_item(item)\n\t\n\titem._remove_from_tower()\n\n\nfunc get_oil_list() -> Array[Item]:\n\treturn _oil_list.duplicate()\n\n\n# NOTE: if item is oil, then we don't care about item space\n# - can add unlimited amount of oils\nfunc can_add_item(item: Item) -> bool:\n\tvar item_id: int = item.get_id()\n\tvar is_oil: bool = ItemProperties.get_is_oil(item_id)\n\tvar can_add: bool = have_item_space() || is_oil\n\n\treturn can_add\n"
  },
  {
    "path": "src/map/buildable_area.gd",
    "content": "class_name BuildableArea extends TileMapLayer\n\n\n# This tilemap is used to define tiles where a player can\n# build towers. One BuildableArea for each Player. Note that\n# this tilemap is used for two things:\n# - Define buildable area in editor while developing\n# - Display buildable area visually while game is running\n# \n# The actual logic for checking buildable positions is\n# implemented by the BuildSpace class. BuildSpace loads data\n# about buildable positions from BuildableAreas when game\n# starts.\n\n\nconst BUILDABLE_AREA_COLOR: Color = Color8(0, 255, 255)\nconst BUILDABLE_PULSE_ALPHA_MIN = 0.1\nconst BUILDABLE_PULSE_ALPHA_MAX = 0.2\nconst BUILDABLE_PULSE_PERIOD = 1.0\n\n@export var player_id: int\n\n\nfunc _ready() -> void:\n\tadd_to_group(\"buildable_areas\")\n\t\n#\tNOTE: reset color so it's same for all areas. In editor,\n#\tbuildable areas have different colors for convenience\n#\twhile developing.\n\tmodulate = BUILDABLE_AREA_COLOR\n\t\n\tvar tween = create_tween()\n\ttween.tween_property(self, \"modulate\",\n\t\tColor(BUILDABLE_AREA_COLOR, BUILDABLE_PULSE_ALPHA_MIN),\n\t\t0.5 * BUILDABLE_PULSE_PERIOD).set_trans(Tween.TRANS_LINEAR)\n\ttween.tween_property(self, \"modulate\",\n\t\tColor(BUILDABLE_AREA_COLOR, BUILDABLE_PULSE_ALPHA_MAX),\n\t\t0.5 * BUILDABLE_PULSE_PERIOD).set_trans(Tween.TRANS_LINEAR).set_delay(0.5 * BUILDABLE_PULSE_PERIOD)\n\ttween.set_loops()\n"
  },
  {
    "path": "src/map/buildable_area.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dsaarf0j6pf6g\"]\n\n[ext_resource type=\"TileSet\" uid=\"uid://bo62tf3gtehiu\" path=\"res://resources/tilesets/buildable_area_tiles.tres\" id=\"1_161yt\"]\n[ext_resource type=\"Script\" path=\"res://src/map/buildable_area.gd\" id=\"1_tjjut\"]\n\n[node name=\"BuildableArea\" type=\"TileMapLayer\"]\nmodulate = Color(0, 1, 1, 0.211765)\nz_index = 12\ntile_set = ExtResource(\"1_161yt\")\nscript = ExtResource(\"1_tjjut\")\n"
  },
  {
    "path": "src/map/map.gd",
    "content": "class_name Map extends Node2D\n\n# Map contains TileMaps which are drawn in the world. Note\n# that some tiles are background while other tiles may be\n# drawn in front of units depending on their position. Map\n# also contains extra non-visual map nodes which are used\n# for gameplay purposes.\n# \n# MainTileMap is for tiles which are aligned with the tile\n# grid (256x128). Contains things like floors and walls.\n# \n# DecorationTileMap is for tiles which need to have more\n# free positioning. This TileMap has a smaller grid size\n# (64x32). Contains things like vegetation, barrels, etc.\n\n# There are two variants of the map: small and big. Small\n# contains 2 lanes and is used for singleplayer. Big\n# contains 8 lanes and is used for multiplayer. Small\n# variant is used to get the best performance on browser\n# build. Swapping is done in GameScene._ready().\n\n# NOTE: explanation of z_index values for tilemap layers and units:\n# - 0 = lvl1-flat tilemap layer, this is for floor tiles on\n#   lvl1 elevation\n# - 10 = lvl1-tall tilemap layer, this is for tall tiles\n#   (walls) on lvl1 elevation\n# - 10 = lvl2-flat tilemap layer, this is for floor tiles on\n#   lvl2 elevation\n# - 20 = lvl2-tall tilemap layer, this is for tall tiles\n#   (walls) on lvl2 elevation\n#\n# Buildable area tiles have z_index of 12, so that they are:\n# - above lvl2 flat tiles\n# - above lvl2 flat decoration tiles\n# - below lvl2 units and tall tiles\n#\n# Note that lvl2-flat layer has same z_index as lvl1-tall\n# but it has y-sort origin of 192. This effectively makes\n# the floor tiles placed on lvl2-flat act the same as\n# lvl1-tall tiles. Imagine it as a transparent cube with a\n# floor tile on top. Making lvl2-flat have z_index of 20\n# would not work because lvl2 floor tiles would draw\n# over tall decorations like trees, placed on lvl1.\n# \n# For decoration tilemap, the z_indexes is similar, but for\n# flat layers, the z_index is +1 greater than tilemap flat\n# layers. This is so that flat decorations like vines are\n# always drawn above tilemap flat tiles. For example:\n# - 0 = lvl1-flat tilemap layer\n# - 1 = lvl1-flat decoration layer\n# \n# Ground creeps have z_index of 10, so that they are:\n# - above lvl1 flat tiles\n# - y-sorted with lvl1 tall tiles and lvl2 flat tiles\n# - below lvl2 tall tiles\n# \n# Ground creeps can be temporarily elevated with tower\n# abilities. In such cases, their z_index gains a +10 and\n# becomes 20. Elevated creeps are:\n# - above all lvl1 tiles\n# - above lvl2 flat tiles\n# - y-sorted with lvl2 tall tiles\n# \n# Air creeps have z_index of 21, so that they are:\n# - above all tilemap and decoration tiles\n# - above temporarily elevated creeps\n# - above towers\n# \n# Towers have z_index of 20, so that they are:\n# - above lvl2 flat tiles\n# - y-sorted with lvl2 tall tiles\n# - below air creeps\n# \n# Corpses have z_index of 10, so that they are:\n# - above lvl1 flat tiles\n# - above lvl1 decoration flat tiles\n# - y-sorted with lvl1 tall tiles\n\n\n@export var _camera_limits: Polygon2D\n@export var _ground_indicator_map: TileMap\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tEventBus.player_started_build_process.connect(_on_player_started_build_process)\n\tEventBus.player_stopped_build_process.connect(_on_player_stopped_build_process)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_camera_limits() -> Polygon2D:\n\treturn _camera_limits\n\n\nfunc get_buildable_cells(player: Player) -> Array[Vector2i]:\n\tvar buildable_area: BuildableArea = _get_buildable_area(player)\n\tvar buildable_cells: Array[Vector2i] = buildable_area.get_used_cells()\n\n\treturn buildable_cells\n\n\nfunc pos_is_on_ground(pos: Vector2) -> bool:\n\tvar map_pos = _ground_indicator_map.local_to_map(pos)\n\tvar tile_data_at_pos: TileData = _ground_indicator_map.get_cell_tile_data(0, map_pos)\n\tvar tile_exists: bool = tile_data_at_pos != null\n\n\treturn tile_exists\n\n\n# NOTE: if \"allow_shared_build_space\" option is enabled,\n# then need to make all local team's players buildable areas\n# visible.\nfunc _set_buildable_area_visible(value: bool):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_team: Team = local_player.get_team()\n\tvar allow_shared_build_space: bool = local_team.get_allow_shared_build_space()\n\n\tvar player_list: Array[Player] = []\n\tif allow_shared_build_space:\n\t\tplayer_list = local_team.get_players()\n\telse:\n\t\tplayer_list.append(local_player)\n\n\tfor the_player in player_list:\n\t\tvar buildable_area: BuildableArea = _get_buildable_area(the_player)\n\t\tbuildable_area.visible = value\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_buildable_area(player: Player) -> BuildableArea:\n\tvar buildable_area_list: Array = get_tree().get_nodes_in_group(\"buildable_areas\")\n\n\tfor buildable_area in buildable_area_list:\n\t\tvar player_match: bool = buildable_area.player_id == player.get_id()\n\n\t\tif player_match:\n\t\t\treturn buildable_area\n\n\treturn null\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_player_started_build_process():\n\t_set_buildable_area_visible(true)\n\n\nfunc _on_player_stopped_build_process():\n\t_set_buildable_area_visible(false)\n"
  },
  {
    "path": "src/map/map_big.tscn",
    "content": "[gd_scene load_steps=45 format=4 uid=\"uid://chgit105npt34\"]\n\n[ext_resource type=\"Script\" path=\"res://src/map/map.gd\" id=\"1_c4qbl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dbh4ut425s1ja\" path=\"res://assets/tiles/stone_columns.png\" id=\"2_c6yxm\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://28he7nw8q1lo\" path=\"res://assets/tiles/floor.png\" id=\"3_dqo7i\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bb3cy5nc11xm4\" path=\"res://assets/tiles/planks.png\" id=\"4_832oj\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dwtspohoptiwn\" path=\"res://assets/tiles/wooden_supports.png\" id=\"5_417yo\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://8hg2mltwjvch\" path=\"res://assets/tiles/bridges.png\" id=\"6_ixaht\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ui4kf3f3fnc\" path=\"res://assets/tiles/stairs.png\" id=\"7_pouod\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b1jfa4r4faj77\" path=\"res://assets/tiles/wooden_pile.png\" id=\"8_xmk2o\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bq4bfj6wa7488\" path=\"res://assets/tiles/floor1_walls.png\" id=\"9_cmj7a\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b8kaotwoawygm\" path=\"res://assets/tiles/barrels.png\" id=\"10_6r70k\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://m7awn68i621a\" path=\"res://assets/tiles/stone_walls.png\" id=\"11_5fu56\"]\n[ext_resource type=\"TileSet\" uid=\"uid://c2ke1gy0rnehu\" path=\"res://resources/tilesets/decorations.tres\" id=\"12_axlbe\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dsaarf0j6pf6g\" path=\"res://src/map/buildable_area.tscn\" id=\"13_vfex0\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://2v03j2bnie6o\" path=\"res://assets/tiles/empty_tiles.png\" id=\"14_w7n31\"]\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_d2fx0\"]\ntile_data = PackedInt32Array(131072, 131082, 1, 131073, 131082, 1, 2, 262154, 1, 65538, 262154, 1, 131074, 393226, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_qfbjk\"]\ntile_data = PackedInt32Array(0, 262145, 6, 65536, 262145, 6, 131072, 262145, 6, 1, 262145, 6, 65537, 262145, 6, 131073, 262145, 6, 2, 262145, 6, 65538, 262145, 6, 131074, 262145, 6)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_ek0n5\"]\ntile_data = PackedInt32Array(0, 131073, 196614, 65536, 131073, 196614, 131072, 131073, 196614, 1, 131073, 196614, 65537, 131073, 196614, 131073, 131073, 196614, 196609, 131073, 196614, 2, 131073, 196614, 65538, 131073, 196614, 131074, 131073, 196614, 196610, 131073, 196614, 262146, 131073, 196614, 3, 131073, 196614, 65539, 131073, 196614, 131075, 131073, 196614, 196611, 131073, 196614, 262147, 131073, 196614, 327683, 131073, 196614, 4, 131073, 196614, 65540, 131073, 196614, 131076, 131073, 196614, 196612, 131073, 196614, 262148, 131073, 196614, 327684, 131073, 196614, 393220, 131073, 196614, 5, 196609, 6, 65541, 196609, 2, 131077, 196609, 6, 196613, 196609, 6, 262149, 1, 4, 327685, 196609, 6, 393221, 262145, 2, 458757, 196609, 6)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_h6mhp\"]\ntile_data = PackedInt32Array(0, 10, 1, 65536, 10, 1, 131072, 10, 1, 196608, 10, 1, 262144, 10, 1, 327680, 10, 1, 393216, 10, 1, 458752, 10, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_oa6ak\"]\ntile_data = PackedInt32Array(0, 10, 1, 65536, 10, 1, 131072, 10, 1, 196608, 10, 1, 262144, 10, 1, 327680, 10, 1, 393216, 10, 1, 458752, 10, 1, 1, 65541, 1, 131073, 65541, 1, 262145, 65541, 1, 393217, 65541, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_42qrd\"]\ntile_data = PackedInt32Array(0, 10, 1, 65536, 10, 1, 131072, 10, 1, 196608, 10, 1, 262144, 10, 1, 327680, 10, 1, 393216, 10, 1, 458752, 10, 1, 1, 393226, 1, 65537, 262164, 196611, 131073, 393226, 1, 196609, 262164, 196611, 262145, 393226, 1, 327681, 262164, 196611, 393217, 393226, 1, 458753, 262164, 196611)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_ijasj\"]\ntile_data = PackedInt32Array(0, 196634, 3, 65536, 262164, 196611, 131072, 196634, 3, 196608, 262164, 196611, 262144, 196634, 3, 327680, 262164, 196611, 393216, 196634, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_6nqay\"]\ntile_data = PackedInt32Array(0, 327706, 3, 131072, 327706, 3, 262144, 327706, 3, 393216, 327706, 3, 65537, 393226, 1, 131073, 65541, 1, 196609, 393226, 1, 262145, 65541, 1, 327681, 393226, 1, 393217, 65541, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_63foq\"]\ntile_data = PackedInt32Array(65536, 65536, 0, 196608, 65536, 0, 1, 131073, 6, 65537, 10, 1, 131073, 10, 1, 196609, 10, 1, 2, 196609, 6, 65538, 393226, 1, 131074, 393226, 1, 196610, 393226, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_vk3cr\"]\ntile_data = PackedInt32Array(65536, 196634, 0, 131072, 196634, 0, 196608, 196634, 0, 1, 65562, 0, 262145, 131098, 0, 2, 65562, 0, 262146, 131098, 0, 3, 65562, 0, 262147, 131098, 0, 65540, 26, 0, 131076, 26, 0, 196612, 26, 0)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_xos4k\"]\ntile_data = PackedInt32Array(0, 196629, 0, 65536, 196631, 3, 131072, 458773, 3, 196608, 196631, 3, 262144, 458773, 3, 327680, 458773, 3, 393216, 458773, 3, 458752, 458773, 3, 524288, 458773, 3, 589824, 458773, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_v4ns7\"]\ntile_data = PackedInt32Array(0, 196629, 0, 65536, 458773, 3, 131072, 458773, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_g7k4a\"]\ntile_data = PackedInt32Array(0, 262149, 131073, 65536, 262149, 131073, 131072, 262149, 131073, 196608, 262149, 131073, 262144, 262149, 131073, 327680, 262149, 131073, 393216, 262149, 131073, 458752, 262149, 131073, 524288, 262149, 131073, 589824, 262149, 131073)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_fiebi\"]\ntile_data = PackedInt32Array(0, 196633, 6, 65536, 65561, 6, 1, 131097, 6, 65537, 196633, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_jl4gk\"]\ntile_data = PackedInt32Array(0, 196628, 3, 65536, 196628, 3, 1, 393241, 3, 65537, 327705, 3, 2, 393241, 3, 65538, 327705, 3, 3, 20, 3, 65539, 262167, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_77y07\"]\ntile_data = PackedInt32Array(65536, 196634, 0, 131072, 196634, 0, 196608, 196634, 0, 262144, 196634, 0, 1, 65562, 0, 65537, 393217, 2, 131073, 196609, 6, 196609, 196609, 6, 262145, 196609, 6, 2, 65562, 0, 65538, 196609, 6, 131074, 196609, 6, 196610, 196609, 2, 262146, 196609, 6, 327682, 196609, 6, 3, 65562, 0, 65539, 196609, 6, 131075, 196609, 6, 196611, 327681, 2, 262147, 196609, 6, 327683, 196609, 6, 393219, 196609, 6, 4, 65562, 0, 65540, 196609, 6, 131076, 196609, 6, 196612, 196609, 6, 262148, 196609, 6, 327684, 196609, 6, 393220, 196609, 6, 458756, 196609, 6, 65541, 26, 0, 131077, 26, 0, 196613, 26, 0, 262149, 26, 0, 327685, 26, 0, 393221, 26, 0, 458757, 26, 0)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_1q1ay\"]\ntile_data = PackedInt32Array(0, 65562, 0, 1, 65562, 0, 131073, 458776, 0, 196609, 458776, 0, 262145, 458776, 0, 327681, 458776, 0, 393217, 458776, 0, 458753, 458776, 0, 2, 65562, 0, 65539, 26, 0, 131075, 26, 0, 196611, 26, 0, 262147, 26, 0, 327683, 26, 0, 393219, 26, 0, 458755, 26, 0, 524291, 26, 0)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_gmax7\"]\ntexture = ExtResource(\"2_c6yxm\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_lnh7f\"]\ntexture = ExtResource(\"3_dqo7i\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 44)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 44)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 44)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 44)\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 44)\n5:0/0 = 0\n5:0/0/texture_origin = Vector2i(0, 44)\n6:0/0 = 0\n6:0/0/texture_origin = Vector2i(0, 44)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 44)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 44)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 44)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 44)\n4:1/0 = 0\n4:1/0/texture_origin = Vector2i(0, 44)\n5:1/0 = 0\n5:1/0/texture_origin = Vector2i(0, 44)\n6:1/0 = 0\n6:1/0/texture_origin = Vector2i(0, 44)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 44)\n0:2/0/probability = 0.1\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 44)\n1:2/0/probability = 0.1\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 44)\n2:2/0/probability = 0.1\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 44)\n3:2/0/probability = 0.1\n4:2/0 = 0\n4:2/0/texture_origin = Vector2i(0, 44)\n4:2/0/probability = 0.1\n5:2/0 = 0\n5:2/0/texture_origin = Vector2i(0, 44)\n5:2/0/probability = 0.2\n6:2/0 = 0\n6:2/0/texture_origin = Vector2i(0, 44)\n6:2/0/probability = 0.1\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 44)\n0:3/0/probability = 0.1\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 44)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 44)\n3:3/next_alternative_id = 2\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 44)\n4:3/0 = 0\n4:3/0/texture_origin = Vector2i(0, 44)\n5:3/0 = 0\n5:3/0/texture_origin = Vector2i(0, 44)\n5:3/0/probability = 0.05\n6:3/0 = 0\n6:3/0/texture_origin = Vector2i(0, 44)\n6:3/0/probability = 0.05\n0:4/0 = 0\n0:4/0/texture_origin = Vector2i(0, 44)\n0:4/0/probability = 0.05\n1:4/0 = 0\n1:4/0/texture_origin = Vector2i(0, 44)\n1:4/0/probability = 0.05\n2:4/0 = 0\n2:4/0/texture_origin = Vector2i(0, 44)\n3:4/0 = 0\n3:4/0/texture_origin = Vector2i(0, 44)\n4:4/0 = 0\n4:4/0/texture_origin = Vector2i(0, 44)\n5:4/0 = 0\n5:4/0/texture_origin = Vector2i(0, 44)\n6:4/0 = 0\n6:4/0/texture_origin = Vector2i(0, 44)\n6:4/0/probability = 0.05\n0:5/0 = 0\n0:5/0/texture_origin = Vector2i(0, 44)\n0:5/0/probability = 0.05\n1:5/0 = 0\n1:5/0/texture_origin = Vector2i(0, 44)\n1:5/0/probability = 0.05\n2:5/0 = 0\n2:5/0/texture_origin = Vector2i(0, 44)\n2:5/0/probability = 0.05\n3:5/0 = 0\n3:5/0/texture_origin = Vector2i(0, 44)\n4:5/0 = 0\n4:5/0/texture_origin = Vector2i(0, 44)\n5:5/0 = 0\n5:5/0/texture_origin = Vector2i(0, 44)\n6:5/0 = 0\n6:5/0/texture_origin = Vector2i(0, 44)\n0:6/0 = 0\n0:6/0/texture_origin = Vector2i(0, 44)\n1:6/0 = 0\n1:6/0/texture_origin = Vector2i(0, 44)\n2:6/next_alternative_id = 5\n2:6/0 = 0\n2:6/0/texture_origin = Vector2i(0, 44)\n3:6/0 = 0\n3:6/0/texture_origin = Vector2i(0, 44)\n4:6/0 = 0\n4:6/0/texture_origin = Vector2i(0, 44)\n5:6/0 = 0\n5:6/0/texture_origin = Vector2i(0, 44)\n6:6/0 = 0\n6:6/0/texture_origin = Vector2i(0, 44)\n7:0/0 = 0\n7:0/0/texture_origin = Vector2i(0, 44)\n7:1/0 = 0\n7:1/0/texture_origin = Vector2i(0, 44)\n7:2/0 = 0\n7:2/0/texture_origin = Vector2i(0, 44)\n7:3/0 = 0\n7:3/0/texture_origin = Vector2i(0, 44)\n7:4/0 = 0\n7:4/0/texture_origin = Vector2i(0, 44)\n7:5/0 = 0\n7:5/0/texture_origin = Vector2i(0, 44)\n7:6/0 = 0\n7:6/0/texture_origin = Vector2i(0, 44)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_gxawd\"]\ntexture = ExtResource(\"4_832oj\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/next_alternative_id = 2\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_512a0\"]\nresource_name = \"wooden-supports\"\ntexture = ExtResource(\"5_417yo\")\ntexture_region_size = Vector2i(256, 384)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 128)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 128)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 128)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 128)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 128)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 128)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 128)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 128)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 128)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 128)\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 128)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 128)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 128)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 128)\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 128)\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 128)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_avgj8\"]\ntexture = ExtResource(\"6_ixaht\")\ntexture_region_size = Vector2i(256, 128)\nuse_texture_padding = false\n0:0/0 = 0\n1:0/0 = 0\n0:1/0 = 0\n1:1/0 = 0\n0:2/0 = 0\n1:2/0 = 0\n0:3/0 = 0\n1:3/0 = 0\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_a6dct\"]\ntexture = ExtResource(\"7_pouod\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/next_alternative_id = 3\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/next_alternative_id = 2\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/next_alternative_id = 4\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_1hvd6\"]\ntexture = ExtResource(\"8_xmk2o\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_koob1\"]\ntexture = ExtResource(\"9_cmj7a\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_ryqdi\"]\ntexture = ExtResource(\"10_6r70k\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_i3vo1\"]\ntexture = ExtResource(\"11_5fu56\")\ntexture_region_size = Vector2i(256, 384)\nuse_texture_padding = false\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 128)\n4:1/0 = 0\n4:1/0/texture_origin = Vector2i(0, 128)\n6:1/0 = 0\n6:1/0/texture_origin = Vector2i(0, 128)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 128)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 128)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 128)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 128)\n4:2/0 = 0\n4:2/0/texture_origin = Vector2i(0, 128)\n5:2/0 = 0\n5:2/0/texture_origin = Vector2i(0, 128)\n6:2/0 = 0\n6:2/0/texture_origin = Vector2i(0, 128)\n7:2/0 = 0\n7:2/0/texture_origin = Vector2i(0, 128)\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 128)\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 128)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 128)\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 128)\n4:3/0 = 0\n4:3/0/texture_origin = Vector2i(0, 128)\n5:3/0 = 0\n5:3/0/texture_origin = Vector2i(0, 128)\n6:3/0 = 0\n6:3/0/texture_origin = Vector2i(0, 128)\n7:3/0 = 0\n7:3/0/texture_origin = Vector2i(0, 128)\n0:5/0 = 0\n0:5/0/texture_origin = Vector2i(0, 128)\n2:5/0 = 0\n2:5/0/texture_origin = Vector2i(0, 128)\n4:5/0 = 0\n4:5/0/texture_origin = Vector2i(0, 128)\n6:5/0 = 0\n6:5/0/texture_origin = Vector2i(0, 128)\n0:6/0 = 0\n0:6/0/texture_origin = Vector2i(0, 128)\n1:6/0 = 0\n1:6/0/texture_origin = Vector2i(0, 128)\n2:6/0 = 0\n2:6/0/texture_origin = Vector2i(0, 128)\n3:6/0 = 0\n3:6/0/texture_origin = Vector2i(0, 128)\n4:6/0 = 0\n4:6/0/texture_origin = Vector2i(0, 128)\n5:6/0 = 0\n5:6/0/texture_origin = Vector2i(0, 128)\n6:6/0 = 0\n6:6/0/texture_origin = Vector2i(0, 128)\n7:6/0 = 0\n7:6/0/texture_origin = Vector2i(0, 128)\n0:7/0 = 0\n0:7/0/texture_origin = Vector2i(0, 128)\n1:7/0 = 0\n1:7/0/texture_origin = Vector2i(0, 128)\n2:7/0 = 0\n2:7/0/texture_origin = Vector2i(0, 128)\n3:7/0 = 0\n3:7/0/texture_origin = Vector2i(0, 128)\n4:7/0 = 0\n4:7/0/texture_origin = Vector2i(0, 128)\n5:7/0 = 0\n5:7/0/texture_origin = Vector2i(0, 128)\n6:7/0 = 0\n6:7/0/texture_origin = Vector2i(0, 128)\n7:7/0 = 0\n7:7/0/texture_origin = Vector2i(0, 128)\n0:9/0 = 0\n0:9/0/texture_origin = Vector2i(0, 128)\n6:9/0 = 0\n6:9/0/texture_origin = Vector2i(0, 128)\n0:10/0 = 0\n0:10/0/texture_origin = Vector2i(0, 128)\n1:10/0 = 0\n1:10/0/texture_origin = Vector2i(0, 128)\n2:10/0 = 0\n2:10/0/texture_origin = Vector2i(0, 128)\n3:10/0 = 0\n3:10/0/texture_origin = Vector2i(0, 128)\n4:10/0 = 0\n4:10/0/texture_origin = Vector2i(0, 128)\n5:10/0 = 0\n5:10/0/texture_origin = Vector2i(0, 128)\n6:10/0 = 0\n6:10/0/texture_origin = Vector2i(0, 128)\n7:10/0 = 0\n7:10/0/texture_origin = Vector2i(0, 128)\n0:11/0 = 0\n0:11/0/texture_origin = Vector2i(0, 128)\n1:11/0 = 0\n1:11/0/texture_origin = Vector2i(0, 128)\n2:11/0 = 0\n2:11/0/texture_origin = Vector2i(0, 128)\n3:11/0 = 0\n3:11/0/texture_origin = Vector2i(0, 128)\n4:11/0 = 0\n4:11/0/texture_origin = Vector2i(0, 128)\n5:11/0 = 0\n5:11/0/texture_origin = Vector2i(0, 128)\n6:11/0 = 0\n6:11/0/texture_origin = Vector2i(0, 128)\n7:11/0 = 0\n7:11/0/texture_origin = Vector2i(0, 128)\n0:13/0 = 0\n0:13/0/texture_origin = Vector2i(0, 128)\n2:13/0 = 0\n2:13/0/texture_origin = Vector2i(0, 128)\n4:13/0 = 0\n4:13/0/texture_origin = Vector2i(0, 128)\n6:13/0 = 0\n6:13/0/texture_origin = Vector2i(0, 128)\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 128)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 128)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 128)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 128)\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 128)\n5:0/0 = 0\n5:0/0/texture_origin = Vector2i(0, 128)\n6:0/0 = 0\n6:0/0/texture_origin = Vector2i(0, 128)\n7:0/0 = 0\n7:0/0/texture_origin = Vector2i(0, 128)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 128)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 128)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 128)\n5:1/0 = 0\n5:1/0/texture_origin = Vector2i(0, 128)\n7:1/0 = 0\n7:1/0/texture_origin = Vector2i(0, 128)\n0:4/0 = 0\n0:4/0/texture_origin = Vector2i(0, 128)\n1:4/0 = 0\n1:4/0/texture_origin = Vector2i(0, 128)\n2:4/0 = 0\n2:4/0/texture_origin = Vector2i(0, 128)\n3:4/0 = 0\n3:4/0/texture_origin = Vector2i(0, 128)\n4:4/0 = 0\n4:4/0/texture_origin = Vector2i(0, 128)\n5:4/0 = 0\n5:4/0/texture_origin = Vector2i(0, 128)\n6:4/0 = 0\n6:4/0/texture_origin = Vector2i(0, 128)\n7:4/0 = 0\n7:4/0/texture_origin = Vector2i(0, 128)\n1:5/0 = 0\n1:5/0/texture_origin = Vector2i(0, 128)\n3:5/0 = 0\n3:5/0/texture_origin = Vector2i(0, 128)\n5:5/0 = 0\n5:5/0/texture_origin = Vector2i(0, 128)\n7:5/0 = 0\n7:5/0/texture_origin = Vector2i(0, 128)\n0:8/0 = 0\n0:8/0/texture_origin = Vector2i(0, 128)\n1:8/0 = 0\n1:8/0/texture_origin = Vector2i(0, 128)\n2:8/0 = 0\n2:8/0/texture_origin = Vector2i(0, 128)\n3:8/0 = 0\n3:8/0/texture_origin = Vector2i(0, 128)\n4:8/0 = 0\n4:8/0/texture_origin = Vector2i(0, 128)\n5:8/0 = 0\n5:8/0/texture_origin = Vector2i(0, 128)\n6:8/0 = 0\n6:8/0/texture_origin = Vector2i(0, 128)\n7:8/0 = 0\n7:8/0/texture_origin = Vector2i(0, 128)\n7:9/0 = 0\n7:9/0/texture_origin = Vector2i(0, 128)\n5:9/0 = 0\n5:9/0/texture_origin = Vector2i(0, 128)\n4:9/0 = 0\n4:9/0/texture_origin = Vector2i(0, 128)\n3:9/0 = 0\n3:9/0/texture_origin = Vector2i(0, 128)\n2:9/0 = 0\n2:9/0/texture_origin = Vector2i(0, 128)\n1:9/0 = 0\n1:9/0/texture_origin = Vector2i(0, 128)\n0:12/0 = 0\n0:12/0/texture_origin = Vector2i(0, 128)\n1:12/0 = 0\n1:12/0/texture_origin = Vector2i(0, 128)\n2:12/0 = 0\n2:12/0/texture_origin = Vector2i(0, 128)\n3:12/0 = 0\n3:12/0/texture_origin = Vector2i(0, 128)\n4:12/0 = 0\n4:12/0/texture_origin = Vector2i(0, 128)\n5:12/0 = 0\n5:12/0/texture_origin = Vector2i(0, 128)\n6:12/0 = 0\n6:12/0/texture_origin = Vector2i(0, 128)\n7:12/0 = 0\n7:12/0/texture_origin = Vector2i(0, 128)\n1:13/0 = 0\n1:13/0/texture_origin = Vector2i(0, 128)\n3:13/0 = 0\n3:13/0/texture_origin = Vector2i(0, 128)\n5:13/0 = 0\n5:13/0/texture_origin = Vector2i(0, 128)\n7:13/0 = 0\n7:13/0/texture_origin = Vector2i(0, 128)\n\n[sub_resource type=\"TileSet\" id=\"TileSet_talwn\"]\ntile_shape = 1\ntile_layout = 5\ntile_size = Vector2i(256, 128)\nnavigation_layer_0/layers = 1\nsources/1 = SubResource(\"TileSetAtlasSource_lnh7f\")\nsources/5 = SubResource(\"TileSetAtlasSource_a6dct\")\nsources/50 = SubResource(\"TileSetAtlasSource_1hvd6\")\nsources/60 = SubResource(\"TileSetAtlasSource_ryqdi\")\nsources/2 = SubResource(\"TileSetAtlasSource_gxawd\")\nsources/4 = SubResource(\"TileSetAtlasSource_avgj8\")\nsources/6 = SubResource(\"TileSetAtlasSource_koob1\")\nsources/9 = SubResource(\"TileSetAtlasSource_i3vo1\")\nsources/0 = SubResource(\"TileSetAtlasSource_gmax7\")\nsources/3 = SubResource(\"TileSetAtlasSource_512a0\")\npattern_0 = SubResource(\"TileMapPattern_d2fx0\")\npattern_1 = SubResource(\"TileMapPattern_qfbjk\")\npattern_2 = SubResource(\"TileMapPattern_vk3cr\")\npattern_3 = SubResource(\"TileMapPattern_xos4k\")\npattern_4 = SubResource(\"TileMapPattern_v4ns7\")\npattern_5 = SubResource(\"TileMapPattern_g7k4a\")\npattern_6 = SubResource(\"TileMapPattern_fiebi\")\npattern_7 = SubResource(\"TileMapPattern_jl4gk\")\npattern_8 = SubResource(\"TileMapPattern_77y07\")\npattern_9 = SubResource(\"TileMapPattern_1q1ay\")\npattern_10 = SubResource(\"TileMapPattern_ek0n5\")\npattern_11 = SubResource(\"TileMapPattern_h6mhp\")\npattern_12 = SubResource(\"TileMapPattern_oa6ak\")\npattern_13 = SubResource(\"TileMapPattern_42qrd\")\npattern_14 = SubResource(\"TileMapPattern_ijasj\")\npattern_15 = SubResource(\"TileMapPattern_6nqay\")\npattern_16 = SubResource(\"TileMapPattern_63foq\")\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_2k3qd\"]\ntexture = ExtResource(\"14_w7n31\")\ntexture_region_size = Vector2i(256, 512)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 192)\n\n[sub_resource type=\"TileSet\" id=\"TileSet_dc62b\"]\ntile_shape = 1\ntile_layout = 5\ntile_size = Vector2i(256, 128)\nsources/1 = SubResource(\"TileSetAtlasSource_2k3qd\")\n\n[node name=\"MapBig\" type=\"Node2D\" node_paths=PackedStringArray(\"_camera_limits\", \"_ground_indicator_map\")]\ny_sort_enabled = true\nscript = ExtResource(\"1_c4qbl\")\n_camera_limits = NodePath(\"CameraLimits\")\n_ground_indicator_map = NodePath(\"GroundIndicatorMap\")\n\n[node name=\"MainTileMap\" type=\"TileMap\" parent=\".\"]\ny_sort_enabled = true\ntile_set = SubResource(\"TileSet_talwn\")\nformat = 2\nlayer_0/name = \"lvl1-flat\"\nlayer_0/y_sort_enabled = true\nlayer_0/tile_data = PackedInt32Array(-1507339, 262145, 1, -1441803, 262145, 1, -1310731, 262145, 1, -1245195, 262145, 1, -1179659, 262145, 6, -1114123, 262145, 6, -1048587, 262145, 1, -983051, 262145, 1, -917515, 327681, 2, -851979, 393217, 2, -786443, 262145, 1, -720907, 262145, 1, -655371, 262145, 1, -589835, 262145, 1, -524299, 262145, 1, -458763, 262145, 1, -393227, 262145, 1, -327691, 262145, 1, -262155, 262145, 1, -196619, 262145, 1, -131083, 327681, 3, -1638410, 393217, 6, -1572874, 393217, 6, -1507338, 327681, 6, -1441802, 458753, 6, -1376266, 393217, 6, -1310730, 262145, 6, -1245194, 65537, 0, -1179658, 196609, 5, -1114122, 262145, 6, -1048586, 131073, 6, -983050, 458753, 6, -720906, 196609, 0, -655370, 65537, 0, -589834, 458753, 4, -524298, 1, 0, -458762, 327681, 6, -393226, 393217, 6, -327690, 327681, 6, -262154, 262145, 6, -196618, 458753, 6, -131082, 327681, 1, -1638409, 262145, 6, -1572873, 458753, 6, -1507337, 327681, 6, -1441801, 458753, 6, -1376265, 393217, 6, -1310729, 327681, 6, -1245193, 131073, 6, -1114121, 262145, 6, -1048585, 393217, 6, -983049, 262145, 6, -917513, 262145, 6, -851977, 458753, 6, -786441, 262145, 6, -720905, 262145, 6, -655369, 1, 6, -589833, 1, 1, -524297, 131073, 4, -458761, 262145, 6, -393225, 262145, 6, -327689, 393217, 6, -262153, 262145, 6, -196617, 458753, 6, -131081, 327681, 1, -1507336, 458753, 1, -1441800, 458753, 1, -1376264, 458753, 1, -1310728, 458753, 1, -1245192, 458753, 1, -1179656, 458753, 1, -1114120, 458753, 1, -1048584, 458753, 1, -983048, 458753, 1, -524296, 458753, 1, -458760, 458753, 1, -393224, 458753, 1, -262152, 393217, 6, -196616, 327681, 6, -131080, 327681, 1, -327687, 393217, 1, -262151, 327681, 6, -196615, 327681, 6, -131079, 327681, 1, 196601, 327681, 5, 262137, 131073, 0, 327673, 131073, 0, 393209, 131073, 0, 458745, 131073, 0, 589817, 65537, 2, 655353, 327681, 3, 720889, 131073, 0, 786425, 131073, 0, 851961, 131073, 0, 917497, 327681, 3, -327686, 393217, 1, -262150, 262145, 6, -196614, 262145, 6, -131078, 327681, 1, 196602, 393217, 1, 327674, 262145, 6, 458746, 393217, 6, 524282, 262145, 2, 589818, 262145, 0, 655354, 262145, 0, 720890, 262145, 6, 786426, 393217, 6, 851962, 393217, 6, 917498, 327681, 1, -327685, 393217, 1, -262149, 327681, 6, -196613, 327681, 6, -131077, 327681, 1, 196603, 393217, 1, 262139, 458753, 6, 524283, 327681, 6, 589819, 1, 6, 655355, 393217, 6, 720891, 327681, 6, 786427, 262145, 6, 851963, 458753, 6, 917499, 327681, 1, -327684, 393217, 1, -196612, 458753, 6, -131076, 327681, 1, 196604, 393217, 1, 393212, 65537, 4, 458748, 458753, 1, 524284, 458753, 1, 589820, 458753, 1, 655356, 458753, 1, 720892, 196609, 4, 786428, 262145, 6, 851964, 458753, 6, 917500, 327681, 1, -1179651, 327681, 3, -1114115, 262145, 1, -1048579, 262145, 1, -983043, 262145, 1, -917507, 262145, 1, -786435, 262145, 1, -720899, 458753, 4, -655363, 327681, 5, -589827, 196609, 2, -524291, 262145, 5, -458755, 131073, 0, -393219, 262145, 1, -262147, 327681, 6, -196611, 458753, 6, -131075, 327681, 1, 196605, 393217, 1, 262141, 327681, 6, 393213, 327681, 1, 720893, 393217, 1, 786429, 393217, 6, 851965, 393217, 6, 917501, 327681, 1, -1179650, 393217, 1, -1114114, 393217, 6, -1048578, 393217, 6, -983042, 458753, 6, -917506, 393217, 6, -851970, 458753, 6, -786434, 262145, 6, -720898, 1, 1, -655362, 1, 1, -589826, 1, 1, -524290, 1, 1, -458754, 262145, 6, -393218, 393217, 6, -327682, 327681, 6, -262146, 393217, 6, -196610, 458753, 6, -131074, 327681, 1, 196606, 393217, 1, 393214, 327681, 1, 720894, 393217, 1, 786430, 327681, 6, 851966, 393217, 6, 917502, 262145, 5, -1179649, 393217, 1, -1114113, 327681, 6, -1048577, 262145, 6, -983041, 327681, 6, -917505, 393217, 6, -851969, 458753, 6, -786433, 458753, 6, -720897, 262145, 6, -655361, 458753, 6, -589825, 262145, 6, -524289, 327681, 6, -458753, 393217, 6, -393217, 327681, 6, -327681, 262145, 6, -262145, 393217, 6, -196609, 458753, 6, -131073, 327681, 1, 196607, 393217, 1, 262143, 393217, 6, 393215, 327681, 1, 720895, 393217, 1, 786431, 327681, 6, 851967, 262145, 6, 917503, 262145, 5, -1245184, 393217, 1, -1179648, 262145, 6, -1114112, 262145, 6, -1048576, 65537, 4, -983040, 458753, 1, -917504, 458753, 1, -851968, 458753, 1, -786432, 458753, 1, -720896, 458753, 1, -655360, 458753, 1, -589824, 458753, 1, -524288, 458753, 1, -458752, 458753, 1, -393216, 458753, 1, -327680, 458753, 1, -262144, 458753, 1, -196608, 327681, 3, 131072, 393217, 1, 327680, 327681, 1, 655360, 393217, 1, 720896, 393217, 6, 786432, 262145, 6, 851968, 327681, 1, -1245183, 393217, 1, -1179647, 327681, 6, -1114111, 327681, 6, -1048575, 327681, 1, 131073, 393217, 1, 196609, 262145, 6, 327681, 327681, 1, 655361, 393217, 1, 720897, 393217, 6, 786433, 458753, 6, 851969, 327681, 1, -1245182, 393217, 1, -1179646, 393217, 6, -1114110, 327681, 6, -1048574, 327681, 1, 131074, 393217, 1, 196610, 262145, 6, 327682, 327681, 1, 655362, 393217, 1, 720898, 327681, 6, 786434, 458753, 6, 851970, 327681, 1, -1245181, 393217, 1, -1179645, 458753, 6, -1048573, 327681, 1, 131075, 393217, 1, -1245180, 393217, 1, -1048572, 327681, 1, 131076, 393217, 1, 196612, 393217, 6, 327684, 327681, 1, 655364, 393217, 1, 720900, 262145, 6, 786436, 458753, 6, 851972, 327681, 1, -1245179, 393217, 1, -1048571, 1, 4, -983035, 262145, 1, -917499, 262145, 1, -851963, 262145, 1, -786427, 262145, 1, -720891, 262145, 0, -655355, 393217, 2, -589819, 327681, 2, -524283, 262145, 2, -458747, 458753, 2, -393211, 131073, 2, -327675, 262145, 1, -262139, 262145, 1, -196603, 262145, 1, -131067, 262145, 1, -65531, 262145, 1, 5, 262145, 1, 65541, 262145, 1, 131077, 131073, 4, 262149, 393217, 6, 327685, 327681, 1, 655365, 393217, 1, 720901, 262145, 6, 786437, 393217, 6, 1245189, 131073, 0, 1310725, 262145, 1, 1376261, 262145, 1, 1441797, 262145, 1, 1507333, 262145, 1, 1572869, 262145, 1, 1638405, 262145, 0, 1703941, 262145, 1, -1245178, 393217, 1, -1179642, 327681, 6, -1114106, 458753, 6, -917498, 458753, 6, -720890, 327681, 6, -589818, 327681, 6, -524282, 393217, 6, -458746, 393217, 6, -65530, 262145, 6, 327686, 327681, 1, 655366, 393217, 1, 720902, 458753, 6, 786438, 458753, 6, 851974, 262145, 6, 917510, 262145, 6, 983046, 262145, 6, 1048582, 327681, 6, 1114118, 458753, 6, 1179654, 262145, 6, 1245190, 458753, 6, 1310726, 327681, 6, 1376262, 393217, 6, 1441798, 327681, 6, 1507334, 458753, 6, 1572870, 458753, 6, 1638406, 262145, 6, 1703942, 458753, 6, -1245177, 393217, 1, -917497, 458753, 6, -524281, 458753, 6, -458745, 458753, 6, -262137, 131073, 6, 262151, 393217, 6, 327687, 327681, 1, 655367, 393217, 1, 720903, 393217, 6, 786439, 458753, 6, 851975, 393217, 6, 917511, 458753, 6, 983047, 458753, 6, 1048583, 393217, 6, 1114119, 131073, 6, 1179655, 393217, 6, 1245191, 262145, 6, 1310727, 458753, 6, 1376263, 262145, 6, 1441799, 393217, 6, 1507335, 327681, 6, 1572871, 458753, 6, 1638407, 262145, 6, 1703943, 262145, 6, -1245176, 393217, 1, -1179640, 393217, 6, -1114104, 458753, 6, -1048568, 65537, 4, -983032, 458753, 1, -917496, 458753, 1, -851960, 458753, 1, -786424, 458753, 1, -720888, 458753, 1, -655352, 458753, 1, -589816, 458753, 1, -524280, 458753, 1, -458744, 458753, 1, -393208, 458753, 1, -327672, 458753, 1, -262136, 458753, 1, -196600, 458753, 1, -131064, 458753, 1, -65528, 458753, 1, 8, 458753, 1, 65544, 458753, 1, 131080, 196609, 5, 196616, 327681, 6, 262152, 262145, 6, 327688, 327681, 1, 655368, 393217, 1, 720904, 393217, 6, 786440, 262145, 6, 851976, 65537, 5, 917512, 458753, 1, 983048, 458753, 1, 1048584, 458753, 1, 1114120, 458753, 1, 1179656, 458753, 1, 1245192, 458753, 1, 1310728, 458753, 1, 1376264, 458753, 1, 1441800, 458753, 1, 1507336, 458753, 1, 1572872, 458753, 1, 1638408, 458753, 1, 1703944, 458753, 1, -1769481, 131073, 5, -1703945, 393217, 6, -1376267, 262145, 1, -262148, 327681, 6, 851973, 1, 4, 917509, 262145, 1, 983045, 262145, 1, 1048581, 262145, 1, 1114117, 262145, 1, -851971, 262145, 1, 851971, 327681, 1, 786435, 393217, 6, 720899, 262145, 6, 655363, 393217, 1, 327683, 327681, 1, -786442, 458753, 6, -851978, 327681, 6, -917514, 131073, 4, -1638408, 458753, 1, -1703944, 458753, 1, -1769480, 458753, 1, -1572872, 458753, 1, -1703946, 458753, 6, -1769482, 393217, 6, -1835018, 393217, 6, -1900554, 327681, 6, -1966090, 393217, 6, -2031626, 393217, 6, -2097162, 327681, 6, -2162698, 262145, 6, -2228234, 458753, 6, -2293770, 393217, 6, -2228235, 262145, 1, -2162699, 262145, 1, -2097163, 262145, 1, -2031627, 262145, 1, -1966091, 262145, 1, -1900555, 262145, 1, -1835019, 262145, 1, -1769483, 262145, 1, -1703947, 262145, 1, -1638411, 262145, 1, -1835017, 327681, 6, -1900553, 458753, 6, -1966089, 458753, 6, -2031625, 327681, 6, -2097161, 262145, 6, -2162697, 262145, 6, -2228233, 458753, 6, -2293769, 393217, 6, -2359305, 393217, 6, -1572875, 262145, 1, -1835016, 458753, 1, -1900552, 458753, 1, -1966088, 458753, 1, -2031624, 458753, 1, -2097160, 458753, 1, -2162696, 458753, 1, -2228232, 458753, 1, -2293768, 458753, 1, -2359304, 458753, 1, -1114109, 262145, 6, -1179644, 262145, 6, -1114108, 262145, 6, -1179643, 458753, 6, -1114107, 458753, 6, -1179641, 262145, 6, -1114105, 262145, 6, -1048570, 327681, 6, -983034, 327681, 6, -851962, 262145, 6, -786426, 458753, 6, -655354, 327681, 6, -393210, 458753, 6, -327674, 262145, 6, -262138, 393217, 6, -196602, 458753, 6, -131066, 327681, 6, 6, 262145, 6, 65542, 393217, 6, 131078, 327681, 6, 196614, 393217, 6, 262150, 458753, 6, -1048569, 393217, 6, -983033, 327681, 6, -851961, 458753, 6, -786425, 262145, 6, -720889, 458753, 6, -655353, 458753, 6, -589817, 327681, 6, -393209, 458753, 6, -327673, 458753, 6, -196601, 327681, 6, -131065, 262145, 6, -65529, 327681, 6, 7, 327681, 6, 65543, 327681, 6, 131079, 393217, 6, 196615, 393217, 6, 262138, 262145, 6, 327675, 458753, 6, 262140, 458753, 6, 327676, 458753, 6, 327677, 393217, 6, 262142, 262145, 6, 327678, 262145, 6, 327679, 458753, 6, 196608, 327681, 6, 262144, 327681, 6, 262145, 393217, 6, 262146, 327681, 6, 196611, 327681, 6, 262147, 458753, 6, 262148, 458753, 6, 196613, 327681, 6, 393210, 262145, 6, 393211, 393217, 6, 458747, 458753, 6, -1048567, 327681, 1, -1048566, 327681, 1, -1048565, 327681, 1, -1048564, 327681, 1, -1245175, 393217, 1, -1179639, 327681, 6, -1114103, 393217, 6, -1245174, 393217, 1, -1179638, 393217, 6, -1114102, 458753, 6, -1245173, 393217, 1, -1179637, 262145, 6, -1114101, 262145, 6, -1245172, 393217, 1, -1179636, 327681, 6, -1114100, 262145, 6, -1048563, 1, 4, -983027, 262145, 3, -917491, 262145, 5, -851955, 262145, 5, -1245171, 393217, 1, -1179635, 458753, 6, -1114099, 393217, 6, -1245170, 393217, 1, -1179634, 262145, 6, -1114098, 262145, 6, -1048562, 327681, 6, -983026, 458753, 6, -917490, 131073, 0, -851954, 1, 1, -1245169, 393217, 1, -1179633, 458753, 6, -1114097, 393217, 6, -1048561, 262145, 6, -983025, 393217, 6, -917489, 262145, 6, -851953, 393217, 6, -1245168, 327681, 3, -1179632, 458753, 1, -1114096, 458753, 1, -1048560, 458753, 1, -983024, 458753, 1, -917488, 458753, 1, -851952, 458753, 1, -786419, 262145, 3, -720883, 262145, 1, -655347, 262145, 1, -589811, 262145, 1, -524275, 262145, 1, -458739, 262145, 1, -393203, 262145, 1, -327667, 262145, 1, -262131, 262145, 1, -786418, 131073, 6, -720882, 393217, 6, -655346, 458753, 6, -589810, 393217, 6, -524274, 393217, 6, -458738, 262145, 6, -393202, 327681, 6, -327666, 262145, 6, -262130, 393217, 6, -786417, 262145, 6, -720881, 393217, 6, -655345, 327681, 6, -589809, 327681, 6, -524273, 262145, 6, -458737, 262145, 6, -393201, 327681, 6, -327665, 458753, 6, -262129, 262145, 6, -786416, 458753, 1, -720880, 458753, 1, -655344, 458753, 1, -589808, 458753, 1, -524272, 458753, 1, -458736, 458753, 1, -393200, 196609, 4, -327664, 327681, 6, -262128, 393217, 6, -196595, 458753, 3, -196594, 327681, 1, -196593, 327681, 1, -196592, 327681, 1, -327663, 327681, 6, -262127, 327681, 6, -196591, 327681, 1, -393199, 393217, 1, -393198, 393217, 1, -327662, 458753, 6, -262126, 458753, 6, -196590, 327681, 1, -393197, 393217, 1, -327661, 458753, 6, -262125, 262145, 6, -196589, 327681, 1, -393196, 393217, 1, -327660, 458753, 6, -262124, 458753, 6, -196588, 327681, 1, -458731, 262145, 1, -393195, 131073, 4, -327659, 393217, 6, -262123, 327681, 6, -196587, 327681, 1, -458730, 393217, 6, -393194, 393217, 6, -327658, 262145, 6, -262122, 327681, 6, -196586, 327681, 1, -458729, 458753, 6, -393193, 327681, 6, -327657, 458753, 6, -262121, 262145, 6, -196585, 327681, 1, -458728, 458753, 1, -393192, 458753, 1, -327656, 458753, 1, -262120, 458753, 1, -196584, 458753, 3, -1638379, 262145, 1, -1572843, 262145, 1, -1507307, 262145, 1, -1441771, 262145, 1, -1376235, 262145, 1, -1310699, 262145, 5, -1179627, 262145, 1, -1114091, 262145, 1, -1048555, 262145, 1, -983019, 262145, 1, -917483, 262145, 0, -851947, 393217, 2, -786411, 327681, 2, -720875, 262145, 2, -655339, 458753, 2, -589803, 131073, 2, -524267, 262145, 1, -1638378, 262145, 6, -1572842, 327681, 6, -1507306, 458753, 6, -1441770, 262145, 6, -1376234, 327681, 6, -1179626, 393217, 6, -1114090, 458753, 6, -1048554, 262145, 6, -983018, 458753, 6, -917482, 327681, 6, -851946, 327681, 6, -786410, 327681, 6, -720874, 393217, 6, -655338, 393217, 6, -589802, 458753, 6, -524266, 262145, 6, -1638377, 262145, 6, -1572841, 458753, 6, -1507305, 262145, 6, -1441769, 262145, 6, -1179625, 327681, 6, -1114089, 393217, 6, -1048553, 262145, 6, -983017, 262145, 6, -917481, 458753, 6, -851945, 458753, 6, -786409, 327681, 6, -720873, 458753, 6, -655337, 458753, 6, -589801, 458753, 6, -524265, 458753, 6, -1638376, 458753, 1, -1572840, 458753, 1, -1507304, 458753, 1, -1441768, 458753, 1, -1376232, 458753, 1, -1310696, 458753, 1, -1245160, 458753, 1, -1179624, 458753, 1, -1114088, 458753, 1, -1048552, 458753, 1, -983016, 458753, 1, -917480, 458753, 1, -851944, 458753, 1, -786408, 458753, 1, -720872, 458753, 1, -655336, 458753, 1, -589800, 458753, 1, -524264, 458753, 1, -2162667, 262145, 1, -2097131, 262145, 1, -2031595, 262145, 1, -1966059, 262145, 1, -1900523, 262145, 1, -1834987, 262145, 1, -1769451, 262145, 1, -1703915, 262145, 1, -2097130, 393217, 6, -2031594, 393217, 6, -1966058, 458753, 6, -1900522, 65537, 0, -1834986, 458753, 0, -1769450, 131073, 6, -1703914, 458753, 6, -2097129, 327681, 6, -2031593, 262145, 6, -1966057, 262145, 6, -1834985, 131073, 5, -1769449, 393217, 6, -1703913, 262145, 6, -1966056, 458753, 1, -1900520, 458753, 1, -1834984, 458753, 1, -1769448, 458753, 1, -1703912, 458753, 1, 131081, 393217, 1, 196617, 393217, 6, 262153, 458753, 6, 327689, 327681, 1, 131082, 393217, 1, 196618, 393217, 6, 262154, 458753, 6, 327690, 327681, 1, 131083, 393217, 1, 196619, 393217, 6, 262155, 327681, 6, 327691, 327681, 1, 131084, 393217, 1, 196620, 458753, 6, 262156, 327681, 6, 327692, 327681, 1, 131085, 393217, 1, 196621, 393217, 6, 262157, 262145, 6, 327693, 327681, 1, 131086, 393217, 1, 196622, 393217, 6, 262158, 327681, 6, 327694, 327681, 1, 131087, 393217, 1, 196623, 327681, 6, 262159, 393217, 6, 327695, 327681, 1, 131088, 393217, 1, 196624, 393217, 6, 262160, 393217, 6, 327696, 327681, 1, 131089, 393217, 1, 196625, 393217, 6, 262161, 393217, 6, 327697, 1, 4, 131090, 393217, 1, 196626, 393217, 6, 262162, 262145, 6, 327698, 262145, 6, 131091, 393217, 1, 196627, 327681, 6, 262163, 393217, 6, 327699, 458753, 6, 131092, 327681, 3, 196628, 458753, 1, 262164, 458753, 1, 327700, 458753, 1, 655369, 393217, 1, 720905, 458753, 6, 786441, 393217, 6, 851977, 327681, 1, 655370, 393217, 1, 720906, 458753, 6, 786442, 262145, 6, 851978, 327681, 1, 655371, 393217, 1, 720907, 327681, 6, 786443, 458753, 6, 851979, 327681, 1, 655372, 393217, 1, 720908, 458753, 6, 786444, 393217, 6, 851980, 327681, 1, 655373, 393217, 1, 720909, 327681, 6, 786445, 327681, 6, 851981, 327681, 1, 655374, 393217, 1, 720910, 458753, 6, 786446, 393217, 6, 851982, 327681, 1, 655375, 393217, 1, 720911, 393217, 6, 786447, 393217, 6, 851983, 327681, 1, 655376, 393217, 1, 720912, 393217, 6, 786448, 393217, 6, 851984, 327681, 1, 655377, 393217, 0, 851985, 327681, 1, 393236, 458753, 1, 524308, 458753, 1, 589844, 458753, 1, 655380, 458753, 1, 720916, 458753, 1, 786452, 458753, 1, 851988, 262145, 3, -917512, 458753, 1, -851976, 458753, 1, -786440, 458753, 1, -720904, 458753, 1, -655368, 458753, 1, -589832, 458753, 1, 655378, 393217, 6, 720914, 458753, 6, 786450, 393217, 6, 851986, 327681, 1, 655379, 458753, 6, 720915, 327681, 6, 786451, 393217, 6, 851987, 327681, 1, 458769, 262145, 5, 524305, 262145, 5, 458770, 1, 1, 524306, 1, 1, 589842, 131073, 0, 393235, 458753, 6, 458771, 458753, 6, 524307, 131073, 6, 589843, 393217, 6, 393233, 262145, 1, 589841, 196609, 2, 720913, 327681, 6, 393234, 262145, 6, 458772, 458753, 1, -327688, 196609, 4, -327683, 131073, 4, -2293771, 262145, 1, -2359307, 262145, 1, -2359306, 393217, 6, 786449, 393217, 6, 524281, 65537, 4, 524280, 1, 2, -1572852, 131073, 2, -1572851, 131073, 2, -1638387, 131073, 2, -1638388, 131073, 2, -1179661, 393217, 6, -1245197, 393217, 6, -1245196, 1, 6, -1114125, 327681, 6, -1114124, 196609, 6, -1179660, 327681, 6, -1310732, 458753, 6, -1310733, 458753, 6, -1310734, 196609, 6, -1245198, 131073, 6, -1179662, 262145, 6, -1114126, 1, 6, -1310698, 327681, 4, -1245162, 1, 0, -1245161, 393217, 6, -1310697, 1, 6, -1245163, 262145, 2, -1245164, 327681, 5, -1310700, 327681, 5, -1179628, 327681, 5, -1376236, 327681, 5, -1900521, 1, 1, -1179657, 327681, 6, 1179653, 327681, 5, 1966084, 327681, 3, 2031620, 131073, 5, 2097156, 327681, 6, 2162692, 327681, 6, 2228228, 1, 5, 2293764, 393217, 3, 1966085, 131073, 5, 2031621, 327681, 6, 2097157, 393217, 6, 2162693, 262145, 6, 2228229, 393217, 6, 2293765, 1, 5, 1966086, 393217, 6, 2031622, 327681, 6, 2097158, 393217, 6, 2162694, 393217, 6, 2228230, 458753, 6, 2293766, 458753, 6, 1966087, 262145, 6, 2031623, 458753, 6, 2097159, 327681, 6, 2162695, 327681, 6, 2228231, 327681, 6, 2293767, 327681, 6, 1966088, 196609, 5, 2031624, 458753, 6, 2097160, 458753, 6, 2162696, 327681, 6, 2228232, 458753, 6, 2293768, 65537, 5, 1966089, 458753, 3, 2031625, 458753, 1, 2097161, 458753, 6, 2162697, 458753, 6, 2228233, 65537, 4, 2293769, 393217, 3, 1769478, 327681, 6, 1769479, 393217, 6, 1835015, 458753, 6, 1900551, 327681, 6, 1900550, 262145, 6, 1835014, 327681, 6, 1769477, 262145, 1, 1835013, 262145, 1, 1900549, 262145, 1, 1769480, 458753, 1, 1835016, 458753, 1, 1900552, 458753, 1, 2359301, 262145, 1, 2424837, 262145, 1, 2490373, 262145, 1, 2555909, 262145, 1, 2621445, 262145, 1, 2686981, 262145, 1, 2752517, 262145, 1, 2818053, 262145, 1, 2883589, 262145, 1, 2949125, 262145, 1, 3014661, 262145, 1, 3080197, 262145, 1, 3145733, 262145, 1, 3211269, 262145, 1, 3276805, 262145, 1, 3342341, 262145, 1, 2359302, 262145, 6, 2424838, 262145, 6, 2490374, 327681, 6, 2555910, 458753, 6, 2621446, 262145, 6, 2686982, 458753, 6, 2752518, 327681, 6, 2818054, 393217, 6, 2883590, 327681, 6, 2949126, 458753, 6, 3014662, 458753, 6, 3080198, 262145, 6, 3145734, 458753, 6, 3211270, 327681, 6, 3276806, 327681, 6, 3342342, 262145, 6, 2359303, 327681, 6, 2424839, 458753, 6, 2490375, 393217, 6, 2555911, 458753, 6, 2621447, 393217, 6, 2686983, 262145, 6, 2752519, 458753, 6, 2818055, 262145, 6, 2883591, 393217, 6, 2949127, 327681, 6, 3014663, 458753, 6, 3080199, 262145, 6, 3145735, 196609, 6, 3211271, 393217, 6, 3276807, 458753, 6, 3342343, 327681, 6, 2359304, 458753, 1, 2424840, 458753, 1, 2490376, 458753, 1, 2555912, 458753, 1, 2621448, 458753, 1, 2686984, 458753, 1, 2752520, 458753, 1, 2818056, 458753, 1, 2883592, 458753, 1, 2949128, 458753, 1, 3014664, 458753, 1, 3080200, 458753, 1, 3145736, 458753, 1, 3211272, 458753, 1, 3276808, 458753, 1, 3342344, 458753, 1, 3473401, 327681, 5, 3538937, 262145, 1, 3604473, 262145, 1, 3670009, 262145, 1, 3735545, 131073, 0, 3801081, 262145, 1, 3866617, 65537, 2, 3932153, 327681, 3, 3997689, 262145, 1, 4063225, 262145, 1, 4128761, 262145, 1, 4194297, 327681, 3, 3473402, 393217, 1, 3538938, 262145, 6, 3604474, 262145, 6, 3670010, 262145, 6, 3735546, 393217, 6, 3801082, 262145, 2, 3866618, 262145, 0, 3932154, 262145, 0, 3997690, 262145, 6, 4063226, 393217, 6, 4128762, 393217, 6, 4194298, 327681, 1, 3473403, 393217, 1, 3538939, 458753, 6, 3604475, 458753, 6, 3670011, 393217, 6, 3735547, 458753, 6, 3801083, 1, 6, 3866619, 327681, 6, 3932155, 393217, 6, 3997691, 327681, 6, 4063227, 262145, 6, 4128763, 458753, 6, 4194299, 327681, 1, 3473404, 393217, 1, 3538940, 458753, 6, 3604476, 458753, 6, 3670012, 65537, 4, 3735548, 458753, 1, 3801084, 458753, 1, 3866620, 458753, 1, 3932156, 458753, 1, 3997692, 196609, 4, 4063228, 262145, 6, 4128764, 458753, 6, 4194300, 327681, 1, 3473405, 393217, 1, 3538941, 327681, 6, 3604477, 393217, 6, 3670013, 327681, 1, 3997693, 393217, 1, 4063229, 393217, 6, 4128765, 393217, 6, 4194301, 327681, 1, 3473406, 393217, 1, 3538942, 262145, 6, 3604478, 262145, 6, 3670014, 327681, 1, 3997694, 393217, 1, 4063230, 327681, 6, 4128766, 393217, 6, 4194302, 262145, 5, 3473407, 393217, 1, 3538943, 393217, 6, 3604479, 458753, 6, 3670015, 327681, 1, 3997695, 393217, 1, 4063231, 327681, 6, 4128767, 262145, 6, 4194303, 262145, 5, 3407872, 393217, 1, 3473408, 327681, 6, 3538944, 327681, 6, 3604480, 327681, 1, 3932160, 393217, 1, 3997696, 393217, 6, 4063232, 262145, 6, 4128768, 327681, 1, 3407873, 393217, 1, 3473409, 262145, 6, 3538945, 393217, 6, 3604481, 327681, 1, 3932161, 393217, 1, 3997697, 393217, 6, 4063233, 458753, 6, 4128769, 327681, 1, 3407874, 393217, 1, 3473410, 262145, 6, 3538946, 327681, 6, 3604482, 327681, 1, 3932162, 393217, 1, 3997698, 327681, 6, 4063234, 458753, 6, 4128770, 327681, 1, 3407875, 393217, 1, 3473411, 327681, 6, 3538947, 458753, 6, 3604483, 327681, 1, 3932163, 393217, 1, 3997699, 262145, 6, 4063235, 393217, 6, 4128771, 327681, 1, 3407876, 393217, 1, 3473412, 393217, 6, 3538948, 458753, 6, 3604484, 327681, 1, 3932164, 393217, 1, 3997700, 262145, 6, 4063236, 458753, 6, 4128772, 327681, 1, 3407877, 131073, 4, 3473413, 327681, 6, 3538949, 393217, 6, 3604485, 327681, 1, 3932165, 393217, 1, 3997701, 262145, 6, 4063237, 393217, 6, 4128773, 1, 4, 3407878, 327681, 6, 3473414, 393217, 6, 3538950, 458753, 6, 3604486, 327681, 1, 3932166, 393217, 1, 3997702, 458753, 6, 4063238, 458753, 6, 4128774, 262145, 6, 3407879, 393217, 6, 3473415, 393217, 6, 3538951, 393217, 6, 3604487, 327681, 1, 3932167, 393217, 1, 3997703, 393217, 6, 4063239, 458753, 6, 4128775, 393217, 6, 3407880, 196609, 5, 3473416, 327681, 6, 3538952, 262145, 6, 3604488, 327681, 1, 3932168, 393217, 1, 3997704, 393217, 6, 4063240, 262145, 6, 4128776, 65537, 5, 3407881, 393217, 1, 3473417, 393217, 6, 3538953, 458753, 6, 3604489, 327681, 1, 3932169, 393217, 1, 3997705, 458753, 6, 4063241, 393217, 6, 4128777, 327681, 1, 3407882, 393217, 1, 3473418, 393217, 6, 3538954, 458753, 6, 3604490, 327681, 1, 3932170, 393217, 1, 3997706, 458753, 6, 4063242, 262145, 6, 4128778, 327681, 1, 3407883, 393217, 1, 3473419, 393217, 6, 3538955, 327681, 6, 3604491, 327681, 1, 3932171, 393217, 1, 3997707, 327681, 6, 4063243, 458753, 6, 4128779, 327681, 1, 3407884, 393217, 1, 3473420, 458753, 6, 3538956, 327681, 6, 3604492, 327681, 1, 3932172, 393217, 1, 3997708, 458753, 6, 4063244, 393217, 6, 4128780, 327681, 1, 3407885, 393217, 1, 3473421, 393217, 6, 3538957, 262145, 6, 3604493, 327681, 1, 3932173, 393217, 1, 3997709, 327681, 6, 4063245, 327681, 6, 4128781, 327681, 1, 3407886, 393217, 1, 3473422, 393217, 6, 3538958, 327681, 6, 3604494, 327681, 1, 3932174, 393217, 1, 3997710, 458753, 6, 4063246, 393217, 6, 4128782, 327681, 1, 3407887, 393217, 1, 3473423, 327681, 6, 3538959, 393217, 6, 3604495, 327681, 1, 3932175, 393217, 1, 3997711, 393217, 6, 4063247, 393217, 6, 4128783, 327681, 1, 3407888, 393217, 1, 3473424, 393217, 6, 3538960, 393217, 6, 3604496, 327681, 1, 3932176, 393217, 1, 3997712, 393217, 6, 4063248, 393217, 6, 4128784, 327681, 1, 3407889, 393217, 1, 3473425, 393217, 6, 3538961, 393217, 6, 3604497, 1, 4, 3670033, 262145, 1, 3735569, 262145, 5, 3801105, 262145, 5, 3866641, 196609, 2, 3932177, 393217, 0, 3997713, 327681, 6, 4063249, 393217, 6, 4128785, 327681, 1, 3407890, 393217, 1, 3473426, 393217, 6, 3538962, 262145, 6, 3604498, 262145, 6, 3670034, 262145, 6, 3735570, 1, 1, 3801106, 1, 1, 3866642, 131073, 0, 3932178, 393217, 6, 3997714, 458753, 6, 4063250, 393217, 6, 4128786, 327681, 1, 3407891, 393217, 1, 3473427, 327681, 6, 3538963, 393217, 6, 3604499, 458753, 6, 3670035, 458753, 6, 3735571, 65537, 6, 3801107, 327681, 6, 3866643, 393217, 6, 3932179, 458753, 6, 3997715, 327681, 6, 4063251, 393217, 6, 4128787, 327681, 1, 3407892, 327681, 3, 3473428, 458753, 1, 3538964, 458753, 1, 3604500, 458753, 1, 3670036, 458753, 1, 3735572, 458753, 1, 3801108, 458753, 1, 3866644, 458753, 1, 3932180, 458753, 1, 3997716, 458753, 1, 4063252, 458753, 1, 4128788, 262145, 3, 4194309, 262145, 1, 4259845, 262145, 1, 4325381, 262145, 1, 4390917, 262145, 1, 4456453, 262145, 0, 4521989, 393217, 2, 4587525, 327681, 2, 4653061, 262145, 2, 4718597, 458753, 2, 4784133, 131073, 2, 4849669, 262145, 1, 4915205, 262145, 1, 4980741, 262145, 1, 5046277, 262145, 1, 5111813, 262145, 1, 5177349, 262145, 1, 5242885, 262145, 1, 4194310, 327681, 6, 4259846, 458753, 6, 4325382, 262145, 6, 4390918, 458753, 6, 4456454, 327681, 6, 4521990, 1, 6, 4587526, 327681, 6, 4653062, 393217, 6, 4718598, 393217, 6, 4784134, 458753, 6, 4849670, 262145, 6, 4915206, 393217, 6, 4980742, 458753, 6, 5046278, 262145, 6, 5111814, 327681, 6, 5177350, 327681, 6, 5242886, 393217, 6, 4194311, 327681, 6, 4259847, 458753, 6, 4325383, 458753, 6, 4390919, 262145, 6, 4456455, 458753, 6, 4521991, 458753, 6, 4587527, 327681, 6, 4653063, 458753, 6, 4718599, 458753, 6, 4784135, 458753, 6, 4849671, 458753, 6, 4915207, 458753, 6, 4980743, 327681, 6, 5046279, 327681, 6, 5111815, 458753, 6, 5177351, 327681, 6, 5242887, 393217, 6, 4194312, 458753, 1, 4259848, 458753, 1, 4325384, 458753, 1, 4390920, 458753, 1, 4456456, 458753, 1, 4521992, 458753, 1, 4587528, 458753, 1, 4653064, 458753, 1, 4718600, 458753, 1, 4784136, 458753, 1, 4849672, 458753, 1, 4915208, 458753, 1, 4980744, 458753, 1, 5046280, 458753, 1, 5111816, 458753, 1, 5177352, 458753, 1, 5242888, 458753, 1, 5373949, 327681, 3, 5439485, 262145, 1, 5505021, 262145, 1, 5570557, 327681, 1, 5373950, 327681, 6, 5439486, 262145, 6, 5505022, 262145, 6, 5570558, 327681, 1, 5373951, 393217, 6, 5439487, 262145, 6, 5505023, 458753, 6, 5570559, 327681, 1, 5308416, 393217, 1, 5373952, 262145, 6, 5439488, 262145, 6, 5505024, 327681, 1, 5308417, 393217, 1, 5373953, 327681, 6, 5439489, 327681, 6, 5505025, 327681, 1, 5308418, 393217, 1, 5373954, 393217, 6, 5439490, 327681, 6, 5505026, 327681, 1, 5308419, 393217, 1, 5373955, 458753, 6, 5439491, 262145, 6, 5505027, 327681, 1, 5308420, 393217, 1, 5373956, 262145, 6, 5439492, 262145, 6, 5505028, 327681, 1, 5308421, 131073, 5, 5373957, 458753, 6, 5439493, 458753, 6, 5505029, 327681, 1, 5308422, 262145, 6, 5373958, 327681, 6, 5439494, 458753, 6, 5505030, 327681, 1, 5308423, 327681, 6, 5373959, 262145, 6, 5439495, 262145, 6, 5505031, 327681, 1, 5308424, 196609, 5, 5373960, 393217, 6, 5439496, 458753, 6, 5505032, 327681, 1, 5308425, 393217, 1, 5373961, 327681, 6, 5439497, 393217, 6, 5505033, 327681, 1, 5308426, 393217, 1, 5373962, 393217, 6, 5439498, 458753, 6, 5505034, 327681, 1, 5308427, 393217, 1, 5373963, 262145, 6, 5439499, 262145, 6, 5505035, 327681, 1, 5308428, 393217, 1, 5373964, 327681, 6, 5439500, 262145, 6, 5505036, 327681, 1, 5308429, 131073, 5, 5373965, 458753, 6, 5439501, 393217, 6, 5505037, 327681, 1, 5308430, 393217, 6, 5373966, 262145, 6, 5439502, 393217, 6, 5505038, 327681, 1, 5308431, 262145, 6, 5373967, 458753, 6, 5439503, 262145, 6, 5505039, 327681, 1, 5308432, 458753, 1, 5373968, 458753, 1, 5439504, 458753, 1, 5505040, 327681, 1, 4456461, 327681, 2, 4521997, 393217, 2, 4587533, 262145, 1, 4653069, 262145, 1, 4718605, 262145, 1, 4784141, 262145, 1, 4849677, 262145, 1, 4915213, 262145, 1, 4980749, 262145, 1, 5046285, 262145, 1, 5111821, 262145, 1, 5177357, 262145, 1, 5242893, 327681, 3, 4456462, 393217, 1, 4521998, 327681, 6, 4587534, 458753, 6, 4653070, 196609, 0, 4718606, 65537, 0, 4784142, 458753, 4, 4849678, 1, 0, 4915214, 327681, 6, 4980750, 393217, 6, 5046286, 327681, 6, 5111822, 393217, 6, 5177358, 262145, 6, 5242894, 262145, 6, 4456463, 393217, 1, 4521999, 393217, 6, 4587535, 327681, 6, 4653071, 262145, 6, 4718607, 1, 6, 4784143, 1, 1, 4849679, 131073, 4, 4915215, 262145, 6, 4980751, 262145, 6, 5046287, 393217, 6, 5111823, 458753, 6, 5177359, 458753, 6, 5242895, 393217, 6, 4456464, 393217, 1, 4522000, 262145, 6, 4587536, 458753, 6, 4653072, 65537, 5, 4718608, 458753, 1, 4784144, 458753, 1, 4849680, 458753, 1, 4915216, 458753, 1, 4980752, 458753, 1, 5046288, 458753, 1, 5111824, 458753, 1, 5177360, 458753, 1, 5242896, 458753, 1, 4456469, 393217, 1, 4522005, 458753, 6, 4587541, 327681, 6, 4653077, 1, 5, 4718613, 327681, 5, 4784149, 196609, 2, 4849685, 262145, 5, 4915221, 131073, 0, 4980757, 262145, 1, 5046293, 262145, 1, 5111829, 262145, 1, 5177365, 262145, 1, 5242901, 262145, 1, 4456470, 393217, 1, 4522006, 458753, 6, 4587542, 327681, 6, 4653078, 458753, 6, 4718614, 393217, 6, 4784150, 327681, 6, 4849686, 327681, 6, 4915222, 262145, 6, 4980758, 458753, 6, 5046294, 393217, 6, 5111830, 458753, 6, 5177366, 262145, 6, 5242902, 262145, 6, 4456471, 393217, 1, 4522007, 262145, 6, 4587543, 327681, 6, 4653079, 262145, 6, 4718615, 458753, 6, 4784151, 458753, 6, 4849687, 458753, 6, 4915223, 327681, 6, 4980759, 458753, 6, 5046295, 393217, 6, 5111831, 327681, 6, 5177367, 327681, 6, 5242903, 393217, 6, 4456472, 393217, 1, 4522008, 458753, 1, 4587544, 458753, 1, 4653080, 458753, 1, 4718616, 458753, 1, 4784152, 458753, 1, 4849688, 458753, 1, 4915224, 458753, 1, 4980760, 458753, 1, 5046296, 458753, 1, 5111832, 458753, 1, 5177368, 458753, 1, 5242904, 458753, 1, 4521973, 327681, 2, 4587509, 393217, 2, 4653045, 262145, 1, 4718581, 262145, 1, 4784117, 262145, 1, 4849653, 262145, 1, 4915189, 262145, 1, 4980725, 262145, 1, 5046261, 262145, 1, 5111797, 262145, 1, 5177333, 262145, 1, 5242869, 262145, 1, 5308405, 262145, 1, 4521974, 393217, 1, 4587510, 327681, 6, 4653046, 458753, 6, 4718582, 196609, 0, 4784118, 65537, 0, 4849654, 458753, 4, 4915190, 1, 0, 4980726, 327681, 6, 5046262, 393217, 6, 5111798, 327681, 6, 5177334, 262145, 6, 5242870, 458753, 6, 5308406, 65537, 0, 4521975, 393217, 1, 4587511, 393217, 6, 4653047, 327681, 6, 4718583, 262145, 6, 4784119, 1, 6, 4849655, 1, 1, 4915191, 131073, 4, 4980727, 262145, 6, 5046263, 262145, 6, 5111799, 393217, 6, 5177335, 262145, 6, 5242871, 458753, 6, 5308407, 131073, 6, 4521976, 393217, 1, 4587512, 262145, 6, 4653048, 262145, 6, 4718584, 65537, 5, 4784120, 458753, 1, 4849656, 458753, 1, 4915192, 458753, 1, 4980728, 458753, 1, 5046264, 458753, 1, 5111800, 458753, 1, 5177336, 458753, 1, 5242872, 458753, 1, 5308408, 458753, 1, 4521981, 393217, 1, 4587517, 458753, 6, 4653053, 458753, 6, 4718589, 1, 5, 4784125, 327681, 5, 4849661, 196609, 2, 4915197, 262145, 5, 4980733, 131073, 0, 5046269, 262145, 1, 5111805, 262145, 1, 5177341, 262145, 1, 5242877, 262145, 1, 5308413, 262145, 1, 4521982, 393217, 1, 4587518, 262145, 6, 4653054, 458753, 6, 4718590, 458753, 6, 4784126, 262145, 6, 4849662, 458753, 6, 4915198, 393217, 6, 4980734, 262145, 6, 5046270, 262145, 6, 5111806, 327681, 6, 5177342, 262145, 6, 5242878, 393217, 6, 5308414, 262145, 6, 4521983, 393217, 1, 4587519, 327681, 6, 4653055, 393217, 6, 4718591, 393217, 6, 4784127, 327681, 6, 4849663, 458753, 6, 4915199, 262145, 6, 4980735, 327681, 6, 5046271, 393217, 6, 5111807, 327681, 6, 5177343, 393217, 6, 5242879, 458753, 6, 5308415, 393217, 6, 4456448, 393217, 1, 4521984, 458753, 1, 4587520, 458753, 1, 4653056, 458753, 1, 4718592, 458753, 1, 4784128, 458753, 1, 4849664, 458753, 1, 4915200, 458753, 1, 4980736, 458753, 1, 5046272, 458753, 1, 5111808, 458753, 1, 5177344, 458753, 1, 5242880, 327681, 3, 4456465, 393217, 1, 4522001, 262145, 6, 4587537, 262145, 6, 4653073, 327681, 1, 4456466, 393217, 1, 4522002, 393217, 6, 4587538, 458753, 6, 4653074, 327681, 1, 4456467, 393217, 1, 4522003, 262145, 6, 4587539, 458753, 6, 4653075, 327681, 1, 4456468, 393217, 1, 4522004, 262145, 6, 4587540, 393217, 6, 4653076, 327681, 1, 4521977, 393217, 1, 4587513, 262145, 6, 4653049, 393217, 6, 4718585, 327681, 1, 4521978, 393217, 1, 4587514, 262145, 6, 4653050, 393217, 6, 4718586, 327681, 1, 4521979, 393217, 1, 4587515, 262145, 6, 4653051, 393217, 6, 4718587, 327681, 1, 4521980, 393217, 1, 4587516, 458753, 6, 4653052, 327681, 6, 4718588, 327681, 1, 5373941, 262145, 1, 5439477, 262145, 1, 5505013, 262145, 1, 5570549, 327681, 2, 5373942, 196609, 5, 5439478, 131073, 6, 5505014, 458753, 6, 5570550, 131073, 4, 5373943, 262145, 6, 5439479, 393217, 6, 5505015, 262145, 6, 5570551, 262145, 6, 5373944, 458753, 1, 5439480, 458753, 1, 5505016, 458753, 1, 5570552, 458753, 1, 5308437, 262145, 1, 5373973, 262145, 1, 5439509, 262145, 1, 5505045, 327681, 2, 5308438, 327681, 6, 5373974, 262145, 6, 5439510, 458753, 6, 5505046, 262145, 6, 5308439, 262145, 6, 5373975, 393217, 6, 5439511, 327681, 6, 5505047, 393217, 6, 5308440, 458753, 1, 5373976, 458753, 1, 5439512, 458753, 1, 5505048, 458753, 1, 5636085, 262145, 1, 5701621, 262145, 1, 5767157, 262145, 1, 5832693, 262145, 1, 5898229, 262145, 1, 5963765, 262145, 1, 6029301, 262145, 1, 6094837, 262145, 1, 6160373, 262145, 1, 6225909, 262145, 1, 6291445, 262145, 1, 6356981, 262145, 1, 6422517, 262145, 1, 6488053, 262145, 1, 5636086, 196609, 6, 5701622, 262145, 6, 5767158, 262145, 6, 5832694, 458753, 6, 5898230, 327681, 6, 5963766, 393217, 6, 6029302, 393217, 6, 6094838, 458753, 6, 6160374, 131073, 5, 6225910, 458753, 0, 6291446, 131073, 6, 6356982, 458753, 6, 6422518, 262145, 6, 6488054, 327681, 6, 5636087, 327681, 6, 5701623, 458753, 6, 5767159, 393217, 6, 5832695, 393217, 6, 5898231, 327681, 6, 5963767, 327681, 6, 6029303, 262145, 6, 6094839, 262145, 6, 6160375, 1, 1, 6225911, 262145, 0, 6291447, 393217, 6, 6356983, 262145, 6, 6422519, 262145, 6, 6488055, 458753, 6, 5636088, 458753, 1, 5701624, 458753, 1, 5767160, 458753, 1, 5832696, 458753, 1, 5898232, 458753, 1, 5963768, 458753, 1, 6029304, 458753, 1, 6094840, 458753, 1, 6160376, 458753, 1, 6225912, 458753, 1, 6291448, 458753, 1, 6356984, 458753, 1, 6422520, 458753, 1, 6488056, 458753, 1, 2031626, 327681, 5, 2097162, 393217, 6, 2162698, 393217, 6, 2228234, 327681, 1, 2031627, 393217, 1, 2097163, 262145, 6, 2162699, 262145, 6, 2228235, 327681, 1, 2031628, 393217, 1, 2097164, 458753, 6, 2162700, 458753, 6, 2228236, 327681, 1, 2031629, 393217, 1, 2097165, 458753, 6, 2162701, 458753, 6, 2228237, 327681, 1, 2031630, 393217, 1, 2097166, 327681, 6, 2162702, 393217, 6, 2228238, 327681, 1, 2031631, 393217, 1, 2097167, 262145, 6, 2162703, 262145, 6, 2228239, 327681, 1, 2031632, 393217, 1, 2097168, 393217, 6, 2162704, 458753, 6, 2228240, 327681, 1, 2031633, 393217, 1, 2097169, 327681, 6, 2162705, 327681, 6, 2228241, 327681, 1, 2031634, 393217, 1, 2097170, 262145, 6, 2162706, 393217, 6, 2228242, 327681, 1, 2031635, 393217, 1, 2097171, 262145, 6, 2162707, 327681, 6, 2228243, 327681, 1, 2031636, 393217, 1, 2097172, 327681, 6, 2162708, 458753, 6, 2228244, 327681, 1, 2031637, 393217, 1, 2097173, 393217, 6, 2162709, 458753, 6, 2228245, 327681, 1, 2031638, 393217, 1, 2097174, 262145, 6, 2162710, 131073, 6, 2228246, 327681, 1, 2031639, 393217, 1, 2097175, 458753, 6, 2162711, 327681, 6, 2228247, 327681, 1, 2031640, 393217, 1, 2097176, 458753, 6, 2162712, 458753, 6, 2228248, 327681, 1, 2097140, 393217, 1, 2162676, 327681, 6, 2228212, 458753, 6, 2293748, 327681, 1, 2097141, 393217, 1, 2162677, 458753, 6, 2228213, 458753, 6, 2293749, 327681, 1, 2097142, 393217, 1, 2162678, 327681, 6, 2228214, 393217, 6, 2293750, 327681, 1, 2097143, 393217, 1, 2162679, 65537, 6, 2228215, 458753, 6, 2293751, 327681, 1, 2097144, 393217, 1, 2162680, 393217, 6, 2228216, 262145, 6, 2293752, 327681, 1, 2097145, 393217, 1, 2162681, 262145, 6, 2228217, 327681, 6, 2293753, 327681, 1, 2097146, 393217, 1, 2162682, 458753, 6, 2228218, 327681, 6, 2293754, 327681, 1, 2097147, 393217, 1, 2162683, 327681, 6, 2228219, 393217, 6, 2293755, 327681, 1, 2097148, 393217, 1, 2162684, 327681, 6, 2228220, 458753, 6, 2293756, 327681, 1, 2097149, 393217, 1, 2162685, 393217, 6, 2228221, 262145, 6, 2293757, 327681, 1, 2097150, 393217, 1, 2162686, 393217, 6, 2228222, 393217, 6, 2293758, 327681, 1, 2097151, 393217, 1, 2162687, 458753, 6, 2228223, 393217, 6, 2293759, 327681, 1, 2031616, 393217, 1, 2097152, 262145, 6, 2162688, 393217, 6, 2228224, 327681, 1, 2031617, 393217, 1, 2097153, 262145, 6, 2162689, 458753, 6, 2228225, 327681, 1, 2031618, 393217, 1, 2097154, 327681, 6, 2162690, 393217, 6, 2228226, 327681, 1, 2031619, 393217, 1, 2097155, 458753, 6, 2162691, 327681, 6, 2228227, 327681, 1, 2097136, 262145, 1, 2162672, 262145, 1, 2228208, 262145, 1, 2293744, 262145, 1, 2359280, 327681, 5, 2424816, 131073, 0, 2490352, 262145, 1, 2555888, 262145, 1, 2621424, 262145, 1, 2686960, 262145, 1, 2752496, 262145, 1, 2818032, 262145, 0, 2883568, 131073, 4, 2949104, 262145, 6, 3014640, 262145, 6, 3080176, 327681, 1, 2097137, 262145, 6, 2162673, 262145, 6, 2228209, 327681, 6, 2293745, 262145, 6, 2359281, 458753, 6, 2424817, 393217, 6, 2490353, 262145, 6, 2555889, 262145, 6, 2621425, 327681, 6, 2686961, 458753, 6, 2752497, 262145, 6, 2818033, 393217, 6, 2883569, 327681, 6, 2949105, 393217, 6, 3014641, 393217, 6, 3080177, 327681, 1, 2097138, 327681, 6, 2162674, 327681, 6, 2228210, 393217, 6, 2293746, 327681, 6, 2359282, 393217, 6, 2424818, 262145, 6, 2490354, 327681, 6, 2555890, 262145, 6, 2621426, 327681, 6, 2686962, 327681, 6, 2752498, 393217, 6, 2818034, 262145, 6, 2883570, 327681, 6, 2949106, 262145, 6, 3014642, 262145, 6, 3080178, 327681, 1, 2097139, 196609, 4, 2162675, 262145, 6, 2228211, 458753, 6, 2293747, 65537, 4, 2359283, 458753, 1, 2424819, 458753, 1, 2490355, 458753, 1, 2555891, 458753, 1, 2621427, 458753, 1, 2686963, 458753, 1, 2752499, 458753, 1, 2818035, 458753, 1, 2883571, 458753, 1, 2949107, 458753, 1, 3014643, 458753, 1, 3080179, 262145, 3, 1310704, 393217, 1, 1376240, 458753, 6, 1441776, 393217, 6, 1507312, 1, 4, 1572848, 262145, 1, 1638384, 131073, 0, 1703920, 262145, 1, 1769456, 262145, 1, 1834992, 262145, 1, 1900528, 262145, 1, 1966064, 262145, 1, 2031600, 262145, 0, 1310705, 393217, 1, 1376241, 458753, 6, 1441777, 393217, 6, 1507313, 393217, 6, 1572849, 327681, 6, 1638385, 262145, 6, 1703921, 458753, 6, 1769457, 393217, 6, 1834993, 262145, 6, 1900529, 327681, 6, 1966065, 458753, 6, 2031601, 327681, 6, 1310706, 393217, 1, 1376242, 458753, 6, 1441778, 458753, 6, 1507314, 393217, 6, 1572850, 393217, 6, 1638386, 393217, 6, 1703922, 262145, 6, 1769458, 262145, 6, 1834994, 458753, 6, 1900530, 327681, 6, 1966066, 327681, 6, 2031602, 393217, 6, 1310707, 393217, 3, 1376243, 458753, 1, 1441779, 458753, 1, 1507315, 458753, 1, 1572851, 458753, 1, 1638387, 458753, 1, 1703923, 458753, 1, 1769459, 458753, 1, 1834995, 458753, 1, 1900531, 458753, 1, 1966067, 458753, 1, 2031603, 458753, 1, 2818078, 393217, 1, 2883614, 393217, 6, 2949150, 262145, 6, 3014686, 327681, 1, 2818079, 393217, 1, 2883615, 196609, 6, 2949151, 327681, 6, 3014687, 327681, 1, 2818080, 393217, 1, 2883616, 327681, 6, 2949152, 393217, 6, 3014688, 327681, 1, 2818081, 393217, 1, 2883617, 393217, 6, 2949153, 393217, 6, 3014689, 327681, 1, 2818082, 131073, 5, 2883618, 393217, 6, 2949154, 458753, 6, 3014690, 327681, 1, 2818083, 393217, 6, 2883619, 458753, 6, 2949155, 458753, 6, 3014691, 327681, 1, 2818084, 458753, 6, 2883620, 458753, 6, 2949156, 262145, 6, 3014692, 327681, 1, 2818085, 458753, 1, 2883621, 458753, 1, 2949157, 458753, 1, 3014693, 262145, 3, 1245214, 393217, 1, 1310750, 262145, 6, 1376286, 458753, 6, 1441822, 327681, 1, 1245215, 393217, 1, 1310751, 262145, 6, 1376287, 131073, 6, 1441823, 327681, 1, 1245216, 393217, 1, 1310752, 393217, 6, 1376288, 327681, 6, 1441824, 327681, 1, 1245217, 393217, 1, 1310753, 262145, 6, 1376289, 393217, 6, 1441825, 327681, 1, 1245218, 393217, 1, 1310754, 458753, 6, 1376290, 327681, 6, 1441826, 1, 5, 1245219, 393217, 1, 1310755, 393217, 6, 1376291, 327681, 6, 1441827, 458753, 6, 1245220, 393217, 1, 1310756, 262145, 6, 1376292, 458753, 6, 1441828, 393217, 6, 1245221, 393217, 3, 1310757, 458753, 1, 1376293, 458753, 1, 1441829, 458753, 1, 2031641, 393217, 1, 2097177, 262145, 6, 2162713, 393217, 6, 2228249, 327681, 1, 1245210, 393217, 3, 1310746, 262145, 1, 1376282, 262145, 1, 1441818, 262145, 1, 1507354, 262145, 1, 1572890, 131073, 0, 1638426, 262145, 1, 1703962, 262145, 1, 1769498, 262145, 1, 1835034, 262145, 1, 1900570, 262145, 1, 1966106, 262145, 0, 2031642, 131073, 5, 2097178, 262145, 6, 2162714, 393217, 6, 2228250, 1, 5, 2293786, 327681, 5, 2359322, 131073, 0, 2424858, 262145, 1, 2490394, 262145, 1, 2555930, 262145, 1, 2621466, 262145, 1, 2687002, 262145, 1, 2752538, 262145, 0, 2818074, 262145, 1, 2883610, 262145, 1, 2949146, 262145, 1, 3014682, 262145, 3, 1245211, 393217, 1, 1310747, 262145, 6, 1376283, 262145, 6, 1441819, 458753, 6, 1507355, 262145, 6, 1572891, 262145, 6, 1638427, 262145, 6, 1703963, 262145, 6, 1769499, 262145, 6, 1835035, 262145, 6, 1900571, 327681, 6, 1966107, 327681, 6, 2031643, 262145, 6, 2097179, 262145, 6, 2162715, 327681, 6, 2228251, 327681, 6, 2293787, 458753, 6, 2359323, 327681, 6, 2424859, 393217, 6, 2490395, 393217, 6, 2555931, 393217, 6, 2621467, 327681, 6, 2687003, 393217, 6, 2752539, 327681, 6, 2818075, 458753, 6, 2883611, 393217, 6, 2949147, 393217, 6, 3014683, 327681, 1, 1245212, 393217, 1, 1310748, 458753, 6, 1376284, 262145, 6, 1441820, 262145, 6, 1507356, 458753, 6, 1572892, 458753, 6, 1638428, 327681, 6, 1703964, 262145, 6, 1769500, 327681, 6, 1835036, 327681, 6, 1900572, 327681, 6, 1966108, 458753, 6, 2031644, 458753, 6, 2097180, 327681, 6, 2162716, 393217, 6, 2228252, 262145, 6, 2293788, 458753, 6, 2359324, 393217, 6, 2424860, 327681, 6, 2490396, 458753, 6, 2555932, 393217, 6, 2621468, 393217, 6, 2687004, 262145, 6, 2752540, 393217, 6, 2818076, 458753, 6, 2883612, 327681, 6, 2949148, 393217, 6, 3014684, 327681, 1, 1245213, 393217, 1, 1310749, 458753, 6, 1376285, 458753, 6, 1441821, 65537, 5, 1507357, 458753, 1, 1572893, 458753, 1, 1638429, 458753, 1, 1703965, 458753, 1, 1769501, 458753, 1, 1835037, 458753, 1, 1900573, 458753, 1, 1966109, 458753, 1, 2031645, 458753, 1, 2097181, 458753, 1, 2162717, 458753, 1, 2228253, 458753, 1, 2293789, 458753, 1, 2359325, 458753, 1, 2424861, 458753, 1, 2490397, 458753, 1, 2555933, 458753, 1, 2621469, 458753, 1, 2687005, 458753, 1, 2752541, 458753, 1, 2818077, 196609, 5, 2883613, 458753, 6, 2949149, 327681, 6, 3014685, 327681, 1, 1507362, 262145, 1, 1572898, 131073, 0, 1638434, 262145, 1, 1703970, 262145, 1, 1769506, 262145, 1, 1835042, 262145, 1, 1900578, 262145, 1, 1966114, 262145, 0, 2031650, 262145, 1, 2097186, 262145, 1, 2162722, 262145, 1, 2228258, 262145, 1, 2293794, 262145, 1, 2359330, 131073, 0, 2424866, 262145, 1, 2490402, 262145, 1, 2555938, 262145, 1, 2621474, 262145, 1, 2687010, 262145, 1, 2752546, 262145, 0, 1507363, 393217, 6, 1572899, 458753, 6, 1638435, 393217, 6, 1703971, 327681, 6, 1769507, 327681, 6, 1835043, 458753, 6, 1900579, 327681, 6, 1966115, 393217, 6, 2031651, 327681, 6, 2097187, 262145, 6, 2162723, 262145, 6, 2228259, 393217, 6, 2293795, 327681, 6, 2359331, 393217, 6, 2424867, 458753, 6, 2490403, 458753, 6, 2555939, 458753, 6, 2621475, 327681, 6, 2687011, 458753, 6, 2752547, 262145, 6, 1507364, 327681, 6, 1572900, 327681, 6, 1638436, 393217, 6, 1703972, 393217, 6, 1769508, 458753, 6, 1835044, 393217, 6, 1900580, 458753, 6, 1966116, 262145, 6, 2031652, 327681, 6, 2097188, 458753, 6, 2162724, 327681, 6, 2228260, 393217, 6, 2293796, 458753, 6, 2359332, 393217, 6, 2424868, 458753, 6, 2490404, 458753, 6, 2555940, 458753, 6, 2621476, 393217, 6, 2687012, 262145, 6, 2752548, 458753, 6, 1507365, 458753, 1, 1572901, 458753, 1, 1638437, 458753, 1, 1703973, 458753, 1, 1769509, 458753, 1, 1835045, 458753, 1, 1900581, 458753, 1, 1966117, 458753, 1, 2031653, 196609, 4, 2097189, 458753, 6, 2162725, 458753, 6, 2228261, 65537, 4, 2293797, 458753, 1, 2359333, 458753, 1, 2424869, 458753, 1, 2490405, 458753, 1, 2555941, 458753, 1, 2621477, 458753, 1, 2687013, 458753, 1, 2752549, 458753, 1, 1310696, 393217, 3, 1376232, 262145, 1, 1441768, 262145, 1, 1507304, 262145, 1, 1572840, 262145, 1, 1638376, 131073, 0, 1703912, 262145, 1, 1769448, 262145, 1, 1834984, 262145, 1, 1900520, 262145, 1, 1966056, 262145, 1, 2031592, 262145, 0, 2097128, 131073, 4, 2162664, 393217, 6, 2228200, 458753, 6, 2293736, 1, 4, 2359272, 327681, 5, 2424808, 131073, 0, 2490344, 262145, 1, 2555880, 262145, 1, 2621416, 262145, 1, 2686952, 262145, 1, 2752488, 262145, 1, 2818024, 262145, 0, 2883560, 262145, 1, 2949096, 262145, 1, 3014632, 262145, 1, 3080168, 458753, 3, 1310697, 393217, 1, 1376233, 327681, 6, 1441769, 458753, 6, 1507305, 327681, 6, 1572841, 458753, 6, 1638377, 458753, 6, 1703913, 393217, 6, 1769449, 458753, 6, 1834985, 393217, 6, 1900521, 327681, 6, 1966057, 458753, 6, 2031593, 262145, 6, 2097129, 458753, 6, 2162665, 393217, 6, 2228201, 393217, 6, 2293737, 262145, 6, 2359273, 262145, 6, 2424809, 458753, 6, 2490345, 327681, 6, 2555881, 393217, 6, 2621417, 327681, 6, 2686953, 458753, 6, 2752489, 458753, 6, 2818025, 393217, 6, 2883561, 327681, 6, 2949097, 262145, 6, 3014633, 458753, 6, 3080169, 327681, 1, 1310698, 393217, 1, 1376234, 262145, 6, 1441770, 458753, 6, 1507306, 393217, 6, 1572842, 327681, 6, 1638378, 393217, 6, 1703914, 393217, 6, 1769450, 262145, 6, 1834986, 262145, 6, 1900522, 327681, 6, 1966058, 458753, 6, 2031594, 262145, 6, 2097130, 262145, 6, 2162666, 393217, 6, 2228202, 262145, 6, 2293738, 327681, 6, 2359274, 393217, 6, 2424810, 262145, 6, 2490346, 458753, 6, 2555882, 262145, 6, 2621418, 393217, 6, 2686954, 327681, 6, 2752490, 327681, 6, 2818026, 458753, 6, 2883562, 458753, 6, 2949098, 327681, 6, 3014634, 262145, 6, 3080170, 327681, 1, 1310699, 393217, 1, 1376235, 262145, 6, 1441771, 327681, 6, 1507307, 65537, 4, 1572843, 458753, 1, 1638379, 458753, 1, 1703915, 458753, 1, 1769451, 458753, 1, 1834987, 458753, 1, 1900523, 458753, 1, 1966059, 458753, 1, 2031595, 458753, 1, 2097131, 458753, 1, 2162667, 458753, 1, 2228203, 458753, 1, 2293739, 458753, 1, 2359275, 458753, 1, 2424811, 458753, 1, 2490347, 458753, 1, 2555883, 458753, 1, 2621419, 458753, 1, 2686955, 458753, 1, 2752491, 458753, 1, 2818027, 458753, 1, 2883563, 196609, 4, 2949099, 327681, 6, 3014635, 327681, 6, 3080171, 327681, 1, 2883564, 393217, 1, 2949100, 262145, 6, 3014636, 458753, 6, 3080172, 327681, 1, 2883565, 393217, 1, 2949101, 393217, 6, 3014637, 262145, 6, 3080173, 327681, 1, 2883566, 393217, 1, 2949102, 65537, 6, 3014638, 327681, 6, 3080174, 327681, 1, 2883567, 393217, 1, 2949103, 458753, 6, 3014639, 458753, 6, 3080175, 327681, 1, 1310700, 393217, 1, 1376236, 458753, 6, 1441772, 262145, 6, 1507308, 327681, 1, 1310701, 393217, 1, 1376237, 262145, 6, 1441773, 393217, 6, 1507309, 327681, 1, 1310702, 393217, 1, 1376238, 393217, 6, 1441774, 1, 6, 1507310, 327681, 1, 1310703, 393217, 1, 1376239, 458753, 6, 1441775, 393217, 6, 1507311, 327681, 1, 2031654, 393217, 1, 2097190, 393217, 6, 2162726, 458753, 6, 2228262, 327681, 1, 2031655, 393217, 1, 2097191, 393217, 6, 2162727, 458753, 6, 2228263, 327681, 1, 2031656, 393217, 1, 2097192, 458753, 6, 2162728, 262145, 6, 2228264, 327681, 1, 2031657, 393217, 1, 2097193, 393217, 6, 2162729, 393217, 6, 2228265, 327681, 1, 2097112, 393217, 1, 2162648, 327681, 6, 2228184, 458753, 6, 2293720, 327681, 1, 2097113, 393217, 1, 2162649, 458753, 6, 2228185, 262145, 6, 2293721, 327681, 1, 2097114, 393217, 1, 2162650, 262145, 6, 2228186, 262145, 6, 2293722, 327681, 1, 2097115, 393217, 1, 2162651, 458753, 6, 2228187, 327681, 6, 2293723, 327681, 1, 2097116, 393217, 1, 2162652, 262145, 6, 2228188, 458753, 6, 2293724, 327681, 1, 2097117, 393217, 1, 2162653, 458753, 6, 2228189, 327681, 6, 2293725, 327681, 1, 2097118, 393217, 1, 2162654, 262145, 6, 2228190, 262145, 6, 2293726, 327681, 1, 2097119, 393217, 1, 2162655, 327681, 6, 2228191, 393217, 6, 2293727, 327681, 1, 2097120, 393217, 1, 2162656, 262145, 6, 2228192, 327681, 6, 2293728, 327681, 1, 2097121, 393217, 1, 2162657, 458753, 6, 2228193, 458753, 6, 2293729, 327681, 1, 2097122, 393217, 1, 2162658, 1, 6, 2228194, 393217, 6, 2293730, 327681, 1, 2097123, 393217, 1, 2162659, 393217, 6, 2228195, 458753, 6, 2293731, 327681, 1, 2097124, 393217, 1, 2162660, 327681, 6, 2228196, 393217, 6, 2293732, 327681, 1, 2097125, 393217, 1, 2162661, 262145, 6, 2228197, 393217, 6, 2293733, 327681, 1, 2097126, 393217, 1, 2162662, 262145, 6, 2228198, 327681, 6, 2293734, 327681, 1, 2097127, 393217, 1, 2162663, 262145, 6, 2228199, 458753, 6, 2293735, 327681, 1, 2097108, 262145, 1, 2162644, 262145, 1, 2228180, 262145, 1, 2293716, 262145, 0, 2359252, 327681, 5, 2424788, 131073, 0, 2490324, 262145, 1, 2555860, 262145, 1, 2621396, 262145, 1, 2686932, 262145, 1, 2752468, 262145, 1, 2818004, 393217, 3, 2097109, 327681, 6, 2162645, 458753, 6, 2228181, 327681, 6, 2293717, 262145, 6, 2359253, 262145, 6, 2424789, 458753, 6, 2490325, 327681, 6, 2555861, 393217, 6, 2621397, 327681, 6, 2686933, 327681, 6, 2752469, 458753, 6, 2818005, 327681, 1, 2097110, 393217, 6, 2162646, 458753, 6, 2228182, 458753, 6, 2293718, 262145, 6, 2359254, 393217, 6, 2424790, 262145, 6, 2490326, 458753, 6, 2555862, 262145, 6, 2621398, 393217, 6, 2686934, 327681, 6, 2752470, 393217, 6, 2818006, 327681, 1, 2097111, 196609, 4, 2162647, 393217, 6, 2228183, 458753, 6, 2293719, 65537, 4, 2359255, 458753, 1, 2424791, 458753, 1, 2490327, 458753, 1, 2555863, 458753, 1, 2621399, 196609, 4, 2686935, 393217, 6, 2752471, 262145, 6, 2818007, 327681, 1, 1572820, 458753, 3, 1638356, 262145, 1, 1703892, 262145, 1, 1769428, 262145, 1, 1834964, 262145, 1, 1900500, 131073, 0, 1966036, 262145, 1, 2031572, 262145, 1, 1572821, 393217, 1, 1638357, 458753, 6, 1703893, 393217, 6, 1769429, 262145, 6, 1834965, 262145, 6, 1900501, 458753, 6, 1966037, 327681, 6, 2031573, 393217, 6, 1572822, 393217, 1, 1638358, 262145, 6, 1703894, 262145, 6, 1769430, 327681, 6, 1834966, 393217, 6, 1900502, 262145, 6, 1966038, 458753, 6, 2031574, 262145, 6, 1572823, 393217, 1, 1638359, 458753, 6, 1703895, 458753, 6, 1769431, 65537, 4, 1834967, 458753, 1, 1900503, 458753, 1, 1966039, 458753, 1, 2031575, 458753, 1, 2621400, 327681, 3, 2686936, 327681, 6, 2752472, 262145, 6, 2818008, 327681, 1, 2621401, 393217, 1, 2686937, 458753, 6, 2752473, 262145, 6, 2818009, 327681, 1, 2621402, 393217, 1, 2686938, 393217, 6, 2752474, 262145, 6, 2818010, 327681, 1, 2621403, 393217, 1, 2686939, 262145, 6, 2752475, 393217, 6, 2818011, 327681, 1, 2621404, 393217, 1, 2686940, 458753, 6, 2752476, 327681, 6, 2818012, 327681, 1, 2621405, 393217, 1, 2686941, 458753, 6, 2752477, 262145, 6, 2818013, 327681, 1, 2621406, 393217, 1, 2686942, 458753, 6, 2752478, 262145, 6, 2818014, 327681, 1, 2621407, 393217, 1, 2686943, 393217, 6, 2752479, 393217, 6, 2818015, 327681, 1, 2621408, 393217, 1, 2686944, 458753, 6, 2752480, 458753, 6, 2818016, 1, 4, 2621409, 393217, 1, 2686945, 327681, 6, 2752481, 327681, 6, 2818017, 262145, 6, 2621410, 393217, 1, 2686946, 393217, 6, 2752482, 262145, 6, 2818018, 262145, 6, 2621411, 327681, 3, 2686947, 458753, 1, 2752483, 458753, 1, 2818019, 458753, 1, 1572824, 327681, 3, 1638360, 262145, 6, 1703896, 327681, 6, 1769432, 327681, 1, 1572825, 393217, 1, 1638361, 458753, 6, 1703897, 393217, 6, 1769433, 327681, 1, 1572826, 393217, 1, 1638362, 458753, 6, 1703898, 458753, 6, 1769434, 327681, 1, 1572827, 393217, 1, 1638363, 458753, 6, 1703899, 393217, 6, 1769435, 327681, 1, 1572828, 393217, 1, 1638364, 458753, 6, 1703900, 327681, 6, 1769436, 327681, 1, 1572829, 393217, 1, 1638365, 393217, 6, 1703901, 262145, 6, 1769437, 327681, 1, 1572830, 393217, 1, 1638366, 327681, 6, 1703902, 458753, 6, 1769438, 327681, 1, 1572831, 393217, 1, 1638367, 262145, 6, 1703903, 458753, 6, 1769439, 327681, 1, 1572832, 131073, 4, 1638368, 327681, 6, 1703904, 393217, 6, 1769440, 327681, 1, 1572833, 458753, 6, 1638369, 327681, 6, 1703905, 458753, 6, 1769441, 327681, 1, 1572834, 458753, 6, 1638370, 393217, 6, 1703906, 327681, 6, 1769442, 327681, 1, 1572835, 458753, 1, 1638371, 458753, 1, 1703907, 458753, 1, 1769443, 393217, 3, 2818090, 262145, 1, 2883626, 262145, 1, 2949162, 262145, 1, 3014698, 262145, 1, 3080234, 262145, 1, 3145770, 262145, 1, 3211306, 262145, 1, 3276842, 327681, 3, 2818091, 458753, 6, 2883627, 458753, 6, 2949163, 458753, 6, 3014699, 393217, 6, 3080235, 262145, 6, 3276843, 327681, 1, 2818092, 393217, 6, 2883628, 327681, 6, 2949164, 393217, 6, 3014700, 458753, 6, 3080236, 393217, 6, 3276844, 327681, 1, 2818093, 458753, 1, 2883629, 458753, 1, 2949165, 458753, 1, 3014701, 458753, 1, 3080237, 196609, 4, 3276845, 327681, 1, 983082, 327681, 5, 1048618, 262145, 1, 1114154, 262145, 1, 1179690, 131073, 0, 1245226, 327681, 5, 1310762, 131073, 0, 1376298, 262145, 1, 1441834, 262145, 1, 983083, 393217, 1, 1114155, 458753, 6, 1179691, 327681, 6, 1245227, 327681, 6, 1310763, 262145, 6, 1376299, 262145, 6, 1441835, 262145, 6, 983084, 393217, 1, 1114156, 393217, 6, 1179692, 327681, 6, 1245228, 327681, 6, 1310764, 393217, 6, 1376300, 458753, 6, 1441836, 393217, 6, 983085, 393217, 1, 1114157, 458753, 6, 1179693, 65537, 4, 1245229, 458753, 1, 1310765, 458753, 1, 1376301, 458753, 1, 1441837, 458753, 1, 1048544, 393217, 1, 1114080, 393217, 6, 1179616, 327681, 6, 1245152, 1, 4, 1310688, 262145, 1, 1376224, 131073, 0, 1441760, 262145, 1, 1507296, 262145, 1, 1048545, 393217, 1, 1114081, 262145, 6, 1179617, 393217, 6, 1245153, 262145, 6, 1310689, 458753, 6, 1376225, 262145, 6, 1441761, 458753, 6, 1507297, 262145, 6, 1048546, 393217, 1, 1114082, 458753, 6, 1179618, 327681, 6, 1245154, 458753, 6, 1310690, 458753, 6, 1376226, 393217, 6, 1441762, 458753, 6, 1507298, 458753, 6, 1048547, 458753, 3, 1114083, 458753, 1, 1179619, 458753, 1, 1245155, 458753, 1, 1310691, 458753, 1, 1376227, 458753, 1, 1441763, 458753, 1, 1507299, 458753, 1, 2883552, 262145, 1, 2949088, 131073, 0, 3014624, 262145, 1, 3080160, 262145, 1, 3145696, 131073, 4, 3211232, 262145, 6, 3276768, 458753, 6, 3342304, 327681, 1, 2883553, 262145, 6, 2949089, 458753, 6, 3014625, 327681, 6, 3080161, 393217, 6, 3145697, 327681, 6, 3211233, 458753, 6, 3276769, 393217, 6, 3342305, 327681, 1, 2883554, 393217, 6, 2949090, 262145, 6, 3014626, 458753, 6, 3080162, 262145, 6, 3145698, 393217, 6, 3211234, 262145, 6, 3276770, 262145, 6, 3342306, 327681, 1, 2883555, 458753, 1, 2949091, 458753, 1, 3014627, 458753, 1, 3080163, 458753, 1, 3145699, 458753, 1, 3211235, 458753, 1, 3276771, 458753, 1, 3342307, 458753, 3, 1048532, 327681, 5, 1114068, 458753, 6, 1179604, 393217, 6, 1245140, 131073, 0, 1048533, 393217, 1, 1114069, 458753, 6, 1179605, 393217, 6, 1245141, 327681, 1, 1048534, 393217, 1, 1114070, 393217, 6, 1179606, 262145, 6, 1245142, 327681, 1, 1048535, 393217, 1, 1114071, 393217, 6, 1179607, 327681, 6, 1245143, 327681, 1, 1048536, 393217, 1, 1114072, 458753, 6, 1179608, 327681, 6, 1245144, 327681, 1, 1048537, 393217, 1, 1114073, 262145, 6, 1179609, 327681, 6, 1245145, 327681, 1, 1048538, 393217, 1, 1114074, 327681, 6, 1179610, 458753, 6, 1245146, 327681, 1, 1048539, 393217, 1, 1114075, 458753, 6, 1179611, 458753, 6, 1245147, 327681, 1, 1048540, 393217, 1, 1114076, 393217, 6, 1179612, 262145, 6, 1245148, 327681, 1, 1048541, 393217, 1, 1114077, 393217, 6, 1179613, 458753, 6, 1245149, 327681, 1, 1048542, 393217, 1, 1114078, 393217, 6, 1179614, 327681, 6, 1245150, 327681, 1, 1048543, 393217, 1, 1114079, 458753, 6, 1179615, 262145, 6, 1245151, 327681, 1, 3145684, 327681, 5, 3211220, 393217, 6, 3276756, 393217, 6, 3342292, 327681, 1, 3145685, 393217, 1, 3211221, 393217, 6, 3276757, 393217, 6, 3342293, 327681, 1, 3145686, 393217, 1, 3211222, 262145, 6, 3276758, 262145, 6, 3342294, 327681, 1, 3145687, 393217, 1, 3211223, 327681, 6, 3276759, 393217, 6, 3342295, 327681, 1, 3145688, 393217, 1, 3211224, 458753, 6, 3276760, 262145, 6, 3342296, 327681, 1, 3145689, 393217, 1, 3211225, 262145, 6, 3276761, 262145, 6, 3342297, 327681, 1, 3145690, 393217, 1, 3211226, 327681, 6, 3276762, 262145, 6, 3342298, 327681, 1, 3145691, 393217, 1, 3211227, 327681, 6, 3276763, 458753, 6, 3342299, 327681, 1, 3145692, 393217, 1, 3211228, 262145, 6, 3276764, 458753, 6, 3342300, 327681, 1, 3145693, 393217, 1, 3211229, 458753, 6, 3276765, 393217, 6, 3342301, 327681, 1, 3145694, 393217, 1, 3211230, 393217, 6, 3276766, 393217, 6, 3342302, 327681, 1, 3145695, 393217, 1, 3211231, 262145, 6, 3276767, 262145, 6, 3342303, 327681, 1, 3080238, 393217, 1, 3276846, 327681, 1, 3080239, 393217, 1, 3276847, 327681, 1, 3080240, 393217, 1, 3276848, 327681, 1, 3080241, 393217, 1, 3276849, 327681, 1, 3080242, 393217, 1, 3276850, 327681, 1, 3080243, 393217, 1, 3276851, 327681, 1, 3080244, 393217, 1, 3276852, 327681, 1, 3080245, 393217, 1, 3276853, 327681, 1, 3080246, 393217, 1, 3145782, 327681, 6, 3276854, 327681, 1, 3080247, 393217, 1, 3145783, 393217, 6, 3276855, 327681, 1, 3080248, 393217, 1, 3145784, 393217, 6, 3276856, 327681, 1, 3080249, 393217, 1, 3145785, 327681, 6, 3276857, 327681, 1, 983086, 393217, 1, 1114158, 393217, 6, 1179694, 327681, 1, 983087, 393217, 1, 1114159, 262145, 6, 1179695, 327681, 1, 983088, 393217, 1, 1114160, 458753, 6, 1179696, 327681, 1, 983089, 393217, 1, 1114161, 327681, 6, 1179697, 327681, 1, 983090, 393217, 1, 1114162, 393217, 6, 1179698, 327681, 1, 983091, 393217, 1, 1114163, 327681, 6, 1179699, 327681, 1, 983092, 393217, 1, 1114164, 458753, 6, 1179700, 327681, 1, 983093, 393217, 1, 1114165, 458753, 6, 1179701, 327681, 1, 983094, 393217, 1, 1114166, 393217, 6, 1179702, 327681, 1, 983095, 393217, 1, 1114167, 458753, 6, 1179703, 327681, 1, 983096, 393217, 1, 1114168, 393217, 6, 1179704, 327681, 1, 983097, 393217, 1, 1114169, 262145, 6, 1179705, 327681, 1, 1507374, 393217, 1, 1572910, 327681, 6, 1638446, 458753, 6, 1703982, 327681, 1, 2031662, 393217, 1, 2097198, 262145, 6, 2162734, 327681, 6, 2228270, 327681, 1, 2555950, 393217, 1, 2621486, 393217, 6, 2687022, 458753, 6, 2752558, 327681, 1, 1507375, 393217, 1, 1572911, 262145, 6, 1638447, 327681, 6, 1703983, 327681, 1, 2031663, 393217, 1, 2097199, 262145, 6, 2162735, 458753, 6, 2228271, 327681, 1, 2555951, 393217, 1, 2621487, 262145, 6, 2687023, 393217, 6, 2752559, 327681, 1, 1507376, 393217, 1, 1572912, 262145, 6, 1638448, 458753, 6, 1703984, 327681, 1, 2031664, 393217, 1, 2097200, 458753, 6, 2162736, 458753, 6, 2228272, 327681, 1, 2555952, 393217, 1, 2621488, 262145, 6, 2687024, 262145, 6, 2752560, 327681, 1, 1507377, 393217, 1, 1572913, 327681, 6, 1638449, 458753, 6, 1703985, 327681, 1, 2031665, 393217, 1, 2097201, 393217, 6, 2162737, 458753, 6, 2228273, 327681, 1, 2555953, 393217, 1, 2621489, 393217, 6, 2687025, 327681, 6, 2752561, 327681, 1, 1507378, 393217, 1, 1572914, 327681, 6, 1638450, 262145, 6, 1703986, 327681, 1, 2031666, 393217, 1, 2097202, 393217, 6, 2162738, 262145, 6, 2228274, 327681, 1, 2555954, 393217, 1, 2621490, 458753, 6, 2687026, 458753, 6, 2752562, 327681, 1, 1507379, 393217, 1, 1572915, 393217, 6, 1638451, 262145, 6, 1703987, 327681, 1, 2031667, 393217, 1, 2097203, 393217, 6, 2162739, 262145, 6, 2228275, 327681, 1, 2555955, 393217, 1, 2621491, 458753, 6, 2687027, 458753, 6, 2752563, 327681, 1, 1507380, 393217, 1, 1572916, 327681, 6, 1638452, 393217, 6, 1703988, 327681, 1, 2031668, 393217, 1, 2097204, 393217, 6, 2162740, 393217, 6, 2228276, 327681, 1, 2555956, 393217, 1, 2621492, 458753, 6, 2687028, 327681, 6, 2752564, 327681, 1, 1507381, 393217, 1, 1572917, 458753, 6, 1638453, 393217, 6, 1703989, 327681, 1, 2031669, 393217, 1, 2097205, 262145, 6, 2162741, 262145, 6, 2228277, 327681, 1, 2555957, 393217, 1, 2621493, 327681, 6, 2687029, 458753, 6, 2752565, 327681, 1, 1507382, 393217, 1, 1572918, 262145, 6, 1638454, 327681, 6, 1703990, 1, 4, 1769526, 327681, 5, 1835062, 131073, 0, 1900598, 262145, 1, 1966134, 262145, 1, 2031670, 131073, 4, 2097206, 393217, 6, 2162742, 327681, 6, 2228278, 1, 4, 2293814, 262145, 1, 2359350, 131073, 0, 2424886, 262145, 1, 2490422, 262145, 1, 2555958, 131073, 5, 2621494, 327681, 6, 2687030, 393217, 6, 2752566, 327681, 1, 1507383, 393217, 1, 1572919, 458753, 6, 1638455, 262145, 6, 1703991, 262145, 6, 1769527, 327681, 6, 1835063, 458753, 6, 1900599, 458753, 6, 1966135, 393217, 6, 2031671, 327681, 6, 2097207, 262145, 6, 2162743, 262145, 6, 2228279, 327681, 6, 2293815, 393217, 6, 2359351, 327681, 6, 2424887, 262145, 6, 2490423, 458753, 6, 2555959, 458753, 6, 2621495, 262145, 6, 2687031, 262145, 6, 2752567, 327681, 1, 1507384, 393217, 1, 1572920, 262145, 6, 1638456, 327681, 6, 1703992, 327681, 6, 1769528, 262145, 6, 1835064, 327681, 6, 1900600, 327681, 6, 1966136, 262145, 6, 2031672, 393217, 6, 2097208, 327681, 6, 2162744, 262145, 6, 2228280, 393217, 6, 2293816, 327681, 6, 2359352, 458753, 6, 2424888, 393217, 6, 2490424, 327681, 6, 2555960, 262145, 6, 2621496, 458753, 6, 2687032, 393217, 6, 2752568, 327681, 1, 1507385, 327681, 3, 1572921, 458753, 1, 1638457, 458753, 1, 1703993, 458753, 1, 1769529, 458753, 1, 1835065, 458753, 1, 1900601, 458753, 1, 1966137, 458753, 1, 2031673, 458753, 1, 2097209, 458753, 1, 2162745, 458753, 1, 2228281, 458753, 1, 2293817, 458753, 1, 2359353, 458753, 1, 2424889, 458753, 1, 2490425, 458753, 1, 2555961, 458753, 1, 2621497, 458753, 1, 2687033, 458753, 1, 2752569, 327681, 3, 2031658, 327681, 5, 2097194, 327681, 6, 2162730, 262145, 6, 2228266, 327681, 1, 2031659, 393217, 1, 2097195, 65537, 6, 2162731, 327681, 6, 2228267, 327681, 1, 2031660, 393217, 1, 2097196, 262145, 6, 2162732, 327681, 6, 2228268, 327681, 1, 2031661, 393217, 1, 2097197, 262145, 6, 2162733, 327681, 6, 2228269, 327681, 1, 2555946, 327681, 5, 2621482, 262145, 1, 2687018, 262145, 1, 2752554, 262145, 1, 2555947, 393217, 1, 2621483, 393217, 6, 2687019, 393217, 6, 2752555, 262145, 6, 2555948, 393217, 1, 2621484, 458753, 6, 2687020, 458753, 6, 2752556, 262145, 6, 2555949, 393217, 1, 2621485, 458753, 6, 2687021, 327681, 6, 2752557, 65537, 4, 1507370, 327681, 5, 1572906, 262145, 1, 1638442, 262145, 1, 1703978, 393217, 3, 1507371, 458753, 6, 1572907, 393217, 6, 1638443, 393217, 6, 1703979, 327681, 1, 1507372, 393217, 6, 1572908, 393217, 6, 1638444, 393217, 6, 1703980, 327681, 1, 1507373, 196609, 4, 1572909, 458753, 6, 1638445, 262145, 6, 1703981, 327681, 1, 5636118, 327681, 6, 5701654, 458753, 6, 5767190, 327681, 6, 5832726, 458753, 6, 5898262, 327681, 6, 5963798, 327681, 6, 6029334, 458753, 6, 6094870, 262145, 6, 6160406, 458753, 6, 6225942, 393217, 6, 6291478, 458753, 6, 6357014, 327681, 6, 6422550, 458753, 6, 6488086, 262145, 6, 6553622, 393217, 6, 6619158, 327681, 6, 6684694, 327681, 6, 5636119, 393217, 6, 5701655, 327681, 6, 5767191, 327681, 6, 5832727, 458753, 6, 5898263, 393217, 6, 5963799, 458753, 6, 6029335, 262145, 6, 6094871, 131073, 5, 6160407, 262145, 6, 6225943, 327681, 6, 6291479, 458753, 6, 6357015, 458753, 6, 6422551, 262145, 6, 6488087, 458753, 6, 6553623, 393217, 6, 6619159, 1, 6, 6684695, 393217, 6, 5636120, 458753, 1, 5701656, 458753, 1, 5767192, 458753, 1, 5832728, 458753, 1, 5898264, 458753, 1, 5963800, 458753, 1, 6029336, 458753, 1, 6094872, 458753, 1, 6160408, 458753, 1, 6225944, 458753, 1, 6291480, 458753, 1, 6357016, 458753, 1, 6422552, 458753, 1, 6488088, 458753, 1, 6553624, 458753, 1, 6619160, 458753, 1, 6684696, 458753, 1, 5570581, 262145, 1, 5636117, 262145, 1, 5701653, 262145, 1, 5767189, 262145, 1, 5832725, 262145, 1, 5898261, 262145, 1, 5963797, 262145, 1, 6029333, 262145, 1, 6094869, 262145, 1, 6160405, 262145, 1, 6225941, 262145, 1, 6291477, 262145, 1, 6357013, 262145, 1, 6422549, 262145, 1, 6488085, 262145, 1, 6553621, 262145, 1, 6619157, 262145, 1, 6684693, 262145, 5, 5570582, 262145, 6, 5570583, 1, 6, 5570584, 458753, 1, 983098, 393217, 1, 1114170, 262145, 6, 1179706, 327681, 1, 983099, 393217, 1, 1114171, 262145, 6, 1179707, 327681, 1, 983100, 393217, 1, 1048636, 327681, 6, 1114172, 327681, 6, 1179708, 327681, 1, 983101, 393217, 1, 1048637, 393217, 6, 1114173, 327681, 6, 1179709, 327681, 1, 983102, 393217, 1, 1048638, 458753, 6, 1114174, 262145, 6, 1179710, 327681, 1, 983103, 393217, 1, 1048639, 262145, 6, 1114175, 262145, 6, 1179711, 327681, 1, 983104, 393217, 1, 1048640, 458753, 6, 1114176, 458753, 6, 1179712, 327681, 1, 983105, 393217, 1, 1048641, 327681, 6, 1114177, 458753, 6, 1179713, 327681, 1, 983106, 393217, 1, 1048642, 262145, 6, 1114178, 262145, 6, 1179714, 327681, 1, 983107, 393217, 1, 1048643, 131073, 5, 1114179, 458753, 6, 1179715, 327681, 1, 983108, 393217, 1, 1048644, 327681, 6, 1114180, 393217, 6, 1179716, 327681, 1, 983109, 393217, 1, 1048645, 393217, 6, 1114181, 458753, 6, 1179717, 327681, 1, 983110, 393217, 1, 1048646, 262145, 6, 1114182, 262145, 6, 1179718, 327681, 1, 983111, 393217, 1, 1048647, 327681, 6, 1114183, 262145, 6, 1179719, 327681, 1, 3080250, 393217, 1, 3145786, 327681, 6, 3276858, 327681, 1, 3080251, 393217, 1, 3145787, 262145, 6, 3276859, 327681, 1, 3080252, 393217, 1, 3145788, 327681, 6, 3211324, 327681, 6, 3276860, 327681, 1, 3080253, 393217, 1, 3145789, 393217, 6, 3211325, 327681, 6, 3276861, 327681, 1, 3080254, 393217, 1, 3145790, 458753, 6, 3211326, 262145, 6, 3276862, 327681, 1, 3080255, 393217, 1, 3145791, 262145, 6, 3211327, 262145, 6, 3276863, 327681, 1, 3080256, 393217, 1, 3145792, 458753, 6, 3211328, 458753, 6, 3276864, 327681, 1, 3080257, 393217, 1, 3145793, 327681, 6, 3211329, 458753, 6, 3276865, 327681, 1, 3080258, 393217, 1, 3145794, 262145, 6, 3211330, 262145, 6, 3276866, 327681, 1, 3080259, 393217, 1, 3145795, 393217, 6, 3211331, 131073, 5, 3276867, 327681, 1, 3080260, 393217, 1, 3145796, 327681, 6, 3211332, 393217, 6, 3276868, 327681, 1, 3080261, 393217, 1, 3145797, 393217, 6, 3211333, 458753, 6, 3276869, 327681, 1, 3080262, 393217, 1, 3145798, 262145, 6, 3211334, 262145, 6, 3276870, 327681, 1, 3080263, 393217, 1, 3145799, 327681, 6, 3211335, 262145, 6, 3276871, 327681, 1, 3080264, 393217, 1, 3145800, 458753, 6, 3211336, 393217, 6, 3276872, 327681, 1, 3080265, 393217, 1, 3145801, 262145, 6, 3211337, 262145, 6, 3276873, 327681, 1, 3080266, 393217, 1, 3145802, 327681, 6, 3211338, 458753, 6, 3276874, 327681, 1, 3080267, 327681, 3, 3145803, 458753, 6, 3211339, 262145, 6, 3276875, 327681, 1, 1048514, 393217, 1, 1114050, 327681, 6, 1179586, 262145, 6, 1245122, 327681, 1, 1048515, 393217, 1, 1114051, 262145, 6, 1179587, 262145, 6, 1245123, 327681, 1, 1048516, 393217, 1, 1114052, 327681, 6, 1179588, 327681, 6, 1245124, 327681, 1, 1048517, 393217, 1, 1114053, 393217, 6, 1179589, 327681, 6, 1245125, 327681, 1, 1048518, 393217, 1, 1114054, 458753, 6, 1179590, 262145, 6, 1245126, 327681, 1, 1048519, 393217, 1, 1114055, 262145, 6, 1179591, 262145, 6, 1245127, 327681, 1, 1048520, 393217, 1, 1114056, 458753, 6, 1179592, 458753, 6, 1245128, 327681, 1, 1048521, 393217, 1, 1114057, 327681, 6, 1179593, 458753, 6, 1245129, 327681, 1, 1048522, 393217, 1, 1114058, 131073, 5, 1179594, 262145, 6, 1245130, 327681, 1, 1048523, 393217, 1, 1114059, 393217, 6, 1179595, 458753, 6, 1245131, 327681, 1, 1048524, 393217, 1, 1114060, 458753, 6, 1179596, 262145, 6, 1245132, 327681, 1, 1048525, 393217, 1, 1114061, 327681, 6, 1179597, 327681, 6, 1245133, 327681, 1, 1048526, 393217, 1, 1114062, 393217, 6, 1179598, 393217, 6, 1245134, 327681, 1, 1048527, 393217, 1, 1114063, 393217, 6, 1179599, 393217, 6, 1245135, 327681, 1, 1048528, 393217, 1, 1114064, 327681, 6, 1179600, 262145, 6, 1245136, 327681, 1, 1048529, 393217, 1, 1114065, 458753, 6, 1179601, 458753, 6, 1245137, 327681, 1, 1048530, 393217, 1, 1114066, 131073, 6, 1179602, 327681, 6, 1245138, 327681, 1, 1048531, 327681, 3, 1114067, 393217, 6, 1179603, 458753, 6, 1245139, 327681, 1, 3145669, 393217, 1, 3211205, 393217, 6, 3276741, 327681, 6, 3342277, 327681, 1, 3145670, 393217, 1, 3211206, 458753, 6, 3276742, 262145, 6, 3342278, 327681, 1, 3145671, 393217, 1, 3211207, 262145, 6, 3276743, 262145, 6, 3342279, 327681, 1, 3145672, 393217, 1, 3211208, 458753, 6, 3276744, 458753, 6, 3342280, 327681, 1, 3145673, 393217, 1, 3211209, 327681, 6, 3276745, 458753, 6, 3342281, 327681, 1, 3145674, 393217, 1, 3211210, 262145, 6, 3276746, 131073, 5, 3342282, 327681, 1, 3145675, 393217, 1, 3211211, 393217, 6, 3276747, 458753, 6, 3342283, 327681, 1, 3145676, 393217, 1, 3211212, 327681, 6, 3276748, 393217, 6, 3342284, 327681, 1, 3145677, 393217, 1, 3211213, 393217, 6, 3276749, 393217, 6, 3342285, 327681, 1, 3145678, 393217, 1, 3211214, 393217, 6, 3276750, 458753, 6, 3342286, 327681, 1, 3145679, 393217, 1, 3211215, 327681, 6, 3276751, 262145, 6, 3342287, 327681, 1, 3145680, 393217, 1, 3211216, 327681, 6, 3276752, 393217, 6, 3342288, 327681, 1, 3145681, 393217, 1, 3211217, 458753, 6, 3276753, 393217, 6, 3342289, 327681, 1, 3145682, 393217, 1, 3211218, 262145, 6, 3276754, 131073, 6, 3342290, 327681, 1, 3145683, 327681, 3, 3211219, 393217, 6, 3276755, 393217, 6, 3342291, 327681, 1, -1376233, 262145, 6, -2162666, 327681, 6, -2162665, 327681, 6, -2162664, 458753, 1, -2097128, 458753, 1, -2031592, 458753, 1, 1114047, 458753, 6, 1179583, 393217, 6, 1114048, 393217, 6, 1179584, 327681, 6, 1114049, 393217, 6, 1179585, 458753, 6, 1245119, 327681, 1, 1245120, 327681, 1, 1245121, 327681, 1, 1048511, 393217, 1, 1048512, 393217, 1, 1048513, 393217, 1, 3145781, 393217, 6, 3145780, 327681, 6, 3145779, 262145, 6, 3145778, 262145, 6, 3145777, 327681, 6, 3145776, 393217, 6, 3145775, 262145, 6, 3145774, 327681, 6, 3145773, 458753, 6, 3145772, 262145, 6, 3145771, 262145, 6, 3211307, 393217, 6, 3211308, 458753, 6, 3211309, 458753, 6, 3211310, 393217, 6, 3211311, 262145, 6, 3211312, 458753, 6, 3211313, 327681, 6, 3211314, 393217, 6, 3211315, 327681, 6, 3211316, 458753, 6, 3211317, 458753, 6, 3211318, 393217, 6, 3211319, 458753, 6, 3211320, 393217, 6, 3211321, 262145, 6, 3211322, 262145, 6, 3211323, 196609, 6, 1048619, 393217, 6, 1048620, 327681, 6, 1048621, 458753, 6, 1048622, 327681, 6, 1048623, 262145, 6, 1048624, 393217, 6, 1048625, 327681, 6, 1048626, 262145, 6, 1048627, 262145, 6, 1048628, 327681, 6, 1048629, 393217, 6, 1048630, 327681, 6, 1048631, 393217, 6, 1048632, 393217, 6, 1048633, 327681, 6, 1048634, 327681, 6, 1048635, 65537, 6)\nlayer_1/name = \"lvl1-tall\"\nlayer_1/y_sort_enabled = true\nlayer_1/z_index = 10\nlayer_1/tile_data = PackedInt32Array(-589832, 131081, 0, -589836, 6, 0, -655372, 6, 0, -720908, 6, 0, -786444, 6, 0, -851980, 6, 0, -917516, 6, 0, -983052, 6, 0, -1048588, 6, 0, -1179660, 131075, 2, -1310732, 6, 0, -1376268, 6, 0, -1441804, 6, 0, -1507340, 6, 0, -1572876, 6, 0, -1638412, 6, 0, -1703948, 6, 0, -1769484, 6, 0, -1835020, 6, 0, -1900556, 6, 0, -1966092, 6, 0, -2031628, 6, 0, -2097164, 6, 0, -2162700, 6, 0, -2228236, 6, 0, -1114124, 6, 0, -1048587, 262153, 10, -524300, 6, 0, -458764, 6, 0, -393228, 6, 0, -327692, 6, 0, -262156, 6, 0, -196620, 6, 0, -131084, 6, 0, -1179652, 6, 0, -1114116, 6, 0, -1048580, 6, 0, -983044, 6, 0, -917508, 6, 0, -851972, 6, 0, -786436, 6, 0, -720900, 6, 0, -655364, 6, 0, -589828, 6, 0, -524292, 6, 0, -458756, 6, 0, -983036, 6, 0, -917500, 6, 0, -851964, 6, 0, -786428, 6, 0, -720892, 6, 0, -655356, 6, 0, -589820, 6, 0, -524284, 6, 0, -458748, 6, 0, -393212, 6, 0, -327676, 6, 0, -262140, 6, 0, -196604, 6, 0, -131068, 6, 0, -65532, 6, 0, 4, 6, 0, 196600, 6, 0, 262136, 6, 0, 327672, 6, 0, 393208, 6, 0, 458744, 6, 0, 524280, 6, 0, 589816, 6, 0, 655352, 6, 0, 720888, 6, 0, 786424, 6, 0, 851960, 6, 0, 917496, 6, 0, 917508, 6, 0, 983044, 6, 0, 1048580, 6, 0, 1114116, 6, 0, 1179652, 6, 0, 1245188, 6, 0, 1310724, 6, 0, 1376260, 6, 0, 1441796, 6, 0, 1507332, 6, 0, 1572868, 6, 0, 1638404, 6, 0, 655357, 65542, 0, 655358, 65542, 0, 655359, 65542, 0, 589824, 65542, 0, 589825, 65542, 0, 589826, 65542, 0, 589827, 65542, 0, 589828, 65542, 0, 589829, 65542, 0, 589830, 65542, 0, 589831, 65542, 0, 589832, 65542, 0, 131065, 65542, 0, 131066, 65542, 0, 131067, 65542, 0, 131068, 65542, 0, 131069, 65542, 0, 131070, 65542, 0, 131071, 65542, 0, 65536, 65542, 0, 65537, 65542, 0, 65538, 65542, 0, 65539, 65542, 0, -1245187, 65542, 0, -1245186, 65542, 0, -1245185, 65542, 0, -1310720, 65542, 0, -1310719, 65542, 0, -1310718, 65542, 0, -1310717, 65542, 0, -1310716, 65542, 0, -1310715, 65542, 0, -1310714, 65542, 0, -1310713, 65542, 0, -1310712, 65542, 0, -393223, 65542, 0, -393222, 65542, 0, -393221, 65542, 0, -393220, 6, 1, -1245188, 6, 1, 65540, 6, 1, 131064, 6, 1, -720904, 196617, 1, -655368, 196617, 1, -786440, 196617, 1, -851976, 196617, 1, -917512, 196617, 2, -1310711, 65542, 0, -1310710, 65542, 0, -1310709, 65542, 0, -1310708, 65542, 0, -1310707, 65542, 0, -1310706, 65542, 0, -1310705, 65542, 0, -1310704, 65542, 0, -458735, 65542, 0, -458734, 65542, 0, -458733, 65542, 0, -458732, 6, 1, -983028, 6, 0, -917492, 6, 0, -851956, 6, 0, -786420, 6, 0, -720884, 6, 0, -655348, 6, 0, -589812, 6, 0, -524276, 6, 0, -458740, 6, 0, -393204, 6, 0, -327668, 6, 0, -262132, 6, 0, -196596, 6, 0, -1507308, 6, 0, -1441772, 6, 0, -1376236, 6, 0, -1310700, 6, 0, -1245164, 6, 0, -1179628, 6, 0, -1114092, 6, 0, -1048556, 6, 0, -983020, 6, 0, -917484, 6, 0, -851948, 6, 0, -786412, 6, 0, -720876, 6, 0, -655340, 6, 0, -589804, 6, 0, -524268, 6, 0, -2162668, 6, 0, -2097132, 6, 0, -2031596, 6, 0, -1966060, 6, 0, -1900524, 6, 0, -1834988, 6, 0, -1769452, 6, 0, -1703916, 6, 0, -1638380, 6, 0, -1572844, 6, 0, 589833, 65542, 0, 589834, 65542, 0, 589835, 65542, 0, 589836, 65542, 0, 589837, 65542, 0, 589838, 65542, 0, 589839, 65542, 0, 589840, 6, 1, 393232, 6, 0, 458768, 6, 0, 524304, 6, 0, 65545, 65542, 0, 65546, 65542, 0, 65547, 65542, 0, 65548, 65542, 0, 65549, 65542, 0, 65550, 65542, 0, 65551, 65542, 0, 65552, 65542, 0, 65553, 65542, 0, 65554, 65542, 0, 65555, 65542, 0, 65556, 65542, 0, -2293772, 6, 0, -2359308, 6, 0, -1376267, 60, 1, -983051, 9, 3, -917515, 393225, 2, -1310731, 65545, 2, -655363, 262153, 11, -524291, 65545, 0, -589824, 327689, 0, -589827, 131122, 2, -1114123, 262153, 2, -1245195, 9, 0, -720899, 60, 0, -458747, 60, 1, -262139, 9, 13, -327675, 262153, 12, -196603, 262153, 12, 196605, 131081, 3, 196604, 131081, 2, 196606, 393225, 2, 196601, 9, 10, -1179650, 393225, 7, 917502, 327689, 11, 917503, 327689, 11, 524305, 262153, 11, 458769, 262153, 11, 655374, 9, 2, 655373, 131081, 3, -196595, 131081, 10, -393198, 393225, 10, -196589, 327689, 11, -196590, 327689, 11, -196584, 65536, 1, -1245183, 131132, 1, -917491, 65539, 2, -851955, 65539, 3, 1966083, 6, 1, 2293763, 6, 0, 1900548, 6, 1, 1900553, 65542, 0, 1703940, 6, 0, 1769476, 6, 0, 1835012, 6, 0, 4521972, 6, 0, 4587508, 6, 0, 4653044, 6, 0, 4718580, 6, 0, 4784116, 6, 0, 4849652, 6, 0, 4915188, 6, 0, 4980724, 6, 0, 5046260, 6, 0, 5111796, 6, 0, 5177332, 6, 0, 5242868, 6, 0, 5308404, 6, 0, 5373940, 6, 0, 5439476, 6, 0, 5505012, 6, 0, 5570548, 6, 0, 5636084, 6, 0, 5701620, 6, 0, 5767156, 6, 0, 5832692, 6, 0, 5898228, 6, 0, 5963764, 6, 0, 6029300, 6, 0, 6094836, 6, 0, 6160372, 6, 0, 6225908, 6, 0, 6291444, 6, 0, 6356980, 6, 0, 4784124, 6, 0, 4849660, 6, 0, 4915196, 6, 0, 4980732, 6, 0, 5046268, 6, 0, 5111804, 6, 0, 5177340, 6, 0, 5242876, 6, 0, 5308412, 6, 0, 5373948, 6, 0, 5439484, 6, 0, 5505020, 6, 0, 5570556, 6, 0, 4194308, 6, 0, 4259844, 6, 0, 4325380, 6, 0, 4390916, 6, 0, 4456452, 6, 0, 4521988, 6, 0, 4587524, 6, 0, 4653060, 6, 0, 4718596, 6, 0, 4784132, 6, 0, 4849668, 6, 0, 4915204, 6, 0, 4980740, 6, 0, 5046276, 6, 0, 5111812, 6, 0, 5177348, 6, 0, 5242884, 6, 1, 4456460, 6, 0, 4521996, 6, 0, 4587532, 6, 0, 4653068, 6, 0, 4718604, 6, 0, 4784140, 6, 0, 4849676, 6, 0, 4915212, 6, 0, 4980748, 6, 0, 5046284, 6, 0, 5111820, 6, 0, 5177356, 6, 0, 5242892, 6, 1, 4718612, 6, 0, 4784148, 6, 0, 4849684, 6, 0, 4915220, 6, 0, 4980756, 6, 0, 5046292, 6, 0, 5111828, 6, 0, 5177364, 6, 0, 5242900, 6, 0, 5308436, 6, 0, 5373972, 6, 0, 5439508, 6, 0, 5505044, 6, 0, 5570580, 6, 0, 5636116, 6, 0, 5701652, 6, 0, 5767188, 6, 0, 5832724, 6, 0, 5898260, 6, 0, 5963796, 6, 0, 6029332, 6, 0, 6094868, 6, 0, 6160404, 6, 0, 6225940, 6, 0, 6291476, 6, 0, 6357012, 6, 0, 6422548, 6, 0, 6488084, 6, 0, 6553620, 6, 0, 6619156, 6, 0, 6684692, 6, 0, 3473400, 6, 0, 3538936, 6, 0, 3604472, 6, 0, 3670008, 6, 0, 3735544, 6, 0, 3801080, 6, 0, 3866616, 6, 0, 3932152, 6, 0, 3997688, 6, 0, 4063224, 6, 0, 4128760, 6, 0, 3932157, 65542, 0, 3932158, 65542, 0, 3932159, 65542, 0, 3866624, 65542, 0, 3866625, 65542, 0, 3866626, 65542, 0, 3866627, 65542, 0, 3866628, 65542, 0, 3866629, 65542, 0, 3866630, 65542, 0, 3866631, 65542, 0, 3866632, 65542, 0, 3866633, 65542, 0, 3866634, 65542, 0, 3866635, 65542, 0, 3866636, 65542, 0, 3866637, 65542, 0, 3866638, 65542, 0, 3866639, 65542, 0, 3866640, 6, 1, 2031604, 65542, 0, 2031605, 65542, 0, 2031606, 65542, 0, 2031607, 65542, 0, 2031608, 65542, 0, 2031609, 65542, 0, 2031610, 65542, 0, 2031611, 65542, 0, 2031612, 65542, 0, 2031613, 65542, 0, 2031614, 65542, 0, 2031615, 65542, 0, 1966080, 65542, 0, 1966081, 65542, 0, 1966082, 65542, 0, 1572847, 6, 0, 1638383, 6, 0, 1703919, 6, 0, 1769455, 6, 0, 1834991, 6, 0, 1900527, 6, 0, 1966063, 6, 0, 2031599, 6, 0, 2097135, 6, 0, 2162671, 6, 0, 2228207, 6, 0, 2293743, 6, 0, 2359279, 6, 0, 2424815, 6, 0, 2490351, 6, 0, 2555887, 6, 0, 2621423, 6, 0, 2686959, 6, 0, 2752495, 6, 0, 2818031, 6, 1, 2818028, 65542, 0, 2818029, 65542, 0, 2818030, 65542, 0, 2359271, 6, 0, 2424807, 6, 0, 2490343, 6, 0, 2555879, 6, 0, 2621415, 6, 0, 2686951, 6, 0, 2752487, 6, 0, 2818023, 6, 0, 2883559, 6, 0, 2949095, 6, 0, 3014631, 6, 0, 3080167, 6, 0, 2031591, 6, 1, 1310695, 6, 0, 1376231, 6, 0, 1441767, 6, 0, 1507303, 6, 0, 1572839, 6, 0, 1638375, 6, 0, 1703911, 6, 0, 1769447, 6, 0, 1834983, 6, 0, 1900519, 6, 0, 1966055, 6, 0, 1245160, 65542, 0, 1245161, 65542, 0, 1245162, 65542, 0, 1245163, 65542, 0, 1245164, 65542, 0, 1245165, 65542, 0, 1245166, 65542, 0, 1245167, 65542, 0, 1245168, 65542, 0, 1245169, 65542, 0, 1245170, 65542, 0, 1245171, 65542, 0, 2031576, 65542, 0, 2031577, 65542, 0, 2031578, 65542, 0, 2031579, 65542, 0, 2031580, 65542, 0, 2031581, 65542, 0, 2031582, 65542, 0, 2031583, 65542, 0, 2031584, 65542, 0, 2031585, 65542, 0, 2031586, 65542, 0, 2031587, 65542, 0, 2031588, 65542, 0, 2031589, 65542, 0, 2031590, 65542, 0, 1507284, 65542, 0, 1507285, 65542, 0, 1507286, 65542, 0, 1507287, 65542, 0, 1507288, 65542, 0, 1507289, 65542, 0, 1507290, 65542, 0, 1507291, 65542, 0, 1507292, 65542, 0, 1507293, 65542, 0, 1507294, 65542, 0, 1507295, 6, 1, 983000, 65542, 0, 983001, 65542, 0, 983002, 65542, 0, 983003, 65542, 0, 983004, 65542, 0, 983005, 65542, 0, 983006, 65542, 0, 983007, 65542, 0, 983008, 65542, 0, 983009, 65542, 0, 983010, 65542, 0, 983011, 65542, 0, 982978, 65542, 0, 982979, 65542, 0, 982980, 65542, 0, 982981, 65542, 0, 982982, 65542, 0, 982983, 65542, 0, 982984, 65542, 0, 982985, 65542, 0, 982986, 65542, 0, 982987, 65542, 0, 982988, 65542, 0, 982989, 65542, 0, 982990, 65542, 0, 982991, 65542, 0, 982992, 65542, 0, 982993, 65542, 0, 982994, 65542, 0, 982995, 65542, 0, 982996, 65542, 0, 982997, 65542, 0, 982998, 65542, 0, 982999, 65542, 0, 2555864, 65542, 0, 2555865, 65542, 0, 2555866, 65542, 0, 2555867, 65542, 0, 2555868, 65542, 0, 2555869, 65542, 0, 2555870, 65542, 0, 2555871, 65542, 0, 2555872, 65542, 0, 2555873, 65542, 0, 2555874, 65542, 0, 2555875, 65542, 0, 3080142, 65542, 0, 3080143, 65542, 0, 3080144, 65542, 0, 3080145, 65542, 0, 3080146, 65542, 0, 3080147, 65542, 0, 3080148, 65542, 0, 3080149, 65542, 0, 3080150, 65542, 0, 3080151, 65542, 0, 3080152, 65542, 0, 3080153, 65542, 0, 3080154, 65542, 0, 3080155, 65542, 0, 3080156, 65542, 0, 3080157, 65542, 0, 3080158, 65542, 0, 3080159, 6, 1, 3080133, 65542, 0, 3080134, 65542, 0, 3080135, 65542, 0, 3080136, 65542, 0, 3080137, 65542, 0, 3080138, 65542, 0, 3080139, 65542, 0, 3080140, 65542, 0, 3080141, 65542, 0, 2883551, 6, 0, 2949087, 6, 0, 3014623, 6, 0, 2293715, 6, 0, 2359251, 6, 0, 2424787, 6, 0, 2490323, 6, 0, 2555859, 6, 0, 2621395, 6, 0, 2686931, 6, 0, 2752467, 6, 0, 2818003, 6, 0, 1572819, 6, 0, 1638355, 6, 0, 1703891, 6, 0, 1769427, 6, 0, 1834963, 6, 0, 1900499, 6, 0, 1966035, 6, 0, 2031571, 6, 0, 2097107, 6, 0, 2162643, 6, 0, 2228179, 6, 0, 1310687, 6, 0, 1376223, 6, 0, 1441759, 6, 0, 2359300, 6, 0, 2424836, 6, 0, 2490372, 6, 0, 2555908, 6, 0, 2621444, 6, 0, 2686980, 6, 0, 2752516, 6, 0, 2818052, 6, 0, 2883588, 6, 0, 2949124, 6, 0, 3014660, 6, 0, 3080196, 6, 0, 3145732, 6, 0, 3211268, 6, 0, 3276804, 6, 0, 3342340, 6, 1, 4194296, 6, 0, 3670032, 6, 0, 3735568, 6, 0, 3801104, 6, 0, 5242889, 65542, 0, 5242890, 65542, 0, 5242891, 65542, 0, 4456437, 65542, 0, 4456438, 65542, 0, 4456439, 65542, 0, 4456440, 65542, 0, 4456441, 65542, 0, 4456442, 65542, 0, 4456443, 65542, 0, 4456444, 65542, 0, 4456445, 65542, 0, 4456446, 65542, 0, 4456447, 65542, 0, 4390912, 65542, 0, 4390925, 65542, 0, 4390926, 65542, 0, 4390927, 65542, 0, 4390928, 65542, 0, 4390929, 65542, 0, 4390930, 65542, 0, 4390931, 65542, 0, 4390932, 65542, 0, 4390933, 65542, 0, 4390934, 65542, 0, 4390935, 65542, 0, 4390936, 65542, 0, 5242881, 65542, 0, 5242882, 65542, 0, 5242883, 65542, 0, 3342345, 65542, 0, 3342346, 65542, 0, 3342347, 65542, 0, 3342348, 65542, 0, 3342349, 65542, 0, 3342350, 65542, 0, 3342351, 65542, 0, 3342352, 65542, 0, 3342353, 65542, 0, 3342354, 65542, 0, 3342355, 65542, 0, 3342356, 65542, 0, 3407865, 65542, 0, 3407866, 65542, 0, 3407867, 65542, 0, 3407868, 65542, 0, 3407869, 65542, 0, 3407870, 65542, 0, 3407871, 65542, 0, 3342336, 65542, 0, 3342337, 65542, 0, 3342338, 65542, 0, 3342339, 65542, 0, 1966090, 65542, 0, 1966091, 65542, 0, 1966092, 65542, 0, 1966093, 65542, 0, 1966094, 65542, 0, 1966095, 65542, 0, 1966096, 65542, 0, 1966097, 65542, 0, 1966098, 65542, 0, 1966099, 65542, 0, 1966100, 65542, 0, 1966101, 65542, 0, 1966102, 65542, 0, 1966103, 65542, 0, 1966104, 65542, 0, 1966105, 6, 1, 1179674, 65542, 0, 1179675, 65542, 0, 1179676, 65542, 0, 1179677, 65542, 0, 1179678, 65542, 0, 1179679, 65542, 0, 1179680, 65542, 0, 1179681, 65542, 0, 1179682, 65542, 0, 1179683, 65542, 0, 1179684, 65542, 0, 1179685, 65542, 0, 2752542, 65542, 0, 2752543, 65542, 0, 2752544, 65542, 0, 2752545, 6, 1, 1966118, 65542, 0, 1966119, 65542, 0, 1966120, 65542, 0, 1966121, 65542, 0, 1966122, 65542, 0, 1966123, 65542, 0, 1966124, 65542, 0, 1966125, 65542, 0, 1966126, 65542, 0, 1966127, 65542, 0, 1966128, 65542, 0, 1966129, 65542, 0, 1966130, 65542, 0, 1966131, 65542, 0, 1966132, 65542, 0, 1966133, 6, 1, 917546, 65542, 0, 917547, 65542, 0, 917548, 65542, 0, 917549, 65542, 0, 917550, 65542, 0, 917551, 65542, 0, 917552, 65542, 0, 917553, 65542, 0, 917554, 65542, 0, 917555, 65542, 0, 917556, 65542, 0, 917557, 65542, 0, 917558, 65542, 0, 917559, 65542, 0, 917560, 65542, 0, 917561, 65542, 0, 917562, 65542, 0, 917563, 65542, 0, 917564, 65542, 0, 917565, 65542, 0, 917566, 65542, 0, 917567, 65542, 0, 917568, 65542, 0, 917569, 65542, 0, 917570, 65542, 0, 917571, 65542, 0, 917572, 65542, 0, 917573, 65542, 0, 917574, 65542, 0, 917575, 65542, 0, 983081, 6, 0, 1048617, 6, 0, 1114153, 6, 0, 1179689, 6, 0, 1245225, 6, 0, 1310761, 6, 0, 1376297, 6, 0, 1441833, 6, 0, 1507369, 6, 0, 1572905, 6, 0, 1638441, 6, 0, 1703977, 6, 0, 1441838, 65542, 0, 1441839, 65542, 0, 1441840, 65542, 0, 1441841, 65542, 0, 1441842, 65542, 0, 1441843, 65542, 0, 1441844, 65542, 0, 1441845, 65542, 0, 1441846, 65542, 0, 1441847, 65542, 0, 1441848, 65542, 0, 1441849, 65542, 0, 2490410, 65542, 0, 2490411, 65542, 0, 2490412, 65542, 0, 2490413, 65542, 0, 2490414, 65542, 0, 2490415, 65542, 0, 2490416, 65542, 0, 2490417, 65542, 0, 2490418, 65542, 0, 2490419, 65542, 0, 2490420, 65542, 0, 2490421, 6, 1, 2555945, 6, 0, 2621481, 6, 0, 2687017, 6, 0, 2752553, 6, 0, 2818089, 6, 0, 2883625, 6, 0, 2949161, 6, 0, 3014697, 6, 0, 3080233, 6, 0, 3145769, 6, 0, 3211305, 6, 0, 3276841, 6, 0, 3014702, 65542, 0, 3014703, 65542, 0, 3014704, 65542, 0, 3014705, 65542, 0, 3014706, 65542, 0, 3014707, 65542, 0, 3014708, 65542, 0, 3014709, 65542, 0, 3014710, 65542, 0, 3014711, 65542, 0, 3014712, 65542, 0, 3014713, 65542, 0, 3014714, 65542, 0, 3014715, 65542, 0, 3014716, 65542, 0, 3014717, 65542, 0, 3014718, 65542, 0, 3014719, 65542, 0, 3014720, 65542, 0, 3014721, 65542, 0, 3014722, 65542, 0, 3014723, 65542, 0, 3014724, 65542, 0, 3014725, 65542, 0, 3014726, 65542, 0, 3014727, 65542, 0, 3014728, 65542, 0, 3014729, 65542, 0, 3014730, 65542, 0, 3014731, 65542, 0, 2293813, 6, 0, 2359349, 6, 0, 2424885, 6, 0, 1769525, 6, 0, 1835061, 6, 0, 1900597, 6, 0, 1507361, 6, 0, 1572897, 6, 0, 1638433, 6, 0, 1703969, 6, 0, 1769505, 6, 0, 1835041, 6, 0, 1900577, 6, 0, 1966113, 6, 0, 2031649, 6, 0, 2097185, 6, 0, 2162721, 6, 0, 2228257, 6, 0, 2293793, 6, 0, 2359329, 6, 0, 2424865, 6, 0, 2490401, 6, 0, 2555937, 6, 0, 2621473, 6, 0, 2687009, 6, 0, 2293785, 6, 0, 2359321, 6, 0, 2424857, 6, 0, 2490393, 6, 0, 2555929, 6, 0, 2621465, 6, 0, 2687001, 6, 0, 2752537, 6, 0, 2818073, 6, 0, 2883609, 6, 0, 2949145, 6, 0, 3014681, 6, 0, 1245209, 6, 0, 1310745, 6, 0, 1376281, 6, 0, 1441817, 6, 0, 1507353, 6, 0, 1572889, 6, 0, 1638425, 6, 0, 1703961, 6, 0, 1769497, 6, 0, 1835033, 6, 0, 1900569, 6, 0, 6422516, 6, 0, 6488052, 6, 0, 4849661, 262153, 11, 4915197, 262153, 11, 2555946, 9, 10, 2555949, 131081, 2, 2555950, 131081, 3, 2555951, 393225, 2, -393197, 393225, 10, 5308426, 393225, 10, 5308427, 393225, 10, 5308418, 393225, 10, 5308419, 393225, 10, 2949088, 65545, 0, 2949091, 327689, 0, 1245212, 393225, 7, 1245215, 131132, 1, 1703986, 327689, 11, 1703987, 327689, 11)\nlayer_2/name = \"lvl2-flat\"\nlayer_2/y_sort_enabled = true\nlayer_2/y_sort_origin = 128\nlayer_2/z_index = 10\nlayer_2/tile_data = PackedInt32Array(-1835025, 262145, 5, -1769489, 458753, 5, -1703953, 393217, 5, -1638417, 393217, 5, -1572881, 458753, 2, -1507345, 458753, 5, -1376273, 458753, 5, -1310737, 458753, 4, -1245201, 393217, 5, -1179665, 196609, 6, -1114129, 458753, 6, -1048593, 262145, 6, -983057, 327681, 6, -917521, 327681, 5, -851985, 327681, 5, -786449, 262145, 5, -720913, 393217, 5, -655377, 262145, 5, -589841, 327681, 5, -524305, 393217, 5, -1900560, 262145, 5, -1835024, 458753, 2, -1769488, 458753, 5, -1703952, 327681, 5, -1638416, 393217, 5, -1572880, 458753, 2, -1507344, 458753, 5, -1441808, 458753, 5, -1376272, 262145, 5, -1310736, 393217, 5, -1245200, 327681, 4, -1179664, 131073, 6, -1114128, 131073, 6, -1048592, 458753, 6, -786448, 262145, 5, -720912, 393217, 5, -655376, 327681, 5, -589840, 458753, 5, -524304, 262145, 5, -1966095, 327681, 5, -1900559, 458753, 2, -1835023, 327681, 2, -1769487, 327681, 5, -1703951, 393217, 5, -1638415, 393217, 5, -1572879, 327681, 5, -1507343, 327681, 5, -1441807, 458753, 5, -1376271, 262145, 5, -1179663, 458753, 5, -1114127, 458753, 5, -1048591, 327681, 5, -851983, 458753, 5, -786447, 327681, 2, -720911, 458753, 2, -655375, 458753, 2, -589839, 262145, 5, -524303, 458753, 5, -1900558, 327681, 5, -1638414, 262145, 5, -1572878, 393217, 5, -1507342, 393217, 5, -1441806, 327681, 5, -1376270, 262145, 5, -1310734, 327681, 5, -1179662, 458753, 5, -1114126, 458753, 5, -851982, 327681, 2, -786446, 262145, 5, -720910, 393217, 5, -655374, 65537, 2, -589838, 458753, 2, -524302, 262145, 5, -1835021, 458753, 5, -1769485, 458753, 5, -1441805, 327681, 5, -1376269, 327681, 5, -1310733, 393217, 5, -1179661, 393217, 5, -1114125, 393217, 5, -1048589, 458753, 5, -917517, 262145, 5, -851981, 262145, 5, -786445, 458753, 5, -720909, 327681, 5, -655373, 262145, 5, -589837, 262145, 5, -524301, 327681, 5, -1507336, 458753, 5, -1441800, 327681, 5, -1376264, 458753, 5, -1310728, 458753, 4, -1245192, 393217, 5, -1179656, 393217, 5, -1114120, 393217, 5, -1048584, 327681, 5, -983048, 327681, 5, -917512, 393217, 5, -851976, 393217, 5, -786440, 458753, 5, -720904, 327681, 5, -655368, 458753, 5, -589832, 458753, 5, -524296, 262145, 5, -458760, 262145, 5, -1572871, 327681, 5, -1507335, 262145, 5, -1441799, 393217, 5, -1376263, 458753, 5, -1310727, 327681, 4, -1245191, 393217, 2, -1179655, 458753, 5, -1114119, 327681, 2, -1048583, 393217, 5, -983047, 327681, 5, -917511, 393217, 5, -851975, 393217, 5, -786439, 327681, 5, -720903, 393217, 5, -655367, 327681, 5, -589831, 393217, 5, -524295, 327681, 5, -458759, 458753, 5, -1572870, 131073, 6, -1507334, 393217, 5, -1441798, 393217, 6, -1310726, 131073, 2, -1245190, 458753, 5, -1179654, 393217, 5, -1114118, 196609, 0, -1048582, 327681, 5, -983046, 393217, 5, -917510, 327681, 5, -851974, 393217, 5, -786438, 458753, 5, -720902, 327681, 5, -655366, 458753, 5, -589830, 458753, 5, -524294, 262145, 5, -458758, 262145, 5, -1572869, 1, 6, -1507333, 262145, 5, -1441797, 393217, 6, -1310725, 131073, 2, -1245189, 458753, 5, -1179653, 458753, 4, -1114117, 327681, 4, -1048581, 327681, 5, -983045, 262145, 5, -917509, 262145, 5, -851973, 458753, 5, -786437, 327681, 5, -720901, 327681, 5, -655365, 458753, 5, -589829, 458753, 5, -524293, 458753, 5, -458757, 458753, 5, -1900552, 393217, 5, -1835016, 393217, 5, -1769480, 458753, 5, -1703944, 393217, 5, -1638408, 327681, 5, -1900551, 393217, 5, -1835015, 262145, 5, -1638407, 393217, 5, -1966086, 393217, 5, -1900550, 327681, 5, -1835014, 327681, 5, -1638406, 393217, 5, -1572868, 327681, 5, -1507332, 262145, 5, -1441796, 196609, 5, -1310724, 393217, 5, -1572867, 327681, 5, -1507331, 262145, 5, -1441795, 458753, 5, -1376259, 327681, 5, -1310723, 327681, 5, -1572866, 262145, 5, -1507330, 262145, 5, -1441794, 131073, 1, -1376258, 65537, 5, -1310722, 458753, 5, -1572865, 393217, 5, -1507329, 458753, 4, -1441793, 458753, 2, -1376257, 262145, 4, -1310721, 458753, 5, -1966080, 327681, 5, -1900544, 1, 2, -1835008, 262145, 5, -1703936, 327681, 5, -1638400, 458753, 5, -1572864, 262145, 4, -1507328, 458753, 2, -1441792, 327681, 2, -1376256, 393217, 5, -1900543, 458753, 5, -1835007, 262145, 4, -1703935, 327681, 5, -1638399, 393217, 5, -1572863, 262145, 4, -1507327, 393217, 5, -1376255, 327681, 5, -1835006, 393217, 5, -1703934, 327681, 5, -1638398, 458753, 5, -1572862, 393217, 5, -1507326, 458753, 2, -1441790, 327681, 5, -1376254, 262145, 5, -1703933, 327681, 5, -1638397, 262145, 6, -1572861, 262145, 0, -1507325, 196609, 2, -1441789, 458753, 5, -1376253, 458753, 5, -1703932, 458753, 5, -1638396, 393217, 6, -1572860, 458753, 6, -1507324, 65537, 1, -1441788, 393217, 5, -1376252, 393217, 5, -1638395, 262145, 6, -1572859, 327681, 6, -1507323, 65537, 1, -1441787, 393217, 5, -1376251, 458753, 5, -1572858, 393217, 5, -1507322, 262145, 5, -1441786, 327681, 5, -1376250, 393217, 5, -1507321, 327681, 4, -1441785, 262145, 5, -1376249, 327681, 5, -1441784, 393217, 5, -1376248, 327681, 5, -1376247, 393217, 5, 327689, 327681, 5, 393225, 327681, 5, 458761, 262145, 5, 524297, 393217, 5, 917513, 458753, 2, 983049, 458753, 4, 1048585, 458753, 2, 1114121, 458753, 5, 1179657, 458753, 5, 1245193, 262145, 5, 1310729, 458753, 5, 1376265, 458753, 5, 1441801, 262145, 5, 1507337, 327681, 4, 1572873, 393217, 5, 1638409, 262145, 5, 1703945, 262145, 5, 1769481, 262145, 4, 1835017, 393217, 5, 1900553, 262145, 5, 327690, 327681, 5, 393226, 458753, 5, 458762, 393217, 5, 524298, 262145, 5, 917514, 458753, 5, 983050, 458753, 5, 1048586, 393217, 5, 1114122, 393217, 5, 1179658, 327681, 4, 1245194, 262145, 5, 1310730, 327681, 5, 1376266, 393217, 5, 1441802, 458753, 2, 1507338, 458753, 5, 1572874, 262145, 5, 1638410, 262145, 5, 1703946, 458753, 4, 1769482, 1, 2, 1835018, 458753, 4, 1900554, 262145, 5, 327691, 393217, 5, 393227, 458753, 5, 458763, 327681, 5, 524299, 262145, 5, 917515, 458753, 5, 983051, 262145, 4, 1048587, 1, 2, 1114123, 393217, 2, 1179659, 1, 2, 1245195, 393217, 5, 1310731, 458753, 5, 1376267, 327681, 2, 1441803, 327681, 4, 1507339, 458753, 2, 1572875, 393217, 5, 1638411, 262145, 5, 1703947, 458753, 4, 1769483, 393217, 5, 1835019, 458753, 5, 1900555, 327681, 5, 393228, 262145, 5, 458764, 458753, 5, 524300, 458753, 5, 917516, 458753, 2, 983052, 327681, 5, 1048588, 327681, 2, 1114124, 393217, 5, 1179660, 262145, 4, 1245196, 393217, 5, 1310732, 262145, 5, 1376268, 65537, 2, 1441804, 458753, 4, 1507340, 196609, 2, 1572876, 393217, 5, 1638412, 393217, 5, 1703948, 393217, 5, 1769484, 458753, 5, 1835020, 65537, 2, 1900556, 458753, 5, 393229, 393217, 5, 458765, 393217, 5, 524301, 393217, 5, 917517, 458753, 4, 983053, 327681, 5, 1048589, 131073, 4, 1114125, 131073, 0, 1179661, 131073, 0, 1245197, 458753, 5, 1310733, 458753, 5, 1376269, 262145, 5, 1441805, 393217, 5, 1507341, 458753, 2, 1572877, 262145, 5, 1638413, 327681, 5, 1703949, 458753, 5, 1769485, 327681, 5, 1835021, 458753, 4, 1900557, 262145, 5, 327694, 393217, 5, 917518, 327681, 2, 983054, 393217, 5, 1048590, 262145, 3, 1114126, 65537, 0, 1179662, 65537, 0, 1245198, 327681, 4, 1310734, 393217, 5, 1441806, 262145, 5, 1507342, 262145, 5, 1572878, 327681, 5, 1638414, 458753, 5, 1703950, 393217, 5, 1769486, 327681, 5, 1900558, 458753, 5, 458749, 393217, 5, 524285, 393217, 5, 589821, 458753, 5, 458750, 393217, 5, 524286, 458753, 5, 589822, 262145, 5, 458751, 458753, 5, 524287, 262145, 5, 589823, 262145, 5, 393216, 458753, 5, 458752, 327681, 5, 524288, 393217, 5, 393217, 393217, 5, 458753, 327681, 5, 524289, 262145, 5, 393218, 327681, 5, 458754, 262145, 5, 524290, 262145, 5, 393219, 262145, 5, 458755, 262145, 5, 524291, 458753, 5, 393220, 262145, 5, 458756, 458753, 5, 524292, 327681, 5, 393221, 393217, 5, 458757, 262145, 5, 524293, 393217, 5, 393222, 327681, 5, 458758, 393217, 5, 524294, 327681, 5, 393223, 262145, 5, 458759, 393217, 5, 524295, 393217, 5, 393224, 458753, 5, 458760, 393217, 5, 524296, 458753, 5, 393212, 262145, 5, 458748, 327681, 5, 524284, 262145, 5, 589820, 327681, 5, 393213, 393217, 5, 393214, 393217, 5, 393215, 458753, 5, 327680, 393217, 5, 327681, 262145, 5, 327682, 393217, 5, 327683, 262145, 5, 327684, 262145, 5, 327685, 393217, 5, 327686, 262145, 5, 327687, 393217, 5, 327688, 458753, 5, -1048576, 262145, 5, -983040, 327681, 5, -917504, 262145, 5, -851968, 458753, 5, -786432, 327681, 5, -720896, 393217, 5, -655360, 327681, 5, -589824, 327681, 5, -524288, 262145, 5, -458752, 458753, 5, -393216, 327681, 5, -327680, 327681, 5, -262144, 458753, 5, -196608, 327681, 5, -131072, 393217, 5, -65536, 458753, 5, -1048575, 327681, 5, -983039, 393217, 5, -917503, 458753, 5, -851967, 262145, 5, -786431, 393217, 5, -720895, 327681, 5, -655359, 262145, 5, -589823, 262145, 5, -524287, 327681, 5, -458751, 393217, 5, -393215, 458753, 5, -327679, 327681, 5, -262143, 327681, 5, -196607, 393217, 5, -131071, 458753, 5, -65535, 393217, 5, -1048574, 393217, 5, -983038, 458753, 5, -917502, 393217, 5, -851966, 327681, 5, -786430, 458753, 5, -720894, 458753, 5, -655358, 327681, 5, -589822, 327681, 5, -524286, 458753, 5, -458750, 393217, 5, -393214, 327681, 5, -327678, 393217, 5, -262142, 458753, 5, -196606, 262145, 5, -131070, 393217, 5, -65534, 458753, 5, -1048573, 262145, 5, -983037, 458753, 5, -917501, 262145, 5, -851965, 393217, 5, -786429, 393217, 5, -720893, 262145, 5, -655357, 458753, 5, -589821, 393217, 5, -524285, 327681, 5, -458749, 393217, 5, -393213, 262145, 5, -327677, 393217, 5, -262141, 458753, 5, -196605, 393217, 5, -131069, 262145, 5, -65533, 327681, 5, -131081, 327681, 5, -65545, 65537, 0, -9, 65537, 4, 65527, 458753, 2, -131080, 458753, 5, -65544, 458753, 5, -8, 327681, 5, 65528, 327681, 5, -131079, 393217, 5, -65543, 327681, 5, -7, 262145, 5, 65529, 458753, 5, -131078, 458753, 5, -65542, 393217, 5, -6, 393217, 5, 65530, 262145, 5, -131077, 262145, 5, -65541, 327681, 5, -5, 458753, 5, 65531, 327681, 5, -131076, 458753, 5, -65540, 458753, 5, -4, 262145, 5, 65532, 458753, 5, -131075, 262145, 5, -65539, 327681, 5, -3, 327681, 5, 65533, 262145, 5, -131074, 458753, 5, -65538, 327681, 5, -2, 262145, 5, 65534, 327681, 5, -131073, 393217, 5, -65537, 458753, 5, -1, 458753, 5, 65535, 393217, 5, 0, 262145, 5, 1, 327681, 5, 2, 458753, 5, 3, 262145, 5, -131086, 458753, 2, -65550, 262145, 5, -14, 458753, 2, 65522, 393217, 5, -131085, 458753, 5, -65549, 458753, 2, -13, 458753, 5, 65523, 262145, 4, -131084, 393217, 5, -65548, 262145, 5, -12, 262145, 4, -131083, 262145, 5, -65547, 1, 1, -131082, 458753, 2, -65546, 327681, 6, -10, 327681, 6, 65526, 262145, 5, -458769, 458753, 2, -393233, 327681, 5, -327697, 458753, 2, -262161, 262145, 2, -196625, 458753, 5, -131089, 327681, 5, -65553, 262145, 5, -17, 458753, 5, 65519, 262145, 5, -458768, 393217, 5, -393232, 262145, 5, -327696, 327681, 5, -262160, 393217, 5, -196624, 262145, 5, -131088, 262145, 5, -65552, 393217, 5, -16, 458753, 5, 65520, 262145, 5, -458767, 458753, 2, -393231, 65537, 2, -327695, 458753, 5, -262159, 327681, 4, -196623, 458753, 5, -131087, 262145, 5, -65551, 262145, 5, -15, 131073, 2, 65521, 262145, 4, -458766, 1, 2, -196622, 327681, 5, -458765, 327681, 5, -196621, 262145, 5, 131055, 327681, 5, 196591, 458753, 2, 262127, 458753, 2, 327663, 458753, 2, 393199, 458753, 4, 458735, 458753, 4, 589807, 262145, 4, 655343, 458753, 2, 720879, 458753, 5, 786415, 458753, 2, 851951, 196609, 2, 131056, 327681, 5, 196592, 262145, 5, 262128, 262145, 5, 327664, 393217, 5, 393200, 393217, 5, 458736, 458753, 5, 589808, 458753, 5, 655344, 262145, 5, 720880, 393217, 5, 786416, 262145, 5, 851952, 393217, 5, 131057, 327681, 5, 196593, 262145, 5, 262129, 458753, 5, 327665, 327681, 2, 524273, 458753, 5, 589809, 327681, 5, 655345, 262145, 5, 720881, 393217, 5, 786417, 458753, 5, 917489, 458753, 5, 131058, 458753, 2, 196594, 327681, 5, 262130, 262145, 5, 327666, 393217, 5, 393202, 262145, 5, 458738, 262145, 5, 524274, 327681, 5, 589810, 393217, 5, 655346, 262145, 5, 720882, 327681, 5, 786418, 393217, 5, 131059, 262145, 5, 262131, 458753, 2, 327667, 327681, 4, 458739, 327681, 5, 524275, 458753, 2, 589811, 327681, 3, 655347, 458753, 5, 720883, 327681, 3, 786419, 262145, 5, 851955, 393217, 5, 917491, 458753, 5, 131060, 458753, 2, 196596, 458753, 5, 262132, 262145, 5, 327668, 262145, 2, 393204, 393217, 5, 458740, 458753, 2, 524276, 458753, 5, 589812, 458753, 2, 655348, 458753, 5, 720884, 196609, 2, 851956, 393217, 5, 917492, 262145, 5, 262133, 458753, 2, 327669, 393217, 5, 393205, 458753, 5, 458741, 458753, 2, 524277, 458753, 2, 589813, 393217, 5, 655349, 262145, 4, 720885, 327681, 5, 851957, 1, 2, 262134, 393217, 5, 327670, 458753, 2, 393206, 458753, 4, 458742, 262145, 5, 524278, 393217, 5, 589814, 393217, 5, 655350, 458753, 2, 720886, 327681, 5, 786422, 196609, 2, 851958, 458753, 2, 917494, 458753, 2, 983030, 327681, 5, 131063, 262145, 5, 196599, 393217, 5, 262135, 262145, 5, 327671, 327681, 5, 393207, 262145, 5, 458743, 327681, 5, 524279, 393217, 5, 589815, 327681, 5, 655351, 262145, 5, 720887, 327681, 5, 786423, 327681, 5, 851959, 393217, 5, 917495, 327681, 5, 983031, 393217, 5, 917496, 458753, 5, 983032, 327681, 5, 1048568, 393217, 5, 1114104, 327681, 5, 917497, 458753, 5, 983033, 458753, 4, 1048569, 458753, 2, 1114105, 458753, 2, 917498, 327681, 5, 983034, 393217, 5, 1048570, 458753, 5, 1114106, 393217, 2, 917499, 393217, 5, 983035, 327681, 5, 1048571, 458753, 2, 1114107, 458753, 5, 917500, 262145, 5, 983036, 262145, 5, 1048572, 393217, 5, 1114108, 458753, 5, 917501, 262145, 5, 983037, 327681, 5, 1048573, 327681, 5, 1114109, 131073, 2, 917502, 458753, 5, 983038, 262145, 5, 1048574, 458753, 2, 1114110, 458753, 2, 917503, 458753, 5, 983039, 458753, 2, 1048575, 327681, 2, 1114111, 262145, 5, 851968, 327681, 5, 917504, 458753, 5, 983040, 393217, 2, 1048576, 393217, 5, 851969, 393217, 5, 917505, 327681, 4, 983041, 262145, 5, 1048577, 458753, 5, 851970, 393217, 5, 917506, 262145, 2, 983042, 131073, 2, 1048578, 262145, 5, 1114114, 327681, 5, 1179650, 262145, 4, 1245186, 262145, 5, 1310722, 458753, 5, 1376258, 131073, 2, 1441794, 262145, 5, 1507330, 327681, 5, 1572866, 393217, 5, 1638402, 458753, 4, 1703938, 262145, 2, 1769474, 458753, 5, 1835010, 327681, 5, 1900546, 327681, 5, 851971, 458753, 5, 917507, 393217, 5, 983043, 393217, 5, 1048579, 458753, 5, 1114115, 458753, 5, 1179651, 458753, 5, 1245187, 393217, 5, 1310723, 393217, 5, 1376259, 393217, 5, 1441795, 458753, 5, 1507331, 327681, 5, 1572867, 458753, 5, 1638403, 262145, 5, 2228226, 458753, 5, 2293763, 458753, 5, 1179640, 393217, 5, 1245176, 262145, 5, 1179641, 262145, 5, 1245177, 458753, 2, 1179642, 327681, 2, 1245178, 458753, 5, 1179643, 458753, 5, 1245179, 327681, 5, 1179644, 393217, 5, 1245180, 262145, 2, 1179645, 262145, 4, 1245181, 262145, 4, 1179646, 458753, 2, 1245182, 327681, 5, 1179647, 458753, 5, 1245183, 262145, 5, 1114112, 458753, 2, 1179648, 393217, 5, 1114113, 458753, 5, 1179649, 262145, 5, 1048566, 262145, 4, 1114102, 458753, 2, 1179638, 393217, 5, 1245174, 327681, 4, 1048567, 458753, 2, 1114103, 327681, 5, 1179639, 458753, 5, 1245175, 458753, 5, 917512, 393217, 5, 983048, 393217, 5, 1048584, 327681, 5, 1114120, 458753, 5, 1179656, 393217, 5, 1245192, 393217, 5, 1310728, 327681, 5, 1376264, 262145, 5, 1441800, 458753, 5, 1507336, 393217, 5, 1572872, 458753, 5, 1638408, 458753, 5, -2031630, 393217, 5, -2031624, 262145, 5, -2097158, 393217, 5, -2031622, 327681, 5, -2097157, 327681, 5, -2031621, 458753, 2, -2097156, 327681, 5, -2031620, 458753, 2, -2097155, 393217, 5, -2031619, 262145, 5, -2031618, 393217, 5, -1507341, 327681, 5, -1572877, 393217, 5, -1703949, 458753, 5, -1703950, 327681, 5, -1769486, 393217, 5, -1835022, 458753, 2, -1966088, 262145, 5, -1966087, 262145, 5, -2031623, 393217, 5, -2097160, 393217, 5, -2097159, 262145, 5, -2097165, 393217, 5, -2031629, 262145, 5, -1966094, 327681, 5, -1441791, 327681, 5, -1638413, 458753, 5, -1900557, 327681, 5, -1966093, 458753, 5, -2162692, 458753, 2, -2162693, 393217, 5, -2228229, 327681, 5, -2228230, 458753, 5, -2293766, 131073, 2, -2293767, 262145, 5, -2293768, 262145, 2, -2359304, 262145, 5, -2162694, 458753, 5, -2228231, 327681, 5, -2359303, 327681, 5, -2162695, 262145, 5, -2162696, 393217, 5, -2228232, 393217, 5, 917485, 327681, 5, 851949, 327681, 5, 851948, 262145, 5, 786412, 327681, 5, 786411, 262145, 5, 720875, 458753, 5, 524264, 393217, 5, -1245209, 327681, 5, -1310744, 262145, 5, -1376279, 458753, 5, -1441814, 327681, 5, -1310745, 327681, 6, -1376280, 458753, 5, -1441815, 458753, 5, -1507350, 327681, 5, -1572885, 393217, 5, -1638420, 327681, 5, -1703955, 393217, 5, -1769490, 262145, 5, -1703954, 327681, 5, -1638419, 262145, 5, -1572884, 393217, 5, -1507349, 262145, 5, -1179673, 327681, 5, -1245208, 458753, 5, -1310743, 262145, 5, -1376278, 262145, 5, -1441813, 327681, 5, -1507348, 458753, 5, -1572883, 131073, 2, -1638418, 393217, 5, -1114137, 393217, 5, -1179672, 393217, 5, -1245207, 327681, 5, -1310742, 196609, 2, -1376277, 458753, 5, -1441812, 393217, 5, -1507347, 458753, 2, -1572882, 458753, 2, 393192, 327681, 5, 458728, 458753, 5, 589803, 393217, 5, 655339, 458753, 2, 655340, 327681, 5, 720876, 458753, 2, 720877, 327681, 4, 786413, 327681, 4, 786414, 458753, 4, 851950, 327681, 4, 720878, 458753, 2, 655342, 458753, 2, 655341, 458753, 2, 589805, 327681, 4, 589804, 458753, 4, 524268, 458753, 2, 524267, 262145, 5, 458731, 262145, 5, 327656, 262145, 5, 262120, 262145, 5, 589806, 327681, 4, 524270, 262145, 4, 524269, 262145, 5, 458733, 1, 2, 458732, 262145, 5, 393196, 327681, 5, 196585, 327681, 5, -24, 327681, 5, 65513, 327681, 5, 131049, 458753, 5, 131050, 262145, 5, 196586, 458753, 5, 196587, 65537, 2, 262123, 262145, 5, 262124, 458753, 5, 327660, 262145, 5, 393198, 458753, 5, -65560, 393217, 5, -65559, 327681, 5, -23, 393217, 5, -22, 458753, 5, 65514, 393217, 5, 65515, 393217, 5, 131051, 327681, 5, 131052, 327681, 4, 196588, 393217, 5, 196589, 327681, 2, 262125, 262145, 4, 262126, 65537, 2, 327662, 327681, 4, 196590, 393217, 4, 131054, 458753, 5, 131053, 327681, 4, 65517, 327681, 5, 65516, 262145, 5, -20, 262145, 4, -21, 327681, 5, -65557, 393217, 5, -65558, 393217, 5, -131094, 262145, 5, -131095, 262145, 5, -196631, 393217, 5, -458777, 393217, 5, -393240, 327681, 5, -327704, 458753, 5, -327703, 327681, 5, -262167, 262145, 5, -196630, 327681, 5, -196629, 458753, 5, -131093, 327681, 5, -131092, 327681, 4, -65556, 262145, 4, -65555, 458753, 5, -19, 262145, 5, -18, 327681, 5, 65518, 262145, 5, -65554, 458753, 5, -131090, 458753, 5, -131091, 393217, 5, -196627, 458753, 5, -262164, 196609, 6, -262165, 458753, 5, -327701, 393217, 6, -327702, 393217, 5, -393238, 327681, 4, -393239, 458753, 2, -458775, 262145, 5, -458776, 262145, 5, -524312, 458753, 5, -524313, 262145, 5, -589849, 393217, 5, -196626, 393217, 5, -262163, 327681, 6, -327700, 327681, 6, -393237, 1, 6, -458774, 262145, 6, -524311, 393217, 5, -589848, 393217, 5, -655385, 393217, 5, -786457, 458753, 5, -720921, 393217, 5, -720920, 327681, 5, -655384, 458753, 5, -655383, 327681, 5, -589847, 458753, 5, -589846, 327681, 6, -524310, 65537, 6, -524309, 65537, 6, -458773, 262145, 6, -458772, 196609, 6, -393236, 327681, 6, -393235, 131073, 6, -327699, 458753, 2, -327698, 458753, 2, -851993, 393217, 5, -786456, 393217, 5, -720919, 458753, 5, -655382, 262145, 5, -589845, 65537, 6, -524308, 327681, 6, -458771, 65537, 6, -393234, 327681, 4, -262162, 262145, 4, -458770, 65537, 6, -524306, 131073, 6, -524307, 327681, 6, -589843, 327681, 6, -589844, 65537, 6, -655380, 196609, 6, -655381, 1, 6, -720917, 393217, 5, -720918, 262145, 5, -786454, 327681, 5, -786455, 327681, 5, -851991, 262145, 5, -851992, 458753, 5, -917528, 262145, 5, -917529, 458753, 5, -983065, 262145, 5, -1048601, 1, 2, -1048600, 393217, 5, -983064, 327681, 5, -983063, 458753, 5, -917527, 458753, 5, -917526, 393217, 5, -851990, 458753, 5, -851989, 327681, 5, -786453, 327681, 5, -786452, 327681, 3, -720916, 131073, 1, -720915, 393217, 3, -655379, 262145, 6, -655378, 262145, 6, -589842, 327681, 6, -1114136, 327681, 5, -1114135, 196609, 2, -1048599, 393217, 5, -1048598, 393217, 5, -983062, 327681, 5, -983061, 458753, 5, -917525, 262145, 5, -917524, 393217, 5, -851988, 393217, 5, -851987, 262145, 5, -786451, 393217, 3, -786450, 327681, 3, -720914, 327681, 3, -1179671, 327681, 5, -1179670, 1, 2, -1114134, 327681, 5, -1114133, 65537, 2, -1048597, 393217, 5, -1048596, 327681, 4, -983060, 262145, 4, -917523, 458753, 5, -917522, 393217, 5, -851986, 393217, 5, -1245206, 327681, 5, -1179669, 458753, 2, -1114132, 327681, 4, -1048595, 327681, 5, -983058, 1, 6, -1245205, 262145, 5, -1179668, 262145, 4, -1048594, 131073, 6, -1310741, 327681, 5, -1310740, 458753, 5, -1245204, 327681, 5, -1245203, 262145, 5, -1179667, 262145, 5, -1179666, 1, 6, -1114130, 65537, 6, -1376276, 327681, 5, -1376275, 393217, 5, -1310739, 393217, 5, -1310738, 393217, 5, -1441811, 262145, 2, -1376274, 458753, 5, -1245202, 393217, 5, -1441810, 458753, 2, -1507346, 393217, 5, -917518, 327681, 2, -983054, 262145, 5, -1048590, 262145, 5, -25, 327681, 5, 65511, 262145, 5, 131047, 393217, 5, 196583, 327681, 5, 262119, 458753, 5, 327655, 458753, 5, 393191, 262145, 5, -65561, 458753, 5, -327705, 262145, 5, -393241, 262145, 5, 262121, 262145, 5, 262122, 458753, 5, 458729, 262145, 5, 458730, 262145, 5, 327659, 393217, 5, 393195, 458753, 5, 458727, 262145, 5, 1835022, 327681, 5, 1114127, 262145, 5, 1048591, 262145, 5, 983055, 327681, 5, 327695, 393217, 5, 327692, 262145, 5, 327693, 327681, 5, 1376270, 327681, 5, 983056, 458753, 5, 1048592, 393217, 5, 1114128, 65537, 2, 1900559, 393217, 5, 1769488, 262145, 5, 1835024, 327681, 2, 1900560, 262145, 5, 458766, 393217, 5, 393230, 393217, 5, 393231, 262145, 5, 458767, 393217, 5, 524302, 327681, 5, 1179663, 262145, 4, 1245199, 327681, 5, 1310735, 327681, 5, 1376271, 393217, 5, 1441807, 262145, 5, 1507343, 458753, 5, 1572879, 458753, 5, 1638415, 262145, 5, 1703951, 393217, 5, 917519, 458753, 5, 1769487, 327681, 5, -262166, 327681, 2, -851984, 327681, 5, -983055, 327681, 4, -983056, 393217, 5, -917520, 458753, 5, -917519, 458753, 5, -1376260, 196609, 4, -1245198, 393217, 5, -1310735, 262145, 5, -1245199, 262145, 5, -1376262, 1, 4, -1376261, 393217, 6, 2293768, 327681, 5, -1572872, 262145, 5, -393230, 262145, 5, -327694, 262145, 5, -262158, 262145, 5, -393229, 393217, 5, -327693, 458753, 5, -262157, 393217, 5, -11, 1, 4, 65525, 393217, 5, 131061, 393217, 5, 196597, 458753, 2, 65524, 458753, 2, 196595, 458753, 2, 196598, 327681, 4, 393203, 262145, 5, 393201, 458753, 5, -196628, 327681, 5, 458737, 393217, 5, 524272, 458753, 5, 524271, 327681, 5, 458734, 458753, 4, 393197, 262145, 4, 327661, 262145, 4, 393194, 458753, 5, 393193, 262145, 5, 327657, 262145, 5, 327658, 327681, 5, 196584, 458753, 5, 131048, 458753, 5, 65512, 458753, 5, -131096, 458753, 5, -196632, 262145, 5, -262168, 393217, 5, -262169, 393217, 5, -196633, 458753, 5, -131097, 262145, 5, 524265, 262145, 5, 524266, 262145, 5, 589802, 393217, 5, 655338, 458753, 4, 720874, 458753, 5, 720873, 327681, 5, 655337, 393217, 5, 589801, 458753, 5, 655336, 262145, 5, 589800, 262145, 5, 524263, 327681, 5, 589799, 458753, 5, 655335, 393217, 5, 720872, 262145, 5, 786409, 327681, 5, 786410, 327681, 5, 720871, 393217, 5, 786407, 327681, 5, 786408, 393217, 5, 851944, 393217, 5, 851945, 327681, 5, 851946, 458753, 5, 851947, 458753, 5, 917482, 393217, 5, 917483, 393217, 5, 917484, 393217, 5, 917486, 458753, 5, 917487, 327681, 5, 917488, 393217, 5, 851953, 458753, 5, 851954, 458753, 5, 917490, 327681, 5, 786420, 327681, 5, 786421, 327681, 5, 917493, 262145, 5, 1835023, 327681, 5, 524303, 327681, 5, 917520, 458753, 5, -1376245, 393217, 5, -1376246, 393217, 5, -1441782, 458753, 5, -1441783, 458753, 5, -1376244, 458753, 5, -1441781, 458753, 5, -1507318, 458753, 5, -1507319, 262145, 5, -1507320, 458753, 2, -1572856, 458753, 5, -1572857, 458753, 2, -1572855, 458753, 5, -1638393, 458753, 5, -1638394, 327681, 5, -1703943, 458753, 5, -1769479, 393217, 5, -1769478, 262145, 5, -1703942, 458753, 5, -1769477, 327681, 5, -1703941, 458753, 5, -1638405, 327681, 5, -1835013, 393217, 5, -1900549, 458753, 5, -1966085, 393217, 5, -1703940, 458753, 5, -1638404, 262145, 5, -1769476, 327681, 5, -1835012, 458753, 5, -1900548, 262145, 5, -1966084, 327681, 2, -1703939, 458753, 5, -1638403, 393217, 5, -1769475, 262145, 5, -1835011, 262145, 5, -1900547, 393217, 5, -1966083, 262145, 5, -1769474, 458753, 5, -1703938, 327681, 5, -1835010, 393217, 5, -1900546, 196609, 2, -1966082, 327681, 5, -1638402, 327681, 5, -1900545, 327681, 5, -1835009, 458753, 2, -1769473, 327681, 5, -1703937, 327681, 5, -2031616, 458753, 2, -1769471, 393217, 5, -1769472, 458753, 2, -1769470, 327681, 5, -1769469, 458753, 2, -1900542, 327681, 5, -1966079, 262145, 5, -1966081, 1, 2, -2031617, 262145, 5, -2097154, 262145, 5, -1966078, 327681, 2, -1835005, 327681, 5, -1835004, 262145, 5, -1769468, 262145, 5, -1769467, 327681, 5, -1703931, 262145, 5, -2031615, 393217, 5, -2097152, 196609, 2, -2097153, 327681, 2, -2162691, 1, 2, -1703930, 393217, 5, -1900540, 393217, 5, -1900541, 393217, 5, -1966077, 262145, 5, -1638401, 262145, 5, -983053, 327681, 5, -1114131, 458753, 5, -983059, 327681, 5, -1441809, 458753, 2, -2359302, 458753, 5, -2359301, 393217, 5, -2293765, 393217, 5, -2359300, 458753, 5, -2293764, 458753, 5, -2228228, 262145, 5, -2359299, 327681, 5, -2293763, 327681, 5, -2228227, 393217, 5, -2359298, 262145, 5, -2293762, 327681, 5, -2228226, 393217, 5, -2162690, 262145, 5, -2359297, 458753, 5, -2293761, 393217, 5, -2228225, 262145, 5, -2162689, 262145, 5, -2424832, 458753, 5, -2359296, 393217, 5, -2293760, 262145, 5, -2228224, 327681, 5, -2162688, 262145, 5, -2424831, 262145, 5, -2359295, 327681, 5, -2293759, 393217, 5, -2228223, 262145, 2, -2162687, 262145, 5, -2097151, 262145, 5, -2424830, 393217, 5, -2359294, 262145, 5, -2293758, 262145, 5, -2228222, 262145, 5, -2162686, 458753, 5, -2097150, 262145, 5, -2031614, 458753, 5, -2424829, 327681, 5, -2359293, 393217, 5, -2293757, 393217, 5, -2228221, 458753, 5, -2162685, 327681, 5, -2097149, 262145, 5, -2031613, 393217, 2, -2424828, 393217, 5, -2359292, 327681, 5, -2293756, 458753, 5, -2228220, 327681, 5, -2162684, 262145, 2, -2097148, 262145, 5, -2031612, 262145, 5, -1966076, 327681, 5, -2424827, 327681, 5, -2359291, 393217, 5, -2293755, 393217, 5, -2228219, 262145, 5, -2162683, 393217, 5, -2097147, 327681, 5, -2031611, 262145, 5, -1966075, 458753, 5, -1900539, 393217, 5, -1835003, 262145, 5, -2424826, 327681, 5, -2359290, 393217, 5, -2293754, 262145, 5, -2228218, 262145, 5, -2162682, 458753, 2, -2097146, 458753, 5, -2031610, 262145, 5, -1966074, 262145, 5, -1900538, 393217, 5, -1835002, 262145, 5, -1769466, 327681, 5, -2424825, 262145, 5, -2359289, 393217, 5, -2293753, 262145, 5, -2228217, 458753, 5, -2162681, 458753, 5, -2097145, 327681, 5, -2031609, 262145, 5, -1966073, 458753, 5, -1900537, 393217, 5, -1835001, 327681, 5, -1769465, 458753, 5, -1703929, 1, 2, -2424824, 458753, 5, -2359288, 393217, 5, -2293752, 458753, 5, -2228216, 393217, 5, -2162680, 327681, 2, -2097144, 262145, 5, -2031608, 458753, 5, -1966072, 458753, 5, -1900536, 262145, 5, -1835000, 262145, 5, -1769464, 196609, 2, -1703928, 393217, 5, -1638392, 458753, 5, -2424823, 458753, 5, -2359287, 458753, 5, -2293751, 327681, 5, -2228215, 262145, 5, -2162679, 327681, 5, -2097143, 393217, 5, -2031607, 458753, 5, -1966071, 327681, 5, -1900535, 262145, 5, -1834999, 262145, 5, -1769463, 262145, 5, -1703927, 393217, 5, -1638391, 327681, 5, -2424822, 262145, 5, -2359286, 327681, 5, -2293750, 393217, 5, -2228214, 393217, 5, -2162678, 262145, 5, -2097142, 393217, 5, -2031606, 262145, 5, -1966070, 327681, 5, -1900534, 262145, 5, -1834998, 1, 0, -1769462, 131073, 0, -1703926, 458753, 5, -1638390, 393217, 5, -1572854, 458753, 5, -2424821, 458753, 5, -2359285, 393217, 5, -2293749, 458753, 5, -2228213, 393217, 5, -2162677, 458753, 2, -2097141, 458753, 5, -2031605, 327681, 2, -1966069, 327681, 5, -1900533, 393217, 0, -1834997, 393217, 6, -1769461, 393217, 6, -1703925, 65537, 4, -1638389, 262145, 5, -1572853, 393217, 5, -1507317, 1, 6, -2424820, 458753, 5, -2359284, 393217, 5, -2293748, 393217, 5, -2228212, 458753, 5, -2162676, 458753, 5, -2097140, 458753, 5, -2031604, 458753, 5, -1966068, 393217, 5, -1900532, 393217, 5, -1834996, 262145, 6, -1769460, 262145, 6, -1703924, 327681, 1, -1638388, 65538, 0, -1572852, 458753, 5, -1507316, 458753, 5, -1441780, 262145, 4, -2424819, 262145, 5, -2359283, 393217, 5, -2293747, 327681, 5, -2228211, 262145, 5, -2162675, 393217, 5, -2097139, 65537, 2, -2031603, 262145, 5, -1966067, 327681, 5, -1900531, 458753, 5, -1834995, 262145, 6, -1769459, 131073, 6, -1703923, 327681, 1, -1638387, 196610, 2, -1572851, 327681, 5, -1507315, 393217, 5, -1441779, 262145, 5, -1376243, 393217, 5, -2424818, 458753, 5, -2359282, 327681, 5, -2293746, 393217, 5, -2228210, 262145, 5, -2162674, 393217, 5, -2097138, 327681, 5, -2031602, 393217, 5, -1966066, 458753, 5, -1900530, 458753, 5, -1834994, 196609, 5, -1769458, 65537, 6, -1703922, 327681, 1, -1638386, 327681, 5, -1572850, 393217, 5, -1507314, 393217, 5, -1441778, 393217, 5, -1376242, 393217, 5, -2424817, 458753, 5, -2359281, 393217, 5, -2293745, 458753, 2, -2228209, 458753, 5, -2162673, 327681, 5, -2097137, 393217, 5, -2031601, 458753, 2, -1966065, 458753, 5, -1900529, 327681, 5, -1834993, 262145, 5, -1769457, 327681, 5, -1703921, 327681, 4, -1638385, 458753, 5, -1572849, 393217, 4, -1507313, 262145, 5, -1441777, 327681, 5, -1376241, 393217, 5, -2424816, 327681, 5, -2359280, 458753, 5, -2293744, 327681, 5, -2228208, 262145, 5, -2162672, 327681, 2, -2097136, 262145, 5, -2031600, 327681, 5, -1966064, 393217, 5, -1900528, 262145, 5, -1834992, 327681, 5, -1769456, 393217, 5, -1703920, 262145, 5, -1638384, 458753, 5, -1572848, 393217, 5, -1507312, 458753, 5, -1441776, 262145, 4, -1376240, 393217, 5, -2424815, 262145, 5, -2359279, 393217, 5, -2293743, 393217, 5, -2228207, 327681, 2, -2162671, 327681, 5, -2097135, 458753, 5, -2031599, 458753, 5, -1966063, 393217, 5, -1900527, 327681, 5, -1834991, 262145, 5, -1769455, 262145, 5, -1703919, 458753, 5, -1638383, 458753, 2, -1572847, 262145, 5, -1507311, 327681, 5, -1441775, 327681, 5, -1376239, 458753, 5, -2424814, 262145, 5, -2359278, 393217, 5, -2293742, 65537, 2, -2228206, 262145, 5, -2162670, 327681, 5, -2097134, 393217, 5, -2031598, 458753, 5, -1966062, 393217, 5, -1900526, 458753, 5, -1834990, 458753, 5, -1769454, 262145, 5, -1703918, 327681, 5, -1638382, 393217, 5, -1572846, 262145, 5, -1507310, 327681, 5, -1441774, 393217, 5, -1376238, 327681, 4, -1048565, 262145, 5, -983029, 393217, 5, -917493, 458753, 5, -851957, 327681, 5, -786421, 327681, 5, -720885, 458753, 5, -655349, 458753, 5, -589813, 458753, 5, -524277, 393217, 5, -458741, 262145, 5, -393205, 262145, 5, -327669, 393217, 5, -262133, 393217, 5, -1048568, 262145, 5, -1048567, 262145, 5, -1048566, 327681, 5, -983032, 458753, 5, -983031, 458753, 5, -983030, 327681, 5, -917496, 458753, 5, -851960, 458753, 5, -786424, 262145, 5, -720888, 327681, 5, -655352, 262145, 5, -589816, 393217, 5, -524280, 393217, 5, -458744, 393217, 5, -393208, 393217, 5, -327672, 262145, 5, -262136, 262145, 5, -196600, 262145, 5, -131064, 262145, 5, -917495, 458753, 5, -851959, 327681, 5, -786423, 393217, 5, -720887, 393217, 5, -655351, 262145, 5, -589815, 327681, 5, -524279, 262145, 5, -458743, 327681, 5, -393207, 262145, 5, -327671, 327681, 5, -262135, 458753, 5, -196599, 262145, 5, -131063, 458753, 5, -917494, 327681, 5, -851958, 327681, 5, -786422, 327681, 5, -720886, 458753, 5, -655350, 327681, 5, -589814, 458753, 5, -524278, 393217, 5, -458742, 393217, 5, -393206, 262145, 5, -327670, 262145, 5, -262134, 458753, 5, -196598, 393217, 5, -131062, 458753, 5, -196597, 458753, 5, -131061, 262145, 5, -524272, 458753, 5, -524271, 327681, 5, -524270, 458753, 5, -524269, 262145, 5, -1310704, 458753, 5, -1245168, 393217, 5, -1179632, 262145, 5, -1114096, 393217, 5, -1048560, 393217, 5, -983024, 262145, 5, -917488, 262145, 5, -851952, 327681, 5, -786416, 262145, 5, -720880, 327681, 5, -655344, 262145, 5, -589808, 262145, 5, -1310703, 458753, 4, -1245167, 393217, 6, -1179631, 458753, 2, -1114095, 393217, 5, -1048559, 393217, 5, -983023, 458753, 5, -917487, 393217, 5, -851951, 393217, 5, -786415, 327681, 5, -720879, 393217, 5, -655343, 327681, 5, -589807, 458753, 5, -1310702, 393217, 5, -1245166, 1, 0, -1179630, 327681, 0, -1114094, 458753, 5, -1048558, 262145, 5, -983022, 458753, 5, -917486, 393217, 5, -851950, 327681, 5, -786414, 393217, 5, -720878, 458753, 5, -655342, 262145, 5, -589806, 393217, 5, -1507309, 458753, 5, -1441773, 262145, 5, -1376237, 458753, 5, -1310701, 327681, 4, -1245165, 393217, 5, -1179629, 327681, 5, -1114093, 393217, 5, -1048557, 458753, 5, -983021, 393217, 5, -917485, 327681, 5, -851949, 327681, 5, -786413, 458753, 5, -720877, 327681, 5, -655341, 262145, 5, -589805, 393217, 5, -2359277, 262145, 5, -2293741, 393217, 5, -2228205, 458753, 2, -2162669, 458753, 2, -2097133, 393217, 5, -2031597, 262145, 5, -1966061, 393217, 5, -1900525, 393217, 5, -1834989, 458753, 5, -1769453, 393217, 5, -1703917, 458753, 5, -1638381, 458753, 5, -1572845, 458753, 5, -2097127, 262145, 5, -2031591, 393217, 5, -1966055, 393217, 5, -1900519, 262145, 5, -1834983, 262145, 5, -1769447, 393217, 5, -1703911, 458753, 5, -1638375, 262145, 5, -1572839, 327681, 5, -1507303, 327681, 5, -1441767, 458753, 5, -1376231, 327681, 5, -1310695, 393217, 5, -1245159, 458753, 5, -1179623, 262145, 4, -1048551, 327681, 5, -983015, 393217, 3, -917479, 262145, 5, -851943, 262145, 2, -786407, 262145, 5, -720871, 262145, 5, -655335, 458753, 5, -589799, 458753, 2, -524263, 262145, 5, -458727, 458753, 3, -393191, 458753, 3, -327655, 393217, 5, -262119, 262145, 5, -196583, 262145, 5, -2031590, 262145, 5, -1966054, 393217, 2, -1900518, 458753, 2, -1834982, 393217, 5, -1769446, 327681, 5, -1703910, 327681, 5, -1638374, 458753, 4, -1572838, 262145, 5, -1507302, 458753, 5, -1441766, 327681, 5, -1376230, 393217, 5, -1310694, 262145, 4, -1245158, 1, 0, -1179622, 196609, 6, -1114086, 262145, 6, -1048550, 327681, 5, -983014, 327681, 5, -917478, 262145, 5, -851942, 458753, 5, -786406, 327681, 5, -720870, 131073, 4, -655334, 458753, 2, -589798, 327681, 5, -524262, 393217, 5, -458726, 458753, 3, -393190, 458753, 3, -327654, 262145, 5, -262118, 393217, 6, -196582, 262145, 6, -1966053, 458753, 2, -1900517, 262145, 5, -1834981, 262145, 5, -1769445, 327681, 5, -1703909, 327681, 5, -1638373, 458753, 5, -1572837, 65537, 6, -1507301, 458753, 5, -1441765, 327681, 5, -1376229, 262145, 5, -1310693, 393217, 5, -1245157, 262145, 5, -1179621, 196609, 1, -1114085, 196609, 1, -1048549, 327681, 4, -983013, 262145, 2, -917477, 262145, 5, -851941, 458753, 2, -786405, 262145, 5, -720869, 65537, 6, -655333, 65537, 2, -589797, 393217, 5, -524261, 458753, 5, -458725, 262145, 5, -393189, 458753, 5, -327653, 262145, 6, -262117, 262145, 6, -196581, 327681, 6, -1834980, 393217, 5, -1769444, 393217, 5, -1703908, 458753, 5, -1638372, 262145, 5, -1572836, 327681, 5, -1507300, 262145, 5, -1441764, 393217, 5, -1376228, 262145, 5, -1310692, 262145, 5, -1245156, 262145, 5, -1179620, 262145, 5, -1114084, 458753, 5, -1048548, 393217, 5, -983012, 262145, 5, -917476, 65537, 5, -851940, 196609, 5, -786404, 262145, 5, -720868, 393217, 5, -655332, 327681, 5, -589796, 458753, 5, -524260, 393217, 5, -458724, 327681, 5, -393188, 393217, 5, -327652, 458753, 6, -262116, 262145, 6, -196580, 458753, 6, -1834979, 458753, 2, -1769443, 262145, 5, -1703907, 262145, 5, -1638371, 262145, 5, -1572835, 458753, 5, -1507299, 262145, 5, -1441763, 262145, 5, -1376227, 262145, 5, -1310691, 458753, 2, -1245155, 327681, 5, -1179619, 327681, 5, -1114083, 327681, 5, -1048547, 393217, 5, -983011, 458753, 4, -917475, 1, 4, -851939, 131073, 5, -786403, 262145, 5, -720867, 393217, 5, -655331, 327681, 5, -589795, 458753, 4, -524259, 393217, 5, -458723, 262145, 5, -393187, 458753, 5, -327651, 327681, 5, -262115, 458753, 6, -196579, 327681, 6, -1769442, 393217, 5, -1703906, 262145, 5, -1638370, 458753, 5, -1572834, 393217, 5, -1507298, 458753, 5, -1441762, 327681, 4, -1376226, 393217, 5, -1310690, 458753, 5, -1245154, 327681, 5, -1179618, 262145, 5, -1114082, 458753, 5, -1048546, 458753, 2, -983010, 458753, 2, -917474, 327681, 5, -851938, 327681, 5, -786402, 262145, 5, -720866, 393217, 5, -655330, 393217, 5, -589794, 393217, 5, -524258, 327681, 5, -458722, 393217, 5, -393186, 458753, 5, -327650, 458753, 5, -262114, 262145, 5, -196578, 262145, 5, -1703905, 458753, 2, -1638369, 458753, 5, -1572833, 262145, 5, -1507297, 1, 6, -1441761, 65537, 6, -1376225, 262145, 6, -1310689, 262145, 6, -1245153, 65537, 2, -1179617, 393217, 5, -1114081, 393217, 5, -1048545, 458753, 5, -983009, 393217, 5, -917473, 393217, 5, -851937, 458753, 5, -786401, 327681, 5, -720865, 458753, 5, -655329, 458753, 5, -589793, 262145, 5, -524257, 458753, 5, -458721, 327681, 5, -393185, 1, 2, -327649, 262145, 5, -262113, 393217, 5, -196577, 262145, 5, -1638368, 458753, 5, -1572832, 393217, 5, -1507296, 65537, 6, -1441760, 393217, 6, -1376224, 131073, 6, -1310688, 327681, 6, -1245152, 458753, 6, -1179616, 196609, 0, -1114080, 262145, 5, -1048544, 327681, 5, -983008, 262145, 5, -917472, 458753, 5, -851936, 458753, 2, -786400, 458753, 2, -720864, 327681, 5, -655328, 458753, 5, -589792, 393217, 5, -524256, 327681, 5, -458720, 393217, 5, -393184, 393217, 2, -327648, 458753, 5, -262112, 458753, 5, -196576, 327681, 5, -1507295, 131073, 6, -1441759, 131073, 6, -1376223, 262145, 6, -1310687, 65537, 6, -1245151, 327681, 6, -1179615, 196609, 0, -1114079, 327681, 5, -1048543, 262145, 5, -983007, 393217, 5, -917471, 458753, 5, -851935, 458753, 2, -786399, 393217, 2, -720863, 393217, 5, -655327, 458753, 2, -589791, 458753, 5, -524255, 327681, 5, -458719, 393217, 5, -393183, 393217, 5, -327647, 262145, 5, -262111, 458753, 5, -196575, 393217, 5, -1441758, 65537, 6, -1376222, 327681, 6, -1310686, 196609, 6, -1245150, 393217, 6, -1179614, 65537, 2, -1114078, 458753, 5, -1048542, 458753, 2, -983006, 327681, 5, -917470, 262145, 5, -851934, 458753, 5, -786398, 393217, 5, -720862, 262145, 5, -655326, 327681, 5, -589790, 393217, 5, -524254, 327681, 5, -458718, 393217, 5, -393182, 458753, 5, -327646, 458753, 5, -262110, 262145, 5, -196574, 393217, 5, -1441757, 393217, 2, -1376221, 393217, 2, -1310685, 327681, 5, -1245149, 65537, 2, -1179613, 458753, 5, -1114077, 393217, 5, -1048541, 327681, 5, -983005, 458753, 5, -917469, 262145, 5, -851933, 458753, 5, -786397, 262145, 5, -720861, 393217, 5, -655325, 327681, 5, -589789, 458753, 5, -524253, 327681, 5, -458717, 327681, 5, -393181, 458753, 5, -327645, 327681, 5, -262109, 327681, 5, -196573, 458753, 5, -1376220, 327681, 5, -1310684, 393217, 5, -1245148, 262145, 5, -1179612, 393217, 5, -1114076, 458753, 5, -1048540, 327681, 5, -983004, 393217, 5, -917468, 327681, 5, -851932, 327681, 5, -786396, 262145, 5, -720860, 458753, 5, -655324, 458753, 5, -589788, 458753, 5, -524252, 327681, 5, -458716, 262145, 5, -393180, 393217, 5, -327644, 262145, 5, -262108, 458753, 5, -196572, 262145, 5, -65528, 393217, 5, 8, 262145, 5, -65527, 327681, 5, 9, 262145, 5, -65526, 393217, 5, 10, 393217, 5, -65525, 327681, 5, 11, 393217, 5, -65524, 262145, 5, 12, 458753, 5, -65523, 393217, 5, 13, 393217, 5, -65522, 458753, 5, 14, 262145, 5, -65521, 262145, 5, 15, 458753, 5, -65520, 393217, 5, 16, 458753, 5, -65519, 458753, 5, 17, 458753, 5, -65518, 458753, 5, 18, 393217, 5, -196596, 262145, 5, -131060, 393217, 5, -196595, 393217, 5, -131059, 327681, 5, -196594, 458753, 5, -131058, 393217, 5, -196593, 458753, 5, -131057, 262145, 5, -196592, 393217, 5, -131056, 262145, 5, -196591, 262145, 5, -131055, 393217, 5, -196590, 327681, 5, -131054, 393217, 5, -196589, 393217, 5, -131053, 393217, 5, -65517, 393217, 5, 19, 458753, 5, -196588, 327681, 5, -131052, 1, 1, -65516, 196609, 2, 20, 458753, 4, -196587, 458753, 4, -131051, 262145, 6, -65515, 196609, 0, 21, 327681, 2, -196586, 393217, 5, -131050, 1, 2, -196585, 458753, 5, -131049, 458753, 5, -196584, 458753, 5, -131048, 262145, 5, -131047, 458753, 2, 2293762, 458753, 5, 131062, 262145, 5, 851943, 458753, 5, 917479, 262145, 5, 917480, 393217, 5, 917481, 327681, 5, 65557, 262145, 5, 131093, 327681, 5, 196629, 458753, 4, 262165, 393217, 5, 327701, 262145, 2, 393237, 327681, 2, 458773, 458753, 2, 524309, 1, 0, 589845, 131073, 0, 655381, 131073, 0, 720917, 458753, 4, 786453, 393217, 5, 851989, 327681, 5, 720918, 196609, 6, 786454, 262145, 4, 851990, 262145, 5, 720919, 458753, 2, 786455, 327681, 2, 851991, 393217, 5, 720920, 327681, 5, 786456, 393217, 5, 851992, 458753, 5, 720921, 393217, 5, 786457, 458753, 5, 851993, 458753, 5, 1179664, 327681, 4, 917521, 262145, 5, 983057, 393217, 5, 1048593, 458753, 5, 1114129, 262145, 5, 1179665, 458753, 2, 917522, 458753, 4, 983058, 458753, 5, 1048594, 458753, 2, 1114130, 458753, 2, 1179666, 458753, 5, 917523, 327681, 2, 983059, 393217, 5, 1048595, 262145, 5, 1114131, 458753, 5, 1179667, 393217, 5, 917524, 458753, 5, 983060, 262145, 5, 1048596, 393217, 5, 1114132, 458753, 5, 1179668, 393217, 5, 917525, 393217, 5, 983061, 393217, 5, 1048597, 458753, 2, 1114133, 393217, 5, 1179669, 262145, 5, 917526, 327681, 5, 983062, 393217, 5, 1048598, 393217, 5, 1114134, 262145, 5, 1179670, 458753, 5, 917527, 458753, 5, 983063, 327681, 5, 1048599, 458753, 5, 1114135, 327681, 5, 1179671, 393217, 5, 917528, 393217, 5, 983064, 393217, 5, 1048600, 262145, 5, 917529, 393217, 5, 983065, 262145, 5, 1048601, 458753, 5, 2293769, 327681, 5, 2293770, 262145, 5, 2293771, 393217, 5, 2293772, 393217, 5, 1245200, 458753, 5, 1310736, 393217, 5, 1376272, 393217, 5, 1441808, 458753, 5, 1507344, 327681, 5, 1572880, 458753, 5, 1638416, 262145, 2, 1703952, 65537, 2, 1245201, 393217, 5, 1310737, 262145, 5, 1376273, 393217, 5, 1441809, 458753, 5, 1507345, 393217, 5, 1572881, 262145, 5, 1638417, 458753, 5, 1703953, 458753, 5, 1769489, 393217, 5, 1835025, 458753, 5, 1900561, 458753, 2, 1245202, 262145, 5, 1310738, 262145, 5, 1376274, 458753, 6, 1441810, 327681, 6, 1507346, 327681, 5, 1572882, 262145, 5, 1638418, 327681, 5, 1703954, 458753, 2, 1769490, 327681, 5, 1835026, 131073, 2, 1900562, 327681, 5, 1245203, 262145, 5, 1310739, 262145, 5, 1376275, 393217, 6, 1441811, 327681, 6, 1507347, 262145, 6, 1572883, 393217, 5, 1638419, 131073, 2, 1703955, 393217, 5, 1769491, 262145, 5, 1835027, 327681, 5, 1900563, 327681, 5, 1245204, 327681, 5, 1310740, 393217, 5, 1376276, 262145, 5, 1441812, 327681, 6, 1507348, 393217, 6, 1572884, 458753, 5, 1638420, 458753, 5, 1703956, 393217, 5, 1769492, 262145, 5, 1835028, 327681, 5, 1900564, 327681, 5, 1245205, 262145, 4, 1310741, 327681, 5, 1376277, 262145, 5, 1441813, 458753, 5, 1507349, 393217, 5, 1572885, 262145, 5, 1638421, 393217, 5, 1703957, 327681, 5, 1769493, 393217, 5, 1835029, 458753, 5, 1900565, 327681, 5, 1245206, 327681, 5, 1310742, 327681, 5, 1376278, 262145, 5, 1441814, 458753, 5, 1507350, 458753, 5, 1572886, 393217, 5, 1245207, 327681, 5, 1310743, 262145, 5, 1376279, 393217, 5, 1441815, 262145, 5, 1507351, 393217, 5, 1572887, 327681, 4, 1310744, 327681, 5, 1376280, 262145, 5, 1441816, 262145, 5, 1507352, 262145, 5, 1572888, 327681, 5, -131046, 196609, 6, 720922, 393217, 5, 786458, 262145, 6, 851994, 327681, 6, 917530, 458753, 6, 983066, 327681, 5, 1048602, 327681, 5, -131045, 65537, 1, 720923, 458753, 6, 786459, 458753, 6, 851995, 458753, 6, 917531, 327681, 6, 983067, 262145, 5, 1048603, 458753, 5, -131044, 393217, 5, 720924, 393217, 6, 786460, 327681, 6, 851996, 393217, 6, 917532, 393217, 6, 983068, 393217, 5, 1048604, 393217, 5, -131043, 327681, 5, 720925, 458753, 6, 786461, 458753, 6, 851997, 393217, 6, 917533, 262145, 6, 983069, 327681, 5, 1048605, 458753, 5, -131042, 262145, 5, 720926, 327681, 6, 786462, 327681, 6, 851998, 327681, 6, 917534, 262145, 5, 983070, 327681, 5, 1048606, 262145, 4, -131041, 393217, 5, 720927, 327681, 6, 786463, 262145, 6, 851999, 393217, 5, 917535, 262145, 5, 983071, 393217, 5, 1048607, 458753, 5, -131040, 327681, 5, 720928, 393217, 5, 786464, 327681, 5, 852000, 393217, 5, 917536, 327681, 4, 983072, 262145, 5, 1048608, 458753, 5, -131039, 393217, 5, 720929, 458753, 5, 786465, 393217, 5, 852001, 327681, 5, 917537, 262145, 4, 983073, 262145, 5, 1048609, 393217, 5, 851976, 458753, 5, 851977, 327681, 5, 851978, 327681, 5, 851979, 458753, 5, 851980, 262145, 5, 851981, 327681, 5, 851982, 262145, 5, 851983, 327681, 5, 851984, 327681, 5, 851985, 327681, 5, 851986, 458753, 5, 851987, 458753, 5, 851988, 327681, 5, 131092, 262145, 2, 196628, 327681, 5, 262164, 458753, 5, 327700, 327681, 5, 393236, 458753, 2, 458772, 262145, 5, 524308, 327681, 5, 589844, 327681, 5, 655380, 327681, 5, 720916, 458753, 5, 786452, 458753, 2, 65556, 393217, 5, -983016, 458753, 5, -917480, 262145, 5, -851944, 393217, 5, -786408, 262145, 5, -720872, 393217, 5, -655336, 327681, 5, -589800, 262145, 5, -524264, 458753, 5, -458728, 458753, 5, -393192, 458753, 5, -327656, 393217, 5, -262120, 393217, 5, -2031592, 262145, 5, -1966056, 262145, 5, -1900520, 327681, 5, -1834984, 262145, 5, -1769448, 393217, 5, -1703912, 327681, 5, -1638376, 393217, 5, -1572840, 327681, 5, -1507304, 458753, 5, -1441768, 458753, 5, -1376232, 262145, 5, -1310696, 393217, 5, -1245160, 327681, 5, -1179624, 262145, 5, -1114088, 327681, 5, -1048552, 327681, 5, -2162664, 458753, 5, -2097128, 393217, 5, -2490365, 262145, 5, -2490364, 393217, 5, -2490363, 262145, 5, -2490362, 327681, 5, -2490361, 327681, 5, -2490360, 458753, 5, -2490359, 393217, 5, -2490358, 393217, 5, -2490357, 327681, 5, -2490356, 393217, 5, -2490355, 393217, 5, -2490354, 262145, 5, -2490353, 393217, 5, -2490352, 327681, 5, -2490351, 393217, 2, -2424840, 458753, 5, -2424839, 393217, 5, -2424838, 262145, 5, -2424837, 262145, 5, -2424836, 393217, 5, -2424835, 262145, 5, -2424834, 458753, 5, -2424833, 327681, 5, -2490368, 393217, 5, -2490367, 327681, 5, -2490366, 327681, 5, -1245197, 2, 0, -1114087, 327681, 5, -917492, 2, 0, -983028, 2, 0, 1703939, 458753, 5, 1769475, 262145, 5, 1835011, 458753, 5, 1703944, 262145, 5, 1769480, 458753, 5, 1835016, 393217, 5, 2359298, 458753, 5, 2424834, 393217, 5, 2490370, 393217, 5, 2555906, 393217, 5, 2359299, 458753, 5, 2424835, 262145, 5, 2490371, 262145, 5, 2555907, 262145, 5, 2359304, 458753, 5, 2424840, 393217, 5, 2490376, 262145, 5, 2555912, 327681, 5, 2359305, 458753, 5, 2424841, 393217, 5, 2490377, 327681, 5, 2555913, 327681, 5, 2359306, 262145, 5, 2424842, 458753, 2, 2490378, 262145, 4, 2555914, 393217, 5, 2359307, 458753, 5, 2424843, 262145, 2, 2490379, 262145, 5, 2555915, 327681, 4, 2359308, 458753, 5, 2424844, 327681, 4, 2490380, 393217, 5, 2555916, 327681, 5, 2490381, 393217, 5, 2555917, 327681, 5, 2621442, 327681, 5, 2621443, 393217, 5, 2490382, 393217, 5, 2555918, 262145, 5, 2490383, 393217, 5, 2555919, 327681, 5, 2490384, 327681, 5, 2555920, 458753, 5, 2490385, 262145, 5, 2555921, 327681, 5, 2490386, 327681, 5, 2555922, 327681, 5, 2490387, 327681, 5, 2555923, 262145, 5, 2490388, 262145, 5, 2555924, 262145, 5, 2490389, 458753, 4, 2555925, 393217, 5, 2621448, 458753, 5, 2621449, 458753, 5, 2621450, 262145, 5, 2621451, 262145, 4, 2621452, 458753, 5, 2621453, 393217, 5, 2621454, 327681, 5, 2621455, 393217, 5, 2621456, 393217, 5, 2621457, 458753, 5, 2621458, 393217, 5, 2621459, 262145, 5, 2621460, 393217, 5, 2686984, 327681, 5, 2752520, 65537, 2, 2818056, 458753, 5, 2883592, 458753, 5, 2949128, 327681, 5, 3014664, 458753, 5, 3080200, 458753, 5, 3145736, 327681, 5, 3211272, 458753, 5, 3276808, 65537, 2, 2686985, 393217, 5, 2752521, 327681, 5, 2818057, 262145, 5, 2883593, 458753, 5, 2949129, 327681, 5, 3014665, 327681, 5, 3080201, 458753, 5, 3145737, 196609, 2, 3211273, 393217, 5, 3276809, 262145, 5, 2686986, 393217, 5, 2752522, 262145, 5, 2818058, 262145, 5, 2883594, 458753, 5, 2949130, 262145, 5, 3014666, 65537, 2, 3080202, 393217, 5, 3145738, 393217, 5, 3211274, 262145, 5, 3276810, 458753, 5, 2686987, 262145, 5, 2752523, 458753, 5, 2818059, 458753, 5, 2883595, 393217, 5, 2949131, 458753, 5, 3014667, 65537, 2, 3080203, 262145, 5, 3145739, 458753, 5, 3211275, 327681, 5, 3276811, 327681, 5, 2686988, 393217, 5, 2752524, 262145, 5, 2818060, 327681, 5, 2883596, 458753, 5, 2949132, 327681, 5, 3014668, 262145, 5, 3080204, 262145, 5, 3145740, 262145, 5, 3211276, 393217, 5, 3276812, 393217, 5, 2686989, 458753, 5, 2752525, 458753, 5, 2818061, 393217, 5, 2883597, 131073, 2, 2949133, 458753, 5, 3014669, 458753, 5, 3080205, 327681, 5, 3145741, 458753, 5, 3211277, 393217, 5, 3276813, 458753, 5, 2686990, 65537, 2, 2752526, 393217, 5, 2818062, 393217, 5, 2883598, 327681, 5, 2949134, 458753, 5, 3014670, 327681, 5, 3080206, 458753, 5, 3145742, 393217, 5, 3211278, 1, 2, 3276814, 262145, 5, 2686991, 262145, 5, 2752527, 327681, 5, 2818063, 262145, 5, 2883599, 393217, 5, 2949135, 131073, 2, 3014671, 196609, 2, 3080207, 262145, 5, 3145743, 458753, 5, 3211279, 262145, 5, 3276815, 327681, 5, 2686992, 393217, 5, 2752528, 262145, 5, 2818064, 262145, 5, 2883600, 327681, 5, 2949136, 458753, 5, 3014672, 262145, 5, 3080208, 131073, 2, 3145744, 458753, 5, 3211280, 458753, 5, 3276816, 393217, 5, 2686993, 327681, 5, 2752529, 262145, 5, 2818065, 327681, 5, 2883601, 327681, 5, 2949137, 458753, 5, 3014673, 458753, 5, 3080209, 1, 2, 3145745, 262145, 5, 3211281, 393217, 5, 3276817, 393217, 5, 2686994, 196609, 2, 2752530, 393217, 5, 2818066, 65537, 2, 2883602, 327681, 5, 2949138, 458753, 5, 3014674, 327681, 5, 3080210, 458753, 5, 3145746, 393217, 5, 3211282, 393217, 5, 3276818, 262145, 5, 2686995, 393217, 5, 2752531, 393217, 5, 2818067, 458753, 5, 2883603, 1, 2, 2949139, 393217, 5, 3014675, 327681, 5, 3080211, 262145, 5, 3145747, 327681, 5, 3211283, 393217, 5, 3276819, 327681, 5, 2686996, 262145, 4, 2752532, 393217, 5, 2818068, 393217, 5, 2883604, 458753, 2, 2949140, 393217, 5, 3014676, 327681, 5, 3080212, 327681, 5, 3145748, 393217, 5, 3211284, 327681, 5, 3276820, 458753, 5, 2686997, 327681, 5, 2752533, 327681, 5, 2818069, 458753, 5, 2883605, 327681, 5, 2949141, 393217, 5, 3014677, 393217, 5, 3080213, 327681, 5, 3145749, 262145, 4, 3211285, 262145, 5, 3276821, 262145, 5, 3080214, 393217, 5, 3145750, 327681, 5, 3211286, 327681, 5, 3276822, 458753, 5, 3211287, 393217, 5, 3276823, 262145, 5, 3080185, 458753, 5, 3145721, 458753, 5, 3211257, 327681, 5, 3276793, 458753, 5, 3342329, 458753, 5, 3080186, 262145, 5, 3145722, 458753, 5, 3211258, 393217, 5, 3276794, 393217, 5, 3342330, 65537, 2, 3080187, 327681, 5, 3145723, 393217, 5, 3211259, 393217, 5, 3276795, 262145, 5, 3342331, 327681, 5, 3080188, 393217, 5, 3145724, 262145, 2, 3211260, 393217, 5, 3276796, 262145, 5, 3342332, 458753, 5, 3080189, 458753, 2, 3145725, 262145, 5, 3211261, 262145, 5, 3276797, 458753, 5, 3342333, 458753, 5, 3080190, 458753, 5, 3145726, 262145, 5, 3211262, 458753, 5, 3276798, 262145, 5, 3342334, 262145, 5, 3080191, 393217, 5, 3145727, 327681, 5, 3211263, 393217, 5, 3276799, 393217, 5, 3342335, 262145, 5, 3014656, 1, 2, 3080192, 393217, 5, 3145728, 458753, 5, 3211264, 327681, 5, 3276800, 327681, 5, 3014657, 393217, 5, 3080193, 458753, 5, 3145729, 1, 2, 3211265, 458753, 5, 3276801, 393217, 5, 2686978, 262145, 5, 2752514, 262145, 5, 2818050, 458753, 5, 2883586, 262145, 5, 2949122, 327681, 5, 3014658, 393217, 5, 3080194, 262145, 5, 3145730, 131073, 2, 3211266, 458753, 5, 3276802, 262145, 5, 2686979, 327681, 5, 2752515, 458753, 5, 2818051, 327681, 5, 2883587, 262145, 5, 2949123, 393217, 5, 3014659, 327681, 5, 3080195, 327681, 5, 3145731, 262145, 5, 3211267, 1, 2, 3276803, 327681, 5, 2621461, 131073, 2, 3342357, 327681, 5, 3407893, 1, 2, 3473429, 327681, 5, 3538965, 393217, 5, 3604501, 262145, 5, 3670037, 393217, 5, 3735573, 262145, 5, 3801109, 262145, 5, 3866645, 262145, 5, 3932181, 1, 2, 3997717, 393217, 5, 4063253, 327681, 5, 4128789, 1, 2, 4194325, 458753, 2, 3342358, 393217, 5, 3407894, 458753, 5, 3473430, 327681, 5, 3538966, 262145, 5, 3604502, 196609, 2, 3670038, 393217, 5, 3735574, 327681, 5, 3801110, 458753, 5, 3866646, 262145, 5, 3932182, 1, 2, 3997718, 131073, 2, 4063254, 327681, 5, 4128790, 327681, 4, 4194326, 262145, 4, 3342359, 458753, 5, 3407895, 393217, 5, 3473431, 131073, 2, 3538967, 458753, 5, 3604503, 327681, 5, 3670039, 131073, 2, 3735575, 458753, 5, 3801111, 393217, 5, 3866647, 458753, 5, 3932183, 327681, 5, 3997719, 196609, 2, 4063255, 458753, 5, 4128791, 327681, 4, 4194327, 262145, 5, 3342360, 458753, 5, 3407896, 458753, 5, 3473432, 393217, 5, 3538968, 458753, 5, 3604504, 458753, 5, 3670040, 262145, 5, 3735576, 327681, 5, 3801112, 262145, 5, 3866648, 458753, 5, 3932184, 458753, 5, 3997720, 393217, 5, 4063256, 196609, 2, 4128792, 262145, 4, 4194328, 327681, 4, 3342361, 327681, 5, 3407897, 393217, 5, 3473433, 458753, 5, 3538969, 458753, 5, 3604505, 327681, 5, 3670041, 458753, 5, 3735577, 393217, 5, 3801113, 131073, 2, 3866649, 393217, 5, 3932185, 393217, 5, 3997721, 327681, 5, 4063257, 262145, 5, 4128793, 65537, 2, 4194329, 327681, 5, 4259861, 196609, 2, 4325397, 458753, 2, 4259862, 327681, 5, 4325398, 393217, 5, 4259863, 327681, 5, 4325399, 262145, 4, 4259864, 262145, 5, 4325400, 262145, 4, 4259865, 262145, 4, 4325401, 327681, 4, 4128776, 458753, 5, 4194312, 131073, 2, 4259848, 327681, 5, 4325384, 393217, 5, 4128777, 262145, 5, 4194313, 458753, 5, 4259849, 393217, 5, 4325385, 393217, 5, 4128778, 262145, 5, 4194314, 262145, 5, 4259850, 327681, 5, 4325386, 262145, 5, 4128779, 327681, 5, 4194315, 393217, 5, 4259851, 458753, 5, 4325387, 458753, 5, 4128780, 262145, 5, 4194316, 262145, 5, 4259852, 327681, 5, 4325388, 393217, 5, 4128781, 262145, 5, 4194317, 393217, 5, 4259853, 262145, 5, 4325389, 458753, 5, 4128782, 393217, 5, 4194318, 262145, 5, 4259854, 196609, 2, 4325390, 458753, 5, 4128783, 458753, 5, 4194319, 327681, 5, 4259855, 327681, 5, 4325391, 262145, 5, 4128784, 262145, 5, 4194320, 262145, 5, 4259856, 327681, 5, 4325392, 393217, 5, 4128785, 65537, 2, 4194321, 393217, 5, 4259857, 327681, 5, 4325393, 196609, 2, 4128786, 262145, 5, 4194322, 327681, 5, 4259858, 262145, 5, 4325394, 262145, 5, 4128787, 262145, 5, 4194323, 327681, 5, 4259859, 327681, 5, 4325395, 458753, 5, 4128788, 262145, 5, 4194324, 458753, 5, 4259860, 262145, 5, 4325396, 458753, 5, 4390920, 327681, 5, 4456456, 262145, 5, 4521992, 196609, 2, 4587528, 458753, 5, 4653064, 327681, 5, 4718600, 458753, 5, 4784136, 131073, 2, 4849672, 393217, 5, 4915208, 327681, 5, 4980744, 262145, 5, 5046280, 393217, 5, 5111816, 458753, 5, 5177352, 327681, 5, 4390921, 458753, 5, 4456457, 327681, 5, 4521993, 458753, 5, 4587529, 327681, 5, 4653065, 327681, 5, 4718601, 65537, 2, 4784137, 458753, 5, 4849673, 327681, 5, 4915209, 327681, 5, 4980745, 393217, 5, 5046281, 458753, 5, 5111817, 327681, 5, 5177353, 262145, 5, 4390922, 458753, 5, 4456458, 196609, 2, 4521994, 262145, 5, 4587530, 327681, 5, 4653066, 65537, 2, 4718602, 262145, 5, 4784138, 458753, 5, 4849674, 393217, 5, 4915210, 393217, 5, 4980746, 131073, 2, 5046282, 458753, 5, 5111818, 262145, 5, 5177354, 393217, 5, 4390923, 196609, 2, 4456459, 393217, 5, 4521995, 458753, 5, 4587531, 327681, 5, 4653067, 393217, 5, 4718603, 458753, 5, 4784139, 327681, 5, 4849675, 262145, 5, 4915211, 262145, 5, 4980747, 458753, 5, 5046283, 458753, 5, 5111819, 327681, 5, 5177355, 327681, 5, 4128769, 131073, 2, 4194305, 458753, 5, 4259841, 262145, 5, 4325377, 327681, 5, 4390913, 393217, 5, 4456449, 1, 2, 4521985, 393217, 5, 4587521, 262145, 5, 4653057, 458753, 5, 4718593, 327681, 5, 4784129, 393217, 5, 4849665, 262145, 5, 4915201, 393217, 5, 4980737, 327681, 5, 5046273, 327681, 5, 5111809, 262145, 5, 5177345, 393217, 5, 4128770, 458753, 5, 4194306, 327681, 5, 4259842, 262145, 5, 4325378, 458753, 5, 4390914, 262145, 5, 4456450, 262145, 5, 4521986, 262145, 5, 4587522, 393217, 5, 4653058, 458753, 5, 4718594, 458753, 5, 4784130, 1, 2, 4849666, 262145, 5, 4915202, 262145, 5, 4980738, 262145, 5, 5046274, 262145, 5, 5111810, 458753, 5, 5177346, 327681, 5, 4128771, 262145, 5, 4194307, 262145, 5, 4259843, 458753, 5, 4325379, 327681, 5, 4390915, 327681, 5, 4456451, 393217, 5, 4521987, 458753, 5, 4587523, 327681, 5, 4653059, 393217, 5, 4718595, 458753, 5, 4784131, 393217, 5, 4849667, 393217, 5, 4915203, 327681, 5, 4980739, 327681, 5, 5046275, 262145, 5, 5111811, 262145, 5, 5177347, 262145, 5, 4128768, 458753, 5, 4194304, 327681, 5, 4259840, 196609, 2, 4325376, 393217, 5, 4390912, 458753, 5, 4456448, 262145, 5, 4521984, 262145, 5, 4587520, 458753, 5, 4653056, 393217, 5, 4718592, 458753, 5, 4784128, 262145, 5, 4849664, 458753, 5, 4915200, 458753, 5, 4980736, 458753, 5, 5046272, 327681, 5, 5111808, 393217, 5, 5177344, 327681, 5, 4194289, 327681, 5, 4259825, 327681, 5, 4325361, 393217, 5, 4194290, 262145, 5, 4259826, 393217, 5, 4325362, 458753, 5, 4194291, 393217, 5, 4259827, 458753, 5, 4325363, 327681, 5, 4194292, 393217, 5, 4259828, 262145, 5, 4325364, 262145, 4, 4194293, 262145, 5, 4259829, 1, 1, 4325365, 1, 4, 4194294, 458753, 2, 4259830, 327681, 6, 4325366, 327681, 6, 4194295, 327681, 5, 4259831, 65537, 0, 4325367, 65537, 4, 4194296, 458753, 5, 4259832, 458753, 5, 4325368, 327681, 5, 4194297, 262145, 5, 4259833, 458753, 5, 4325369, 262145, 5, 4194298, 458753, 5, 4259834, 262145, 5, 4325370, 262145, 5, 4194299, 327681, 5, 4259835, 458753, 5, 4325371, 458753, 5, 4194300, 393217, 5, 4259836, 327681, 5, 4325372, 458753, 5, 4194301, 1, 2, 4259837, 327681, 5, 4325373, 262145, 5, 4194302, 393217, 5, 4259838, 393217, 5, 4325374, 327681, 5, 4194303, 262145, 5, 4259839, 393217, 5, 4325375, 458753, 5, 4390897, 458753, 5, 4390898, 393217, 5, 4390899, 458753, 5, 4390900, 458753, 2, 4390901, 393217, 5, 4390902, 262145, 5, 4390903, 458753, 2, 4390904, 327681, 5, 4390905, 458753, 5, 4390906, 458753, 5, 4390907, 458753, 5, 4390908, 262145, 5, 4390909, 262145, 5, 4390910, 327681, 5, 4390911, 327681, 5, 3473393, 327681, 4, 3538929, 327681, 5, 3604465, 393217, 5, 3670001, 65537, 2, 3735537, 393217, 5, 3801073, 458753, 5, 3866609, 327681, 5, 3932145, 458753, 5, 3997681, 458753, 5, 4063217, 458753, 5, 4128753, 327681, 5, 3211250, 327681, 4, 3276786, 458753, 5, 3342322, 327681, 5, 3407858, 393217, 5, 3473394, 458753, 4, 3538930, 262145, 4, 3604466, 458753, 5, 3670002, 393217, 5, 3735538, 327681, 5, 3801074, 327681, 5, 3866610, 262145, 5, 3932146, 393217, 5, 3997682, 327681, 5, 4063218, 262145, 5, 4128754, 262145, 5, 3211251, 393217, 5, 3276787, 327681, 5, 3342323, 262145, 4, 3407859, 393217, 2, 3473395, 393217, 5, 3538931, 393217, 5, 3604467, 393217, 5, 3670003, 458753, 5, 3735539, 262145, 5, 3801075, 393217, 5, 3866611, 327681, 5, 3932147, 458753, 5, 3997683, 458753, 5, 4063219, 327681, 5, 4128755, 393217, 5, 3211252, 458753, 5, 3276788, 327681, 5, 3342324, 393217, 5, 3407860, 327681, 5, 3473396, 393217, 5, 3538932, 65537, 2, 3604468, 327681, 5, 3670004, 327681, 5, 3735540, 393217, 5, 3801076, 393217, 5, 3866612, 1, 2, 3932148, 262145, 5, 3997684, 262145, 5, 4063220, 262145, 5, 4128756, 458753, 2, 3211253, 262145, 5, 3276789, 327681, 5, 3342325, 458753, 5, 3407861, 1, 2, 3473397, 327681, 5, 3538933, 393217, 5, 3604469, 393217, 5, 3670005, 327681, 5, 3735541, 458753, 5, 3801077, 327681, 5, 3866613, 262145, 5, 3932149, 262145, 5, 3997685, 458753, 2, 4063221, 458753, 5, 4128757, 327681, 4, 3080182, 458753, 5, 3145718, 262145, 5, 3211254, 458753, 5, 3276790, 262145, 5, 3342326, 327681, 5, 3407862, 393217, 5, 3473398, 393217, 5, 3538934, 327681, 5, 3604470, 1, 2, 3670006, 393217, 5, 3735542, 458753, 5, 3801078, 262145, 5, 3866614, 327681, 5, 3932150, 262145, 5, 3997686, 458753, 5, 4063222, 458753, 5, 4128758, 262145, 5, 3080183, 458753, 5, 3145719, 458753, 5, 3211255, 262145, 5, 3276791, 393217, 5, 3342327, 458753, 5, 3407863, 393217, 5, 3473399, 262145, 5, 3538935, 458753, 5, 3604471, 458753, 5, 3670007, 262145, 5, 3735543, 393217, 5, 3801079, 327681, 5, 3866615, 262145, 5, 3932151, 393217, 5, 3997687, 393217, 5, 4063223, 458753, 5, 4128759, 393217, 5, 3080184, 458753, 2, 3145720, 262145, 5, 3211256, 327681, 5, 3276792, 327681, 5, 3342328, 458753, 5, 3473383, 458753, 5, 3538919, 458753, 5, 3604455, 458753, 5, 3669991, 458753, 5, 3735527, 458753, 5, 3801063, 393217, 5, 3866599, 262145, 5, 3932135, 458753, 5, 3997671, 327681, 5, 4063207, 458753, 5, 4128743, 393217, 5, 4194279, 327681, 5, 4259815, 327681, 5, 4325351, 458753, 5, 4390887, 262145, 5, 3473384, 327681, 5, 3538920, 393217, 5, 3604456, 458753, 4, 3669992, 262145, 5, 3735528, 327681, 5, 3801064, 262145, 5, 3866600, 327681, 5, 3932136, 327681, 5, 3997672, 327681, 5, 4063208, 65537, 2, 4128744, 458753, 5, 4194280, 262145, 4, 4259816, 458753, 2, 4325352, 393217, 5, 4390888, 458753, 5, 3473385, 327681, 5, 3538921, 458753, 5, 3604457, 458753, 4, 3669993, 327681, 5, 3735529, 327681, 5, 3801065, 458753, 5, 3866601, 327681, 5, 3932137, 327681, 5, 3997673, 262145, 5, 4063209, 262145, 5, 4128745, 327681, 5, 4194281, 262145, 5, 4259817, 393217, 5, 4325353, 327681, 4, 4390889, 458753, 4, 3473386, 458753, 5, 3538922, 327681, 5, 3604458, 393217, 5, 3669994, 458753, 5, 3735530, 262145, 5, 3801066, 393217, 5, 3866602, 262145, 5, 3932138, 458753, 5, 3997674, 327681, 5, 4063210, 65537, 2, 4128746, 327681, 5, 4194282, 458753, 5, 4259818, 327681, 5, 4325354, 327681, 4, 4390890, 1, 2, 3473387, 458753, 5, 3538923, 327681, 5, 3604459, 262145, 5, 3669995, 131073, 2, 3735531, 458753, 5, 3801067, 393217, 5, 3866603, 393217, 5, 3932139, 327681, 5, 3997675, 327681, 5, 4063211, 458753, 5, 4128747, 458753, 5, 4194283, 458753, 5, 4259819, 393217, 5, 4325355, 458753, 4, 4390891, 458753, 5, 3473388, 393217, 5, 3538924, 327681, 5, 3604460, 262145, 5, 3669996, 327681, 5, 3735532, 458753, 5, 3801068, 458753, 5, 3866604, 327681, 5, 3932140, 458753, 2, 3997676, 262145, 5, 4063212, 262145, 5, 4128748, 393217, 5, 4194284, 65537, 2, 4259820, 458753, 5, 4325356, 262145, 4, 4390892, 393217, 5, 3473389, 393217, 5, 3538925, 458753, 5, 3604461, 196609, 2, 3669997, 262145, 4, 3735533, 458753, 2, 3801069, 131073, 2, 3866605, 393217, 5, 3932141, 327681, 5, 3997677, 327681, 5, 4063213, 393217, 5, 4128749, 393217, 5, 4194285, 458753, 5, 4259821, 393217, 5, 4325357, 458753, 5, 4390893, 393217, 5, 3473390, 327681, 4, 3538926, 327681, 4, 3604462, 327681, 5, 3669998, 327681, 5, 3735534, 262145, 5, 3801070, 458753, 5, 3866606, 458753, 5, 3932142, 327681, 5, 3997678, 262145, 5, 4063214, 262145, 5, 4128750, 65537, 2, 4194286, 393217, 5, 4259822, 393217, 5, 4325358, 393217, 5, 4390894, 327681, 5, 3473391, 393217, 5, 3538927, 327681, 5, 3604463, 393217, 4, 3669999, 393217, 5, 3735535, 262145, 5, 3801071, 1, 2, 3866607, 262145, 5, 3932143, 262145, 5, 3997679, 458753, 5, 4063215, 65537, 2, 4128751, 327681, 5, 4194287, 65537, 2, 4259823, 262145, 5, 4325359, 393217, 5, 4390895, 393217, 5, 3473392, 327681, 5, 3538928, 393217, 5, 3604464, 262145, 5, 3670000, 262145, 5, 3735536, 458753, 5, 3801072, 393217, 5, 3866608, 458753, 5, 3932144, 327681, 5, 3997680, 458753, 5, 4063216, 262145, 5, 4128752, 262145, 5, 4194288, 393217, 5, 4259824, 393217, 5, 4325360, 262145, 5, 4390896, 65537, 2, 4718609, 327681, 5, 4784145, 393217, 5, 4849681, 1, 2, 4915217, 262145, 5, 4980753, 262145, 5, 5046289, 393217, 5, 5111825, 458753, 5, 5177361, 262145, 5, 5242897, 458753, 5, 5308433, 327681, 4, 4718608, 327681, 5, 4784144, 393217, 5, 4849680, 327681, 5, 4915216, 262145, 5, 4980752, 327681, 5, 5046288, 393217, 5, 5111824, 327681, 5, 5177360, 131073, 2, 5242896, 393217, 5, 5308432, 458753, 5, 4718610, 262145, 5, 4784146, 458753, 5, 4849682, 458753, 5, 4915218, 262145, 5, 4980754, 327681, 5, 5046290, 393217, 5, 5111826, 65537, 2, 5177362, 262145, 5, 5242898, 393217, 5, 5308434, 393217, 4, 5373970, 327681, 5, 5439506, 458753, 2, 4718611, 65537, 2, 4784147, 458753, 5, 4849683, 458753, 5, 4915219, 262145, 5, 4980755, 262145, 5, 5046291, 458753, 5, 5111827, 327681, 5, 5177363, 458753, 5, 5242899, 393217, 5, 5308435, 327681, 5, 5373971, 262145, 5, 5439507, 458753, 5, 4653072, 327681, 5, 4653073, 458753, 5, 4653074, 458753, 5, 4653075, 262145, 5, 5373968, 262145, 5, 5439504, 458753, 4, 5505040, 327681, 5, 5570576, 327681, 5, 5636112, 1, 2, 5701648, 262145, 5, 5767184, 458753, 5, 5832720, 393217, 5, 5898256, 458753, 5, 5963792, 393217, 5, 5373969, 393217, 5, 5439505, 393217, 5, 5505041, 262145, 4, 5570577, 458753, 5, 5636113, 458753, 2, 5701649, 327681, 2, 5767185, 327681, 5, 5832721, 131073, 2, 5898257, 327681, 5, 5963793, 327681, 5, 5505042, 458753, 5, 5570578, 458753, 2, 5636114, 393217, 5, 5701650, 327681, 5, 5767186, 327681, 5, 5832722, 262145, 5, 5898258, 327681, 5, 5963794, 393217, 5, 5505043, 393217, 5, 5570579, 327681, 5, 5636115, 393217, 5, 5701651, 327681, 4, 5767187, 262145, 5, 5832723, 458753, 5, 5898259, 458753, 5, 5963795, 393217, 5, 6029328, 393217, 5, 6094864, 262145, 5, 6160400, 458753, 5, 6225936, 458753, 5, 6291472, 327681, 5, 6357008, 327681, 5, 6422544, 393217, 5, 6488080, 458753, 5, 6553616, 262145, 5, 6619152, 458753, 5, 6684688, 458753, 5, 6750224, 458753, 5, 6815760, 393217, 5, 6029329, 458753, 5, 6094865, 196609, 2, 6160401, 458753, 5, 6225937, 262145, 5, 6291473, 327681, 5, 6357009, 327681, 5, 6422545, 393217, 5, 6488081, 131073, 2, 6553617, 393217, 5, 6619153, 458753, 5, 6684689, 262145, 5, 6750225, 458753, 5, 6815761, 458753, 5, 6029330, 327681, 5, 6094866, 327681, 5, 6160402, 458753, 5, 6225938, 262145, 5, 6291474, 65537, 2, 6357010, 262145, 5, 6422546, 458753, 5, 6488082, 327681, 5, 6553618, 327681, 5, 6619154, 262145, 5, 6684690, 458753, 5, 6750226, 393217, 5, 6815762, 458753, 5, 6029331, 327681, 5, 6094867, 458753, 5, 6160403, 196609, 2, 6225939, 393217, 5, 6291475, 458753, 5, 6357011, 262145, 5, 6422547, 262145, 5, 6488083, 393217, 5, 6553619, 327681, 5, 6619155, 393217, 5, 6684691, 458753, 5, 6750227, 393217, 5, 6815763, 327681, 5, 4390936, 327681, 5, 4456472, 458753, 5, 4522008, 458753, 5, 4587544, 327681, 5, 4653080, 458753, 5, 4718616, 458753, 5, 4784152, 393217, 5, 4849688, 262145, 5, 4915224, 458753, 5, 4980760, 327681, 5, 5046296, 262145, 5, 5111832, 458753, 5, 5177368, 458753, 5, 5242904, 262145, 5, 5308440, 393217, 5, 5373976, 327681, 5, 5439512, 393217, 5, 5505048, 327681, 5, 5570584, 393217, 5, 5636120, 393217, 5, 5701656, 327681, 5, 5767192, 393217, 5, 5832728, 327681, 5, 5898264, 327681, 5, 5963800, 262145, 5, 6029336, 262145, 5, 6094872, 458753, 5, 6160408, 131073, 2, 6225944, 458753, 5, 6291480, 327681, 5, 6357016, 393217, 5, 6422552, 458753, 5, 6488088, 327681, 5, 6553624, 393217, 5, 6619160, 131073, 2, 6684696, 458753, 5, 6750232, 458753, 5, 6815768, 262145, 5, 4390937, 458753, 5, 4456473, 458753, 5, 4522009, 327681, 4, 4587545, 262145, 5, 4653081, 262145, 5, 4718617, 458753, 5, 4784153, 262145, 4, 4849689, 458753, 4, 4915225, 458753, 4, 4980761, 327681, 5, 5046297, 393217, 5, 5111833, 262145, 5, 5177369, 393217, 5, 5242905, 262145, 5, 5308441, 458753, 4, 5373977, 327681, 5, 5439513, 327681, 5, 5505049, 327681, 5, 5570585, 458753, 5, 5636121, 262145, 5, 5701657, 1, 2, 5767193, 458753, 5, 5832729, 393217, 5, 5898265, 262145, 5, 5963801, 393217, 5, 6029337, 262145, 5, 6094873, 458753, 5, 6160409, 393217, 5, 6225945, 196609, 2, 6291481, 393217, 5, 6357017, 458753, 5, 6422553, 458753, 5, 6488089, 327681, 5, 6553625, 262145, 5, 6619161, 262145, 5, 6684697, 327681, 5, 6750233, 262145, 5, 4390938, 65537, 2, 4456474, 131073, 2, 4522010, 262145, 4, 4587546, 262145, 5, 4653082, 393217, 5, 4718618, 458753, 5, 4784154, 262145, 5, 4849690, 458753, 5, 4915226, 262145, 2, 4980762, 458753, 5, 5046298, 1, 2, 5111834, 327681, 5, 5177370, 262145, 5, 5242906, 458753, 5, 5308442, 458753, 5, 5373978, 393217, 5, 5439514, 393217, 5, 5505050, 327681, 5, 5570586, 65537, 2, 5636122, 262145, 5, 5701658, 262145, 5, 5767194, 262145, 5, 5832730, 327681, 5, 5898266, 262145, 5, 5963802, 393217, 5, 6029338, 458753, 5, 6094874, 393217, 5, 6160410, 262145, 5, 6225946, 262145, 5, 6291482, 262145, 5, 6357018, 458753, 5, 6422554, 458753, 5, 6488090, 393217, 5, 6553626, 458753, 5, 6619162, 262145, 5, 6684698, 262145, 5, 4390939, 1, 2, 4456475, 458753, 5, 4522011, 327681, 5, 4587547, 262145, 4, 4653083, 327681, 4, 4718619, 262145, 5, 4784155, 393217, 5, 4849691, 131073, 2, 4915227, 1, 2, 4980763, 458753, 5, 5046299, 458753, 5, 5111835, 393217, 5, 5177371, 458753, 5, 5242907, 262145, 5, 5308443, 458753, 5, 5373979, 262145, 5, 5439515, 458753, 5, 5505051, 196609, 2, 5570587, 262145, 5, 5636123, 327681, 5, 5701659, 458753, 5, 5767195, 327681, 5, 5832731, 262145, 5, 5898267, 393217, 5, 5963803, 327681, 5, 6029339, 327681, 5, 6094875, 327681, 5, 6160411, 458753, 5, 6225947, 393217, 5, 6291483, 393217, 5, 6357019, 458753, 5, 6422555, 262145, 5, 6488091, 458753, 5, 6553627, 327681, 5, 6619163, 393217, 5, 4390940, 393217, 5, 4456476, 458753, 5, 4522012, 458753, 5, 4587548, 458753, 5, 4653084, 458753, 2, 4718620, 327681, 5, 4784156, 327681, 5, 4849692, 327681, 5, 4915228, 393217, 5, 4980764, 393217, 5, 5046300, 393217, 5, 5111836, 262145, 5, 5177372, 393217, 5, 5242908, 458753, 5, 5308444, 393217, 5, 5373980, 327681, 5, 5439516, 393217, 5, 5505052, 262145, 5, 5570588, 393217, 5, 5636124, 327681, 5, 5701660, 262145, 5, 5767196, 327681, 5, 5832732, 327681, 5, 5898268, 458753, 5, 5963804, 327681, 5, 6029340, 327681, 5, 6094876, 262145, 5, 6160412, 262145, 5, 6225948, 262145, 5, 6291484, 262145, 5, 6357020, 262145, 5, 6422556, 393217, 5, 6488092, 262145, 5, 6553628, 393217, 5, 4390941, 262145, 5, 4456477, 262145, 5, 4522013, 262145, 5, 4587549, 262145, 5, 4653085, 327681, 5, 4718621, 262145, 5, 4784157, 262145, 5, 4849693, 458753, 5, 4915229, 393217, 5, 4980765, 262145, 5, 5046301, 458753, 5, 5111837, 393217, 5, 5177373, 393217, 5, 5242909, 458753, 5, 5308445, 393217, 5, 5373981, 262145, 5, 5439517, 458753, 5, 5505053, 262145, 5, 5570589, 262145, 5, 5636125, 262145, 5, 5701661, 327681, 5, 5767197, 393217, 5, 5832733, 262145, 5, 5898269, 458753, 5, 5963805, 458753, 5, 6029341, 327681, 5, 6094877, 327681, 5, 6160413, 327681, 5, 6225949, 393217, 5, 6291485, 458753, 5, 6357021, 393217, 5, 6422557, 393217, 5, 6488093, 393217, 5, 3211288, 65537, 2, 3276824, 327681, 5, 3211289, 262145, 5, 3276825, 262145, 5, 3211290, 262145, 5, 3276826, 393217, 5, 3342362, 327681, 5, 3407898, 458753, 5, 3473434, 65537, 2, 3538970, 327681, 5, 3604506, 262145, 5, 3670042, 393217, 5, 3735578, 393217, 5, 3801114, 262145, 5, 3866650, 393217, 5, 3932186, 262145, 5, 3997722, 262145, 5, 4063258, 65537, 2, 4128794, 327681, 5, 4194330, 327681, 5, 4259866, 393217, 2, 4325402, 262145, 5, 3211291, 458753, 5, 3276827, 262145, 5, 3342363, 458753, 5, 3407899, 327681, 5, 3473435, 393217, 5, 3538971, 393217, 5, 3604507, 458753, 5, 3670043, 262145, 5, 3735579, 327681, 5, 3801115, 262145, 5, 3866651, 393217, 5, 3932187, 262145, 5, 3997723, 262145, 5, 4063259, 262145, 5, 4128795, 262145, 5, 4194331, 458753, 5, 4259867, 393217, 5, 4325403, 1, 2, 3211292, 327681, 5, 3276828, 393217, 5, 3342364, 327681, 5, 3407900, 327681, 5, 3473436, 458753, 5, 3538972, 327681, 5, 3604508, 262145, 5, 3670044, 262145, 5, 3735580, 458753, 5, 3801116, 262145, 5, 3866652, 262145, 5, 3932188, 262145, 5, 3997724, 458753, 2, 4063260, 327681, 5, 4128796, 327681, 5, 4194332, 458753, 5, 4259868, 262145, 5, 4325404, 262145, 5, 3145757, 327681, 4, 3211293, 458753, 5, 3276829, 262145, 5, 3342365, 327681, 4, 3407901, 393217, 5, 3473437, 458753, 5, 3538973, 327681, 5, 3604509, 262145, 5, 3670045, 458753, 5, 3735581, 393217, 5, 3801117, 458753, 5, 3866653, 327681, 4, 3932189, 393217, 5, 3997725, 458753, 5, 4063261, 327681, 5, 4128797, 262145, 5, 4194333, 327681, 4, 4259869, 262145, 5, 4325405, 393217, 5, 3145758, 327681, 5, 3211294, 262145, 5, 3276830, 327681, 5, 3342366, 393217, 5, 3407902, 262145, 5, 3473438, 458753, 5, 3538974, 262145, 5, 3604510, 458753, 2, 3670046, 458753, 5, 3735582, 262145, 5, 3801118, 1, 6, 3866654, 65537, 6, 3932190, 262145, 6, 3997726, 262145, 6, 4063262, 65537, 2, 4128798, 393217, 5, 4194334, 327681, 4, 4259870, 327681, 2, 4325406, 393217, 5, 5570552, 458753, 2, 5636088, 262145, 5, 5701624, 458753, 5, 5767160, 458753, 5, 5832696, 196609, 2, 5898232, 458753, 5, 5963768, 393217, 5, 6029304, 262145, 5, 6094840, 262145, 5, 6160376, 327681, 5, 6225912, 262145, 5, 6291448, 262145, 5, 6356984, 458753, 5, 6422520, 458753, 5, 6488056, 458753, 5, 6553592, 262145, 5, 6619128, 1, 2, 6684664, 327681, 5, 5570553, 458753, 2, 5636089, 262145, 4, 5701625, 327681, 5, 5767161, 262145, 5, 5832697, 393217, 5, 5898233, 458753, 5, 5963769, 458753, 5, 6029305, 393217, 5, 6094841, 458753, 5, 6160377, 327681, 5, 6225913, 393217, 5, 6291449, 458753, 5, 6356985, 393217, 5, 6422521, 393217, 5, 6488057, 458753, 5, 6553593, 262145, 5, 6619129, 262145, 5, 6684665, 327681, 5, 6750201, 458753, 5, 5570554, 327681, 4, 5636090, 1, 2, 5701626, 393217, 5, 5767162, 393217, 5, 5832698, 327681, 4, 5898234, 458753, 5, 5963770, 458753, 5, 6029306, 327681, 5, 6094842, 458753, 5, 6160378, 262145, 5, 6225914, 262145, 5, 6291450, 393217, 5, 6356986, 262145, 5, 6422522, 458753, 5, 6488058, 327681, 5, 6553594, 262145, 5, 6619130, 196609, 2, 6684666, 393217, 5, 6750202, 131073, 2, 6815738, 393217, 5, 6881274, 393217, 5, 5570555, 131073, 2, 5636091, 327681, 5, 5701627, 131073, 2, 5767163, 262145, 5, 5832699, 327681, 4, 5898235, 262145, 5, 5963771, 262145, 5, 6029307, 393217, 5, 6094843, 458753, 5, 6160379, 327681, 5, 6225915, 131073, 2, 6291451, 262145, 5, 6356987, 327681, 5, 6422523, 327681, 5, 6488059, 458753, 5, 6553595, 327681, 5, 6619131, 327681, 5, 6684667, 458753, 5, 6750203, 458753, 5, 6815739, 458753, 5, 6881275, 262145, 5, 5570556, 458753, 4, 5636092, 262145, 5, 5701628, 262145, 5, 5767164, 393217, 5, 5832700, 458753, 5, 5898236, 327681, 4, 5963772, 458753, 4, 6029308, 327681, 5, 6094844, 458753, 5, 6160380, 393217, 5, 6225916, 393217, 5, 6291452, 393217, 5, 6356988, 393217, 5, 6422524, 327681, 5, 6488060, 262145, 5, 6553596, 262145, 5, 6619132, 393217, 5, 6684668, 458753, 5, 6750204, 458753, 5, 6815740, 393217, 5, 6881276, 393217, 5, 5570557, 262145, 5, 5636093, 458753, 5, 5701629, 393217, 5, 5767165, 458753, 5, 5832701, 262145, 5, 5898237, 458753, 5, 5963773, 65537, 2, 6029309, 393217, 5, 6094845, 262145, 5, 6160381, 1, 2, 6225917, 1, 2, 6291453, 393217, 5, 6356989, 327681, 5, 6422525, 327681, 5, 6488061, 1, 2, 6553597, 327681, 5, 6619133, 393217, 5, 6684669, 458753, 5, 6750205, 458753, 5, 6815741, 393217, 5, 6881277, 327681, 5, 6946813, 327681, 5, 7012349, 393217, 5, 5570558, 393217, 5, 5636094, 1, 2, 5701630, 262145, 5, 5767166, 131073, 2, 5832702, 327681, 5, 5898238, 262145, 5, 5963774, 458753, 5, 6029310, 262145, 5, 6094846, 393217, 5, 6160382, 327681, 5, 6225918, 262145, 5, 6291454, 262145, 5, 6356990, 262145, 5, 6422526, 458753, 5, 6488062, 131073, 2, 6553598, 458753, 5, 6619134, 327681, 5, 6684670, 393217, 5, 6750206, 393217, 5, 6815742, 262145, 5, 6881278, 393217, 5, 6946814, 65537, 2, 7012350, 393217, 5, 7077886, 262145, 5, 5570559, 458753, 5, 5636095, 393217, 5, 5701631, 327681, 5, 5767167, 458753, 5, 5832703, 393217, 5, 5898239, 458753, 5, 5963775, 458753, 5, 6029311, 262145, 5, 6094847, 262145, 5, 6160383, 196609, 2, 6225919, 458753, 5, 6291455, 262145, 5, 6356991, 393217, 5, 6422527, 458753, 5, 6488063, 327681, 5, 6553599, 262145, 5, 6619135, 393217, 5, 6684671, 458753, 5, 6750207, 458753, 5, 6815743, 262145, 5, 6881279, 327681, 5, 6946815, 327681, 5, 7012351, 393217, 5, 7077887, 262145, 5, 5505024, 327681, 5, 5570560, 327681, 5, 5636096, 458753, 5, 5701632, 327681, 5, 5767168, 327681, 5, 5832704, 327681, 5, 5898240, 262145, 5, 5963776, 458753, 5, 6029312, 393217, 2, 6094848, 393217, 5, 6160384, 327681, 5, 6225920, 327681, 5, 6291456, 393217, 5, 6356992, 327681, 5, 6422528, 458753, 5, 6488064, 393217, 5, 6553600, 327681, 5, 6619136, 458753, 5, 6684672, 327681, 5, 6750208, 262145, 5, 6815744, 327681, 5, 6881280, 327681, 5, 6946816, 458753, 5, 7012352, 262145, 5, 5505025, 262145, 5, 5570561, 262145, 5, 5636097, 393217, 5, 5701633, 393217, 5, 5767169, 65537, 2, 5832705, 327681, 5, 5898241, 458753, 5, 5963777, 393217, 5, 6029313, 262145, 5, 6094849, 131073, 2, 6160385, 458753, 5, 6225921, 327681, 5, 6291457, 327681, 4, 6356993, 262145, 5, 6422529, 327681, 5, 6488065, 458753, 5, 6553601, 458753, 5, 6619137, 327681, 5, 6684673, 262145, 5, 6750209, 458753, 5, 6815745, 262145, 5, 6881281, 327681, 5, 6946817, 196609, 2, 7012353, 393217, 5, 5505026, 262145, 5, 5570562, 393217, 5, 5636098, 327681, 5, 5701634, 393217, 5, 5767170, 458753, 4, 5832706, 458753, 5, 5898242, 327681, 5, 5963778, 458753, 5, 6029314, 393217, 5, 6094850, 327681, 5, 6160386, 327681, 5, 6225922, 393217, 5, 6291458, 458753, 5, 6356994, 262145, 5, 6422530, 458753, 5, 6488066, 327681, 5, 6553602, 262145, 5, 6619138, 327681, 5, 6684674, 262145, 5, 6750210, 262145, 5, 6815746, 458753, 5, 6881282, 458753, 5, 6946818, 327681, 5, 7012354, 393217, 5, 5505027, 393217, 5, 5570563, 262145, 5, 5636099, 327681, 5, 5701635, 327681, 5, 5767171, 458753, 5, 5832707, 458753, 5, 5898243, 131073, 2, 5963779, 393217, 5, 6029315, 262145, 5, 6094851, 393217, 5, 6160387, 393217, 5, 6225923, 327681, 5, 6291459, 458753, 5, 6356995, 458753, 4, 6422531, 262145, 5, 6488067, 327681, 5, 6553603, 327681, 5, 6619139, 327681, 5, 6684675, 262145, 5, 6750211, 458753, 5, 6815747, 458753, 5, 6881283, 327681, 5, 6946819, 327681, 5, 7012355, 327681, 5, 5505028, 393217, 5, 5570564, 327681, 5, 5636100, 458753, 5, 5701636, 131073, 2, 5767172, 262145, 5, 5832708, 458753, 5, 5898244, 458753, 5, 5963780, 458753, 5, 6029316, 262145, 5, 6094852, 327681, 5, 6160388, 393217, 5, 6225924, 131073, 2, 6291460, 458753, 5, 6356996, 262145, 5, 6422532, 458753, 5, 6488068, 393217, 5, 6553604, 458753, 5, 6619140, 458753, 5, 6684676, 196609, 2, 6750212, 458753, 5, 6815748, 393217, 5, 6881284, 393217, 5, 6946820, 393217, 5, 7012356, 262145, 5, 5505029, 458753, 5, 5570565, 458753, 5, 5636101, 262145, 5, 5701637, 458753, 5, 5767173, 262145, 5, 5832709, 458753, 5, 5898245, 458753, 5, 5963781, 458753, 5, 6029317, 262145, 5, 6094853, 262145, 5, 6160389, 262145, 5, 6225925, 1, 2, 6291461, 262145, 5, 6356997, 327681, 5, 6422533, 327681, 5, 6488069, 196609, 2, 6553605, 393217, 5, 6619141, 458753, 5, 6684677, 458753, 5, 6750213, 458753, 5, 6815749, 327681, 5, 6881285, 327681, 5, 6946821, 327681, 5, 7012357, 393217, 5, 5505030, 393217, 5, 5570566, 393217, 5, 5636102, 1, 2, 5701638, 327681, 4, 5767174, 327681, 5, 5832710, 262145, 5, 5898246, 327681, 5, 5963782, 458753, 5, 6029318, 327681, 5, 6094854, 1, 2, 6160390, 262145, 5, 6225926, 393217, 5, 6291462, 393217, 5, 6356998, 1, 2, 6422534, 458753, 5, 6488070, 327681, 5, 6553606, 327681, 5, 6619142, 458753, 5, 6684678, 393217, 5, 6750214, 393217, 5, 6815750, 65537, 2, 6881286, 458753, 5, 6946822, 327681, 5, 7012358, 393217, 5, 5505031, 393217, 5, 5570567, 262145, 5, 5636103, 327681, 2, 5701639, 458753, 4, 5767175, 393217, 5, 5832711, 262145, 5, 5898247, 393217, 5, 5963783, 131073, 2, 6029319, 458753, 5, 6094855, 393217, 5, 6160391, 327681, 5, 6225927, 262145, 5, 6291463, 327681, 5, 6356999, 262145, 5, 6422535, 458753, 5, 6488071, 327681, 5, 6553607, 327681, 5, 6619143, 327681, 5, 6684679, 262145, 5, 6750215, 327681, 5, 6815751, 262145, 5, 6881287, 262145, 5, 6946823, 262145, 5, 7012359, 393217, 5, 5505032, 1, 2, 5570568, 327681, 5, 5636104, 458753, 5, 5701640, 262145, 4, 5767176, 196609, 2, 5832712, 458753, 5, 5898248, 327681, 5, 5963784, 327681, 5, 6029320, 262145, 5, 6094856, 327681, 5, 6160392, 131073, 2, 6225928, 131073, 2, 6291464, 196609, 2, 6357000, 327681, 5, 6422536, 458753, 5, 6488072, 65537, 2, 6553608, 458753, 5, 6619144, 393217, 5, 6684680, 262145, 5, 6750216, 458753, 5, 6815752, 262145, 5, 6881288, 327681, 5, 6946824, 327681, 5, 7012360, 458753, 5, 5505033, 393217, 5, 5570569, 393217, 5, 5636105, 196609, 2, 5701641, 327681, 5, 5767177, 393217, 2, 5832713, 458753, 5, 5898249, 262145, 5, 5963785, 458753, 5, 6029321, 458753, 5, 6094857, 393217, 5, 6160393, 458753, 5, 6225929, 458753, 5, 6291465, 393217, 5, 6357001, 262145, 5, 6422537, 327681, 5, 6488073, 393217, 5, 6553609, 458753, 5, 6619145, 262145, 5, 6684681, 262145, 5, 6750217, 262145, 5, 6815753, 327681, 5, 6881289, 458753, 5, 6946825, 262145, 5, 7012361, 458753, 5, 5505034, 327681, 5, 5570570, 393217, 5, 5636106, 327681, 5, 5701642, 458753, 5, 5767178, 458753, 2, 5832714, 262145, 5, 5898250, 65537, 2, 5963786, 262145, 5, 6029322, 458753, 5, 6094858, 458753, 5, 6160394, 327681, 5, 6225930, 262145, 5, 6291466, 458753, 5, 6357002, 458753, 5, 6422538, 327681, 5, 6488074, 393217, 5, 6553610, 458753, 5, 6619146, 458753, 5, 6684682, 327681, 5, 6750218, 458753, 5, 6815754, 262145, 5, 6881290, 458753, 5, 6946826, 327681, 5, 7012362, 262145, 5, 5505035, 458753, 5, 5570571, 458753, 5, 5636107, 458753, 5, 5701643, 262145, 5, 5767179, 393217, 5, 5832715, 327681, 4, 5898251, 327681, 5, 5963787, 327681, 5, 6029323, 393217, 5, 6094859, 262145, 5, 6160395, 262145, 5, 6225931, 327681, 5, 6291467, 393217, 5, 6357003, 393217, 5, 6422539, 327681, 5, 6488075, 131073, 2, 6553611, 262145, 5, 6619147, 131073, 2, 6684683, 131073, 2, 6750219, 327681, 5, 6815755, 393217, 5, 6881291, 327681, 5, 6946827, 327681, 5, 7012363, 458753, 5, 5505036, 393217, 5, 5570572, 327681, 5, 5636108, 327681, 5, 5701644, 393217, 5, 5767180, 262145, 5, 5832716, 393217, 5, 5898252, 458753, 5, 5963788, 262145, 5, 6029324, 393217, 5, 6094860, 262145, 5, 6160396, 327681, 5, 6225932, 1, 2, 6291468, 327681, 5, 6357004, 393217, 5, 6422540, 393217, 5, 6488076, 393217, 5, 6553612, 327681, 5, 6619148, 262145, 5, 6684684, 262145, 5, 6750220, 327681, 5, 6815756, 393217, 5, 6881292, 393217, 5, 6946828, 262145, 5, 7012364, 458753, 5, 5505037, 458753, 5, 5570573, 458753, 5, 5636109, 458753, 5, 5701645, 1, 2, 5767181, 262145, 5, 5832717, 65537, 2, 5898253, 458753, 5, 5963789, 393217, 5, 6029325, 327681, 5, 6094861, 262145, 5, 6160397, 327681, 5, 6225933, 262145, 5, 6291469, 327681, 5, 6357005, 458753, 5, 6422541, 262145, 5, 6488077, 262145, 5, 6553613, 65537, 2, 6619149, 458753, 5, 6684685, 327681, 5, 6750221, 262145, 5, 6815757, 393217, 5, 6881293, 458753, 5, 6946829, 327681, 5, 7012365, 327681, 5, 5505038, 458753, 5, 5570574, 262145, 5, 5636110, 393217, 5, 5701646, 262145, 5, 5767182, 327681, 5, 5832718, 458753, 5, 5898254, 196609, 2, 5963790, 458753, 5, 6029326, 458753, 5, 6094862, 262145, 5, 6160398, 262145, 5, 6225934, 393217, 5, 6291470, 458753, 5, 6357006, 262145, 5, 6422542, 262145, 5, 6488078, 262145, 5, 6553614, 393217, 5, 6619150, 393217, 5, 6684686, 458753, 5, 6750222, 327681, 5, 6815758, 393217, 5, 6881294, 327681, 5, 6946830, 393217, 5, 7012366, 393217, 5, 5505039, 393217, 5, 5570575, 393217, 5, 5636111, 393217, 5, 5701647, 393217, 5, 5767183, 262145, 5, 5832719, 262145, 5, 5898255, 262145, 5, 5963791, 458753, 5, 6029327, 262145, 5, 6094863, 458753, 5, 6160399, 458753, 5, 6225935, 327681, 5, 6291471, 393217, 5, 6357007, 262145, 5, 6422543, 327681, 5, 6488079, 262145, 5, 6553615, 131073, 2, 6619151, 393217, 5, 6684687, 262145, 5, 6750223, 458753, 5, 6815759, 262145, 5, 6881295, 458753, 5, 6946831, 393217, 5, 7012367, 262145, 5, 4718584, 262145, 5, 4784120, 262145, 5, 4849656, 393217, 5, 4915192, 262145, 5, 4980728, 327681, 5, 5046264, 393217, 5, 5111800, 458753, 5, 5177336, 458753, 5, 5242872, 458753, 5, 5308408, 262145, 5, 5373944, 458753, 5, 5439480, 458753, 4, 5505016, 262145, 4, 4718585, 393217, 5, 4784121, 393217, 5, 4849657, 262145, 5, 4915193, 131073, 2, 4980729, 262145, 5, 5046265, 458753, 5, 5111801, 262145, 5, 5177337, 393217, 5, 5242873, 458753, 5, 5308409, 327681, 5, 5373945, 458753, 2, 5439481, 131073, 2, 5505017, 393217, 5, 4718586, 393217, 5, 4784122, 327681, 5, 4849658, 393217, 5, 4915194, 393217, 5, 4980730, 393217, 5, 5046266, 262145, 5, 5111802, 262145, 5, 5177338, 327681, 5, 5242874, 327681, 5, 5308410, 262145, 5, 5373946, 327681, 4, 5439482, 262145, 5, 5505018, 327681, 4, 4718587, 458753, 5, 4784123, 327681, 5, 4849659, 327681, 5, 4915195, 327681, 5, 4980731, 393217, 5, 5046267, 458753, 5, 5111803, 393217, 5, 5177339, 1, 2, 5242875, 262145, 5, 5308411, 262145, 5, 5373947, 458753, 5, 5439483, 65537, 2, 5505019, 327681, 5, 4456418, 393217, 5, 4521954, 327681, 5, 4587490, 393217, 5, 4653026, 262145, 5, 4718562, 393217, 5, 4784098, 393217, 5, 4849634, 262145, 5, 4915170, 393217, 5, 4980706, 262145, 5, 5046242, 393217, 5, 5111778, 393217, 5, 5177314, 393217, 5, 4456419, 262145, 5, 4521955, 327681, 5, 4587491, 458753, 5, 4653027, 393217, 5, 4718563, 393217, 5, 4784099, 393217, 5, 4849635, 458753, 5, 4915171, 262145, 5, 4980707, 262145, 5, 5046243, 458753, 5, 5111779, 393217, 5, 5177315, 262145, 5, 5242851, 262145, 5, 4456420, 393217, 5, 4521956, 458753, 5, 4587492, 262145, 5, 4653028, 393217, 5, 4718564, 262145, 5, 4784100, 393217, 5, 4849636, 458753, 5, 4915172, 262145, 5, 4980708, 262145, 5, 5046244, 458753, 5, 5111780, 393217, 5, 5177316, 458753, 5, 5242852, 327681, 5, 5308388, 458753, 5, 4456421, 327681, 5, 4521957, 262145, 5, 4587493, 458753, 5, 4653029, 393217, 5, 4718565, 327681, 5, 4784101, 458753, 5, 4849637, 393217, 5, 4915173, 262145, 5, 4980709, 458753, 5, 5046245, 262145, 5, 5111781, 327681, 5, 5177317, 327681, 5, 5242853, 393217, 5, 5308389, 262145, 5, 5373925, 327681, 5, 4456422, 327681, 5, 4521958, 327681, 5, 4587494, 393217, 5, 4653030, 393217, 5, 4718566, 393217, 5, 4784102, 327681, 5, 4849638, 327681, 5, 4915174, 262145, 5, 4980710, 262145, 5, 5046246, 393217, 5, 5111782, 393217, 5, 5177318, 327681, 5, 5242854, 262145, 5, 5308390, 327681, 5, 5373926, 458753, 5, 5439462, 393217, 5, 4456423, 458753, 5, 4521959, 393217, 5, 4587495, 393217, 5, 4653031, 393217, 5, 4718567, 393217, 5, 4784103, 262145, 5, 4849639, 262145, 5, 4915175, 393217, 5, 4980711, 262145, 5, 5046247, 327681, 5, 5111783, 262145, 5, 5177319, 393217, 5, 5242855, 458753, 5, 5308391, 262145, 5, 5373927, 393217, 5, 5439463, 458753, 5, 5504999, 262145, 5, 4456424, 458753, 5, 4521960, 458753, 2, 4587496, 262145, 5, 4653032, 65537, 2, 4718568, 1, 2, 4784104, 262145, 5, 4849640, 327681, 5, 4915176, 262145, 5, 4980712, 458753, 5, 5046248, 327681, 5, 5111784, 327681, 5, 5177320, 393217, 5, 5242856, 458753, 5, 5308392, 262145, 5, 5373928, 262145, 5, 5439464, 393217, 5, 5505000, 393217, 5, 5570536, 327681, 5, 4456425, 458753, 4, 4521961, 262145, 4, 4587497, 262145, 5, 4653033, 393217, 5, 4718569, 327681, 5, 4784105, 262145, 4, 4849641, 327681, 5, 4915177, 458753, 5, 4980713, 327681, 5, 5046249, 262145, 4, 5111785, 327681, 4, 5177321, 327681, 4, 5242857, 262145, 4, 5308393, 393217, 5, 5373929, 327681, 5, 5439465, 262145, 5, 5505001, 393217, 5, 5570537, 458753, 5, 5636073, 458753, 5, 4456426, 327681, 4, 4521962, 327681, 5, 4587498, 327681, 4, 4653034, 393217, 5, 4718570, 393217, 5, 4784106, 393217, 5, 4849642, 393217, 5, 4915178, 393217, 5, 4980714, 262145, 5, 5046250, 262145, 5, 5111786, 458753, 5, 5177322, 327681, 5, 5242858, 327681, 5, 5308394, 458753, 5, 5373930, 327681, 5, 5439466, 327681, 5, 5505002, 458753, 5, 5570538, 393217, 5, 5636074, 393217, 5, 5701610, 393217, 5, 4456427, 458753, 5, 4521963, 327681, 5, 4587499, 458753, 2, 4653035, 262145, 5, 4718571, 458753, 5, 4784107, 458753, 5, 4849643, 458753, 5, 4915179, 393217, 5, 4980715, 393217, 5, 5046251, 1, 6, 5111787, 65537, 6, 5177323, 131073, 6, 5242859, 1, 6, 5308395, 393217, 5, 5373931, 262145, 5, 5439467, 393217, 5, 5505003, 327681, 5, 5570539, 458753, 5, 5636075, 458753, 5, 5701611, 262145, 5, 5767147, 458753, 5, 5832683, 327681, 5, 4456428, 393217, 5, 4521964, 327681, 5, 4587500, 262145, 2, 4653036, 262145, 5, 4718572, 327681, 5, 4784108, 327681, 5, 4849644, 458753, 5, 4915180, 458753, 4, 4980716, 393217, 5, 5046252, 196609, 6, 5111788, 458753, 6, 5177324, 262145, 6, 5242860, 327681, 6, 5308396, 327681, 5, 5373932, 393217, 5, 5439468, 393217, 5, 5505004, 458753, 5, 5570540, 327681, 5, 5636076, 458753, 5, 5701612, 327681, 5, 5767148, 458753, 5, 5832684, 458753, 5, 4456429, 262145, 5, 4521965, 262145, 5, 4587501, 458753, 5, 4653037, 262145, 5, 4718573, 262145, 5, 4784109, 458753, 5, 4849645, 262145, 5, 4915181, 393217, 5, 4980717, 327681, 4, 5046253, 131073, 6, 5111789, 131073, 6, 5177325, 458753, 6, 5242861, 393217, 5, 5308397, 458753, 5, 5373933, 458753, 5, 5439469, 458753, 5, 5505005, 262145, 5, 5570541, 393217, 5, 5636077, 327681, 5, 5701613, 262145, 5, 5767149, 393217, 5, 5832685, 327681, 5, 4456430, 458753, 5, 4521966, 262145, 5, 4587502, 327681, 5, 4653038, 327681, 4, 4718574, 458753, 5, 4784110, 65537, 2, 4849646, 262145, 5, 4915182, 262145, 5, 4980718, 262145, 5, 5046254, 458753, 5, 5111790, 458753, 5, 5177326, 327681, 5, 5242862, 327681, 4, 5308398, 458753, 5, 5373934, 393217, 5, 5439470, 327681, 5, 5505006, 393217, 5, 5570542, 327681, 5, 5636078, 458753, 5, 5701614, 262145, 5, 5767150, 327681, 5, 5832686, 393217, 5, 5898222, 327681, 5, 4456431, 458753, 4, 4521967, 393217, 5, 4587503, 393217, 5, 4653039, 458753, 2, 4718575, 262145, 5, 4784111, 393217, 5, 4849647, 458753, 5, 4915183, 458753, 2, 4980719, 262145, 5, 5046255, 327681, 5, 5111791, 262145, 5, 5177327, 262145, 5, 5242863, 1, 2, 5308399, 262145, 5, 5373935, 393217, 5, 5439471, 262145, 5, 5505007, 393217, 5, 5570543, 327681, 5, 5636079, 327681, 5, 5701615, 262145, 5, 5767151, 262145, 5, 5832687, 458753, 5, 5898223, 458753, 5, 5963759, 262145, 5, 4456432, 262145, 5, 4521968, 327681, 5, 4587504, 262145, 5, 4653040, 458753, 5, 4718576, 131073, 2, 4784112, 327681, 5, 4849648, 196609, 2, 4915184, 327681, 5, 4980720, 458753, 4, 5046256, 327681, 5, 5111792, 327681, 5, 5177328, 262145, 5, 5242864, 327681, 4, 5308400, 327681, 5, 5373936, 327681, 5, 5439472, 393217, 5, 5505008, 393217, 5, 5570544, 393217, 5, 5636080, 458753, 5, 5701616, 458753, 5, 5767152, 327681, 5, 5832688, 262145, 5, 5898224, 393217, 5, 5963760, 393217, 5, 6029296, 327681, 5, 4456433, 458753, 5, 4521969, 327681, 5, 4587505, 393217, 5, 4653041, 262145, 5, 4718577, 327681, 5, 4784113, 262145, 5, 4849649, 458753, 5, 4915185, 393217, 5, 4980721, 262145, 5, 5046257, 327681, 5, 5111793, 393217, 5, 5177329, 458753, 5, 5242865, 393217, 5, 5308401, 327681, 5, 5373937, 327681, 5, 5439473, 327681, 5, 5505009, 458753, 5, 5570545, 393217, 5, 5636081, 458753, 5, 5701617, 196609, 2, 5767153, 262145, 5, 5832689, 327681, 5, 5898225, 458753, 5, 5963761, 327681, 5, 6029297, 458753, 5, 6094833, 327681, 5, 6160369, 393217, 5, 4456434, 327681, 5, 4521970, 393217, 5, 4587506, 327681, 5, 4653042, 327681, 5, 4718578, 262145, 5, 4784114, 327681, 5, 4849650, 131073, 2, 4915186, 458753, 5, 4980722, 327681, 5, 5046258, 393217, 5, 5111794, 393217, 5, 5177330, 262145, 5, 5242866, 262145, 5, 5308402, 393217, 5, 5373938, 393217, 5, 5439474, 458753, 5, 5505010, 393217, 5, 5570546, 327681, 5, 5636082, 458753, 5, 5701618, 262145, 5, 5767154, 458753, 5, 5832690, 262145, 5, 5898226, 327681, 5, 5963762, 393217, 5, 6029298, 458753, 5, 6094834, 393217, 5, 6160370, 458753, 5, 6225906, 262145, 5, 4456435, 262145, 5, 4521971, 327681, 5, 4587507, 458753, 5, 4653043, 458753, 5, 4718579, 458753, 5, 4784115, 458753, 5, 4849651, 1, 2, 4915187, 393217, 5, 4980723, 327681, 5, 5046259, 393217, 5, 5111795, 458753, 5, 5177331, 458753, 5, 5242867, 458753, 5, 5308403, 262145, 5, 5373939, 1, 2, 5439475, 262145, 5, 5505011, 393217, 5, 5570547, 393217, 5, 5636083, 196609, 2, 5701619, 458753, 5, 5767155, 262145, 5, 5832691, 262145, 5, 5898227, 262145, 5, 5963763, 393217, 5, 6029299, 458753, 5, 6094835, 327681, 5, 6160371, 262145, 5, 6225907, 458753, 5, 6291443, 458753, 5, 3145761, 327681, 4, 3211297, 327681, 5, 3276833, 262145, 5, 3342369, 327681, 5, 3407905, 393217, 5, 3473441, 458753, 5, 3538977, 327681, 5, 3604513, 262145, 5, 3670049, 327681, 5, 3735585, 393217, 5, 3801121, 458753, 4, 3866657, 65537, 6, 3932193, 327681, 6, 3997729, 196609, 6, 4063265, 393217, 6, 4128801, 65537, 2, 4194337, 458753, 2, 4259873, 327681, 5, 4325409, 393217, 5, 4390945, 393217, 5, 4456481, 327681, 5, 4522017, 458753, 4, 4587553, 131073, 2, 4653089, 393217, 4, 4718625, 327681, 5, 4784161, 458753, 5, 4849697, 458753, 5, 4915233, 458753, 5, 4980769, 393217, 5, 5046305, 458753, 5, 5111841, 327681, 5, 5177377, 327681, 5, 5242913, 327681, 5, 5308449, 393217, 5, 5373985, 393217, 5, 5439521, 262145, 5, 5505057, 327681, 5, 5570593, 458753, 5, 5636129, 327681, 5, 5701665, 458753, 5, 5767201, 327681, 5, 5832737, 458753, 5, 5898273, 458753, 5, 5963809, 393217, 5, 6029345, 393217, 5, 6094881, 262145, 5, 6160417, 327681, 5, 6225953, 327681, 5, 6291489, 393217, 5, 852002, 458753, 2, 917538, 458753, 5, 983074, 458753, 5, 3145762, 393217, 5, 3211298, 458753, 5, 3276834, 327681, 5, 3342370, 327681, 5, 3407906, 262145, 5, 3473442, 458753, 5, 3538978, 458753, 2, 3604514, 262145, 5, 3670050, 458753, 5, 3735586, 327681, 5, 3801122, 458753, 2, 3866658, 393217, 2, 3932194, 393217, 2, 3997730, 327681, 5, 4063266, 65537, 2, 4128802, 458753, 5, 4194338, 327681, 5, 4259874, 262145, 5, 4325410, 262145, 4, 4390946, 131073, 2, 4456482, 458753, 5, 4522018, 262145, 4, 4587554, 327681, 2, 4653090, 327681, 5, 4718626, 262145, 5, 4784162, 393217, 5, 4849698, 327681, 5, 4915234, 458753, 5, 4980770, 393217, 5, 5046306, 327681, 5, 5111842, 458753, 5, 5177378, 327681, 5, 5242914, 393217, 5, 5308450, 327681, 5, 5373986, 262145, 5, 5439522, 393217, 5, 5505058, 458753, 5, 5570594, 327681, 5, 5636130, 458753, 5, 5701666, 327681, 5, 5767202, 327681, 5, 5832738, 327681, 5, 5898274, 262145, 5, 5963810, 393217, 5, 6029346, 262145, 5, 6094882, 262145, 5, 6160418, 262145, 5, 6225954, 262145, 5, 6291490, 458753, 5, 852003, 393217, 5, 917539, 327681, 5, 983075, 458753, 2, 3145763, 458753, 4, 3211299, 458753, 5, 3276835, 458753, 5, 3342371, 458753, 5, 3407907, 393217, 5, 3473443, 393217, 5, 3538979, 327681, 4, 3604515, 262145, 5, 3670051, 262145, 5, 3735587, 393217, 5, 3801123, 327681, 2, 3866659, 262145, 5, 3932195, 327681, 5, 3997731, 393217, 5, 4063267, 262145, 5, 4128803, 393217, 5, 4194339, 393217, 5, 4259875, 262145, 5, 4325411, 327681, 5, 4390947, 327681, 5, 4456483, 327681, 5, 4522019, 327681, 5, 4587555, 393217, 5, 4653091, 458753, 5, 4718627, 262145, 5, 4784163, 327681, 5, 4849699, 393217, 5, 4915235, 458753, 5, 4980771, 262145, 5, 5046307, 393217, 5, 5111843, 262145, 5, 5177379, 327681, 5, 5242915, 327681, 5, 5308451, 262145, 5, 5373987, 327681, 5, 5439523, 262145, 5, 5505059, 327681, 5, 5570595, 262145, 5, 5636131, 262145, 5, 5701667, 262145, 5, 5767203, 393217, 5, 5832739, 393217, 5, 5898275, 262145, 5, 5963811, 458753, 5, 6029347, 393217, 5, 6094883, 393217, 5, 6160419, 458753, 5, 852004, 327681, 4, 917540, 262145, 5, 983076, 393217, 5, 3473444, 262145, 5, 3538980, 393217, 5, 3604516, 327681, 5, 3670052, 393217, 5, 3735588, 458753, 5, 3801124, 458753, 4, 3866660, 262145, 5, 3932196, 458753, 5, 3997732, 262145, 5, 4063268, 393217, 5, 4128804, 393217, 5, 4194340, 327681, 4, 4259876, 458753, 2, 4325412, 327681, 5, 4390948, 327681, 5, 4456484, 458753, 5, 4522020, 262145, 5, 4587556, 327681, 5, 4653092, 262145, 5, 4718628, 327681, 5, 4784164, 393217, 5, 4849700, 327681, 5, 4915236, 327681, 5, 4980772, 262145, 5, 5046308, 393217, 5, 5111844, 327681, 5, 5177380, 327681, 5, 5242916, 393217, 5, 5308452, 458753, 5, 5373988, 262145, 5, 5439524, 262145, 5, 5505060, 458753, 5, 5570596, 458753, 5, 5636132, 327681, 5, 5701668, 458753, 5, 5767204, 393217, 5, 5832740, 262145, 5, 5898276, 327681, 5, 5963812, 393217, 5, 6029348, 393217, 5, 6094884, 458753, 5, 3473445, 327681, 5, 3538981, 327681, 5, 3604517, 327681, 5, 3670053, 393217, 5, 3735589, 262145, 5, 3801125, 196609, 2, 3866661, 262145, 5, 3932197, 327681, 5, 3997733, 262145, 5, 4063269, 458753, 5, 4128805, 458753, 5, 4194341, 262145, 5, 4259877, 458753, 5, 4325413, 393217, 5, 4390949, 262145, 5, 4456485, 327681, 5, 4522021, 458753, 5, 4587557, 393217, 5, 4653093, 393217, 5, 4718629, 393217, 5, 4784165, 262145, 5, 4849701, 327681, 5, 4915237, 327681, 5, 4980773, 458753, 5, 5046309, 393217, 5, 5111845, 393217, 5, 5177381, 262145, 5, 5242917, 393217, 5, 5308453, 458753, 5, 5373989, 393217, 5, 5439525, 393217, 5, 5505061, 327681, 5, 5570597, 327681, 5, 5636133, 327681, 5, 5701669, 262145, 5, 5767205, 262145, 5, 5832741, 393217, 5, 5898277, 327681, 5, 5963813, 458753, 5, 6029349, 393217, 5, 6094885, 393217, 5, 3473446, 393217, 2, 3538982, 262145, 5, 3604518, 327681, 5, 3670054, 262145, 5, 3735590, 458753, 5, 3801126, 327681, 4, 3866662, 393217, 5, 3932198, 327681, 5, 3997734, 196609, 2, 4063270, 327681, 5, 4128806, 393217, 5, 4194342, 262145, 5, 4259878, 393217, 5, 4325414, 262145, 5, 4390950, 327681, 5, 4456486, 458753, 5, 4522022, 262145, 5, 4587558, 327681, 5, 4653094, 458753, 5, 4718630, 327681, 5, 4784166, 393217, 5, 4849702, 327681, 5, 4915238, 327681, 5, 4980774, 393217, 5, 5046310, 458753, 5, 5111846, 458753, 5, 5177382, 327681, 5, 5242918, 393217, 5, 5308454, 393217, 5, 5373990, 262145, 5, 5439526, 458753, 5, 5505062, 262145, 5, 5570598, 393217, 5, 5636134, 327681, 5, 5701670, 327681, 5, 5767206, 327681, 5, 5832742, 458753, 5, 5898278, 393217, 5, 5963814, 262145, 5, 6029350, 458753, 5, 3473447, 327681, 5, 3538983, 327681, 5, 3604519, 327681, 5, 3670055, 327681, 5, 3735591, 262145, 5, 3801127, 327681, 5, 3866663, 327681, 4, 3932199, 327681, 5, 3997735, 458753, 2, 4063271, 327681, 5, 4128807, 458753, 5, 4194343, 327681, 5, 4259879, 393217, 5, 4325415, 458753, 5, 4390951, 327681, 4, 4456487, 393217, 5, 4522023, 262145, 5, 4587559, 327681, 5, 4653095, 458753, 5, 4718631, 262145, 5, 4784167, 262145, 5, 4849703, 393217, 5, 4915239, 393217, 5, 4980775, 393217, 5, 5046311, 262145, 5, 5111847, 262145, 5, 5177383, 262145, 5, 5242919, 262145, 5, 5308455, 393217, 5, 5373991, 327681, 5, 5439527, 458753, 5, 5505063, 458753, 5, 5570599, 327681, 5, 5636135, 458753, 5, 5701671, 458753, 5, 5767207, 262145, 5, 5832743, 458753, 5, 5898279, 458753, 5, 3473448, 458753, 2, 3538984, 458753, 5, 3604520, 393217, 5, 3670056, 262145, 5, 3735592, 327681, 5, 3801128, 327681, 5, 3866664, 458753, 4, 3932200, 393217, 5, 3997736, 262145, 5, 4063272, 262145, 5, 4128808, 458753, 5, 4194344, 458753, 5, 4259880, 327681, 5, 4325416, 458753, 5, 4390952, 327681, 5, 4456488, 458753, 5, 4522024, 262145, 5, 4587560, 327681, 5, 4653096, 327681, 5, 4718632, 327681, 5, 4784168, 327681, 5, 4849704, 393217, 5, 4915240, 393217, 5, 4980776, 262145, 5, 5046312, 393217, 5, 5111848, 262145, 5, 5177384, 327681, 5, 5242920, 262145, 5, 5308456, 327681, 5, 5373992, 393217, 5, 5439528, 458753, 5, 5505064, 458753, 5, 5570600, 327681, 5, 5636136, 458753, 5, 5701672, 458753, 5, 5767208, 393217, 5, 5832744, 393217, 5, 3473449, 262145, 4, 3538985, 393217, 5, 3604521, 458753, 5, 3670057, 262145, 5, 3735593, 262145, 5, 3801129, 393217, 5, 3866665, 262145, 5, 3932201, 458753, 5, 3997737, 458753, 2, 4063273, 458753, 5, 4128809, 262145, 5, 4194345, 393217, 5, 4259881, 458753, 5, 4325417, 458753, 5, 4390953, 393217, 5, 4456489, 393217, 5, 4522025, 262145, 5, 4587561, 458753, 5, 4653097, 458753, 5, 4718633, 262145, 5, 4784169, 327681, 5, 4849705, 262145, 5, 4915241, 393217, 5, 4980777, 393217, 5, 5046313, 458753, 5, 5111849, 327681, 5, 5177385, 458753, 5, 5242921, 458753, 5, 5308457, 458753, 5, 5373993, 458753, 5, 5439529, 327681, 5, 5505065, 262145, 5, 5570601, 327681, 5, 5636137, 327681, 5, 5701673, 327681, 5, 5767209, 393217, 5, 3473450, 393217, 5, 3538986, 262145, 5, 3604522, 393217, 5, 3670058, 458753, 5, 3735594, 327681, 5, 3801130, 327681, 5, 3866666, 393217, 2, 3932202, 327681, 5, 3997738, 393217, 5, 4063274, 262145, 5, 4128810, 327681, 5, 4194346, 393217, 5, 4259882, 262145, 5, 4325418, 458753, 5, 4390954, 393217, 5, 4456490, 262145, 5, 4522026, 262145, 5, 4587562, 262145, 5, 4653098, 393217, 5, 4718634, 327681, 5, 4784170, 393217, 5, 4849706, 327681, 5, 4915242, 262145, 5, 4980778, 393217, 5, 5046314, 458753, 5, 5111850, 458753, 5, 5177386, 327681, 5, 5242922, 458753, 5, 5308458, 327681, 5, 5373994, 393217, 5, 5439530, 458753, 5, 5505066, 393217, 5, 5570602, 262145, 5, 5636138, 458753, 5, 5701674, 458753, 5, 5767210, 458753, 5, 3473451, 327681, 4, 3538987, 458753, 5, 3604523, 458753, 5, 3670059, 262145, 5, 3735595, 393217, 5, 3801131, 262145, 5, 3866667, 327681, 5, 3932203, 393217, 2, 3997739, 327681, 5, 4063275, 262145, 5, 4128811, 327681, 5, 4194347, 393217, 5, 4259883, 458753, 5, 4325419, 262145, 5, 4390955, 458753, 5, 4456491, 458753, 5, 4522027, 262145, 5, 4587563, 262145, 5, 4653099, 327681, 5, 4718635, 262145, 5, 4784171, 393217, 5, 4849707, 262145, 5, 4915243, 327681, 5, 4980779, 393217, 5, 5046315, 393217, 5, 5111851, 393217, 5, 5177387, 393217, 5, 5242923, 327681, 5, 5308459, 458753, 5, 5373995, 262145, 5, 5439531, 327681, 5, 5505067, 327681, 5, 5570603, 327681, 5, 5636139, 262145, 5, 5701675, 393217, 5, 3473452, 393217, 5, 3538988, 458753, 2, 3604524, 327681, 5, 3670060, 393217, 5, 3735596, 327681, 5, 3801132, 458753, 5, 3866668, 262145, 5, 3932204, 262145, 5, 3997740, 458753, 5, 4063276, 262145, 5, 4128812, 262145, 5, 4194348, 458753, 5, 4259884, 262145, 5, 4325420, 327681, 5, 4390956, 393217, 5, 4456492, 262145, 5, 4522028, 327681, 5, 4587564, 458753, 5, 4653100, 458753, 5, 4718636, 262145, 5, 4784172, 327681, 5, 4849708, 458753, 5, 4915244, 327681, 5, 4980780, 393217, 5, 5046316, 262145, 5, 5111852, 262145, 5, 5177388, 393217, 5, 5242924, 262145, 5, 5308460, 327681, 5, 5373996, 458753, 5, 5439532, 393217, 5, 5505068, 262145, 5, 5570604, 458753, 5, 3473453, 327681, 5, 3538989, 262145, 4, 3604525, 262145, 5, 3670061, 327681, 5, 3735597, 262145, 5, 3801133, 458753, 5, 3866669, 393217, 5, 3932205, 393217, 5, 3997741, 327681, 5, 4063277, 262145, 5, 4128813, 393217, 5, 4194349, 458753, 5, 4259885, 393217, 5, 4325421, 327681, 5, 4390957, 262145, 5, 4456493, 262145, 5, 4522029, 262145, 5, 4587565, 262145, 5, 4653101, 393217, 5, 4718637, 262145, 5, 4784173, 327681, 5, 4849709, 327681, 5, 4915245, 262145, 5, 4980781, 327681, 5, 5046317, 458753, 5, 5111853, 458753, 5, 5177389, 393217, 5, 5242925, 327681, 5, 5308461, 327681, 5, 5373997, 327681, 5, 5439533, 393217, 5, 5505069, 327681, 5, 5570605, 327681, 5, 3473454, 458753, 5, 3538990, 458753, 5, 3604526, 458753, 5, 3670062, 458753, 5, 3735598, 327681, 5, 3801134, 262145, 5, 3866670, 327681, 5, 3932206, 262145, 5, 3997742, 458753, 5, 4063278, 327681, 5, 4128814, 393217, 5, 4194350, 262145, 5, 4259886, 262145, 5, 4325422, 327681, 5, 4390958, 327681, 5, 4456494, 262145, 5, 4522030, 327681, 5, 4587566, 458753, 5, 4653102, 393217, 5, 4718638, 327681, 5, 4784174, 393217, 5, 4849710, 327681, 5, 4915246, 327681, 5, 4980782, 458753, 5, 5046318, 393217, 5, 5111854, 327681, 5, 5177390, 393217, 5, 5242926, 262145, 5, 5308462, 393217, 5, 5373998, 327681, 5, 5439534, 458753, 5, 5505070, 262145, 5, 3473455, 327681, 5, 3538991, 458753, 5, 3604527, 262145, 5, 3670063, 327681, 5, 3735599, 327681, 5, 3801135, 327681, 5, 3866671, 393217, 5, 3932207, 458753, 5, 3997743, 262145, 5, 4063279, 262145, 5, 4128815, 327681, 5, 4194351, 262145, 5, 4259887, 327681, 5, 4325423, 327681, 5, 4390959, 327681, 5, 4456495, 262145, 5, 4522031, 262145, 5, 4587567, 327681, 5, 4653103, 327681, 5, 4718639, 327681, 5, 4784175, 393217, 5, 4849711, 458753, 5, 4915247, 327681, 5, 4980783, 327681, 5, 5046319, 327681, 5, 5111855, 262145, 5, 5177391, 262145, 5, 5242927, 393217, 5, 5308463, 262145, 5, 5373999, 458753, 5, 5439535, 393217, 5, 3473456, 393217, 5, 3538992, 458753, 2, 3604528, 458753, 5, 3670064, 393217, 5, 3735600, 393217, 5, 3801136, 327681, 5, 3866672, 262145, 5, 3932208, 458753, 5, 3997744, 393217, 5, 4063280, 262145, 5, 4128816, 393217, 5, 4194352, 327681, 5, 4259888, 458753, 5, 4325424, 262145, 5, 4390960, 262145, 5, 4456496, 393217, 5, 4522032, 327681, 5, 4587568, 458753, 5, 4653104, 393217, 5, 4718640, 393217, 5, 4784176, 458753, 5, 4849712, 262145, 5, 4915248, 262145, 5, 4980784, 327681, 5, 5046320, 393217, 5, 5111856, 327681, 5, 5177392, 262145, 5, 5242928, 262145, 5, 5308464, 262145, 5, 3473457, 262145, 5, 3538993, 327681, 2, 3604529, 262145, 5, 3670065, 262145, 5, 3735601, 327681, 5, 3801137, 458753, 5, 3866673, 458753, 5, 3932209, 393217, 5, 3997745, 393217, 5, 4063281, 327681, 5, 4128817, 327681, 5, 4194353, 262145, 5, 4259889, 327681, 5, 4325425, 262145, 5, 4390961, 262145, 5, 4456497, 393217, 5, 4522033, 262145, 5, 4587569, 327681, 5, 4653105, 327681, 5, 4718641, 262145, 5, 4784177, 327681, 5, 4849713, 327681, 5, 4915249, 393217, 5, 4980785, 458753, 5, 5046321, 327681, 5, 5111857, 458753, 5, 5177393, 327681, 5, 5242929, 458753, 5, 3473458, 458753, 2, 3538994, 262145, 5, 3604530, 262145, 5, 3670066, 458753, 5, 3735602, 262145, 5, 3801138, 262145, 5, 3866674, 458753, 5, 3932210, 262145, 5, 3997746, 262145, 5, 4063282, 393217, 5, 4128818, 458753, 5, 4194354, 327681, 5, 4259890, 458753, 5, 4325426, 458753, 5, 4390962, 393217, 5, 4456498, 393217, 5, 4522034, 327681, 5, 4587570, 393217, 5, 4653106, 458753, 5, 4718642, 262145, 5, 4784178, 262145, 5, 4849714, 458753, 5, 4915250, 458753, 5, 4980786, 262145, 5, 5046322, 327681, 5, 5111858, 458753, 5, 5177394, 262145, 5, 5242930, 393217, 5, 4390942, 458753, 5, 4456478, 393217, 5, 4522014, 262145, 5, 4587550, 327681, 5, 4653086, 393217, 5, 4718622, 262145, 5, 4784158, 262145, 5, 4849694, 262145, 5, 4915230, 327681, 5, 4980766, 393217, 5, 5046302, 327681, 5, 5111838, 393217, 5, 5177374, 327681, 5, 5242910, 393217, 5, 5308446, 393217, 5, 5373982, 262145, 5, 5439518, 327681, 5, 5505054, 393217, 5, 5570590, 327681, 5, 5636126, 458753, 5, 5701662, 458753, 5, 5767198, 458753, 5, 5832734, 393217, 5, 5898270, 393217, 5, 5963806, 458753, 5, 6029342, 458753, 5, 6094878, 327681, 5, 6160414, 327681, 5, 6225950, 327681, 5, 6291486, 262145, 5, 6357022, 458753, 5, 6422558, 393217, 5, 3145759, 458753, 2, 3211295, 262145, 5, 3276831, 458753, 5, 3342367, 262145, 5, 3407903, 327681, 5, 3473439, 262145, 5, 3538975, 262145, 5, 3604511, 327681, 5, 3670047, 458753, 5, 3735583, 393217, 5, 3801119, 65537, 6, 3866655, 393217, 6, 3932191, 131073, 6, 3997727, 327681, 6, 4063263, 458753, 6, 4128799, 196609, 0, 4194335, 458753, 5, 4259871, 262145, 5, 4325407, 262145, 4, 4390943, 393217, 4, 4456479, 458753, 5, 4522015, 327681, 5, 4587551, 458753, 5, 4653087, 327681, 5, 4718623, 458753, 5, 4784159, 262145, 5, 4849695, 262145, 5, 4915231, 327681, 5, 4980767, 393217, 5, 5046303, 458753, 5, 5111839, 327681, 5, 5177375, 458753, 5, 5242911, 393217, 5, 5308447, 262145, 5, 5373983, 327681, 5, 5439519, 458753, 5, 5505055, 393217, 5, 5570591, 393217, 5, 5636127, 458753, 5, 5701663, 262145, 5, 5767199, 458753, 5, 5832735, 458753, 5, 5898271, 458753, 5, 5963807, 327681, 5, 6029343, 393217, 5, 6094879, 327681, 5, 6160415, 327681, 5, 6225951, 458753, 5, 6291487, 393217, 5, 6357023, 327681, 5, 6422559, 393217, 5, 3145760, 262145, 5, 3211296, 262145, 5, 3276832, 327681, 4, 3342368, 393217, 5, 3407904, 393217, 5, 3473440, 458753, 5, 3538976, 262145, 5, 3604512, 458753, 5, 3670048, 327681, 5, 3735584, 458753, 5, 3801120, 131073, 6, 3866656, 131073, 6, 3932192, 262145, 6, 3997728, 65537, 6, 4063264, 327681, 6, 4128800, 196609, 0, 4194336, 327681, 5, 4259872, 327681, 5, 4325408, 262145, 5, 4390944, 458753, 5, 4456480, 458753, 5, 4522016, 458753, 5, 4587552, 393217, 5, 4653088, 458753, 5, 4718624, 458753, 4, 4784160, 393217, 5, 4849696, 393217, 5, 4915232, 327681, 5, 4980768, 327681, 5, 5046304, 262145, 5, 5111840, 393217, 5, 5177376, 327681, 5, 5242912, 262145, 5, 5308448, 327681, 5, 5373984, 327681, 5, 5439520, 458753, 5, 5505056, 262145, 5, 5570592, 458753, 5, 5636128, 393217, 5, 5701664, 262145, 5, 5767200, 262145, 5, 5832736, 393217, 5, 5898272, 393217, 5, 5963808, 327681, 5, 6029344, 262145, 5, 6094880, 458753, 5, 6160416, 262145, 5, 6225952, 327681, 5, 6291488, 458753, 5, 6357024, 327681, 5, 1769494, 393217, 5, 1835030, 458753, 5, 1900566, 393217, 5, 1769495, 327681, 5, 1835031, 393217, 5, 1900567, 393217, 5, 1638422, 327681, 5, 1703958, 393217, 5, 1638423, 327681, 5, 1703959, 262145, 5, 1638424, 393217, 5, 1703960, 327681, 5, -131037, 458753, 5, 720931, 262145, 5, 786467, 262145, 5, -131036, 458753, 5, 720932, 393217, 5, 786468, 327681, 5, -327643, 327681, 5, -262107, 327681, 5, -196571, 458753, 5, -131035, 327681, 5, 720933, 327681, 5, -327642, 393217, 5, -262106, 262145, 5, -196570, 393217, 2, -131034, 458753, 2, 720934, 458753, 5, -327641, 393217, 5, -262105, 393217, 5, -196569, 327681, 5, -131033, 458753, 2, -65497, 458753, 4, 39, 393217, 5, 65575, 458753, 5, 131111, 458753, 5, 196647, 458753, 4, 262183, 458753, 5, 327719, 262145, 5, 393255, 262145, 5, 458791, 327681, 5, 524327, 327681, 5, 589863, 393217, 5, 655399, 262145, 5, 720935, 262145, 5, -327640, 262145, 5, -262104, 393217, 5, -196568, 327681, 5, -131032, 393217, 5, -65496, 458753, 4, 40, 458753, 2, 65576, 327681, 5, 131112, 393217, 5, 196648, 458753, 2, 262184, 393217, 5, 327720, 327681, 5, 393256, 458753, 2, 458792, 65537, 2, 524328, 327681, 2, 589864, 393217, 5, 655400, 458753, 5, 720936, 262145, 5, -327639, 458753, 5, -262103, 393217, 5, -196567, 393217, 5, -131031, 327681, 5, -65495, 393217, 5, 41, 131073, 2, 65577, 458753, 4, 131113, 458753, 5, 196649, 458753, 5, 262185, 262145, 5, 327721, 196609, 2, 393257, 458753, 5, 458793, 458753, 5, 524329, 393217, 5, 589865, 327681, 4, 655401, 458753, 5, 720937, 262145, 5, -131038, 262145, 5, 720930, 458753, 5, 786466, 262145, 5, -917540, 262145, 5, -852004, 393217, 5, -786468, 262145, 5, -720932, 458753, 5, -655396, 393217, 5, -589860, 262145, 5, -524324, 327681, 5, -458788, 458753, 5, -393252, 393217, 5, -327716, 393217, 5, -262180, 458753, 5, -196644, 393217, 5, -131108, 262145, 5, -65572, 393217, 5, -36, 327681, 5, 65500, 458753, 5, 131036, 262145, 5, 196572, 393217, 5, 262108, 262145, 5, 327644, 458753, 5, 393180, 327681, 5, 458716, 393217, 5, 524252, 393217, 5, 589788, 327681, 5, 655324, 393217, 5, 720860, 458753, 5, 3473372, 262145, 5, 3538908, 327681, 4, 3604444, 393217, 5, 3669980, 458753, 5, 3735516, 393217, 5, 3801052, 327681, 5, 3866588, 393217, 5, 3932124, 327681, 5, 3997660, 327681, 5, 4063196, 327681, 5, 4128732, 458753, 5, 4194268, 262145, 5, 4259804, 458753, 5, 4325340, 393217, 5, 4390876, 393217, 5, 4456412, 327681, 5, 4521948, 327681, 5, 4587484, 327681, 5, 4653020, 327681, 5, 4718556, 458753, 5, 4784092, 458753, 5, -983075, 327681, 5, -917539, 327681, 5, -852003, 458753, 5, -786467, 262145, 5, -720931, 458753, 5, -655395, 262145, 5, -589859, 393217, 5, -524323, 458753, 5, -458787, 458753, 5, -393251, 393217, 5, -327715, 458753, 5, -262179, 458753, 5, -196643, 393217, 5, -131107, 262145, 5, -65571, 327681, 5, -35, 327681, 5, 65501, 327681, 5, 131037, 458753, 5, 196573, 327681, 5, 262109, 262145, 5, 327645, 393217, 5, 393181, 262145, 5, 458717, 327681, 5, 524253, 458753, 5, 589789, 262145, 5, 655325, 393217, 5, 720861, 393217, 5, 3473373, 458753, 5, 3538909, 327681, 5, 3604445, 458753, 2, 3669981, 458753, 5, 3735517, 393217, 5, 3801053, 458753, 5, 3866589, 262145, 5, 3932125, 327681, 4, 3997661, 393217, 5, 4063197, 262145, 5, 4128733, 327681, 5, 4194269, 458753, 5, 4259805, 262145, 5, 4325341, 262145, 5, 4390877, 262145, 5, 4456413, 393217, 5, 4521949, 327681, 5, 4587485, 393217, 5, 4653021, 458753, 5, 4718557, 393217, 5, 4784093, 262145, 5, 4849629, 327681, 5, -1048610, 458753, 5, -983074, 458753, 5, -917538, 393217, 5, -852002, 393217, 5, -786466, 327681, 5, -720930, 458753, 5, -655394, 458753, 5, -589858, 262145, 5, -524322, 327681, 5, -458786, 327681, 5, -393250, 393217, 5, -327714, 262145, 5, -262178, 393217, 5, -196642, 393217, 5, -131106, 458753, 5, -65570, 458753, 5, -34, 393217, 5, 65502, 458753, 5, 131038, 458753, 5, 196574, 458753, 5, 262110, 262145, 5, 327646, 393217, 5, 393182, 393217, 5, 458718, 327681, 5, 524254, 262145, 5, 589790, 458753, 5, 655326, 262145, 5, 720862, 262145, 5, 3473374, 327681, 5, 3538910, 458753, 5, 3604446, 327681, 5, 3669982, 458753, 5, 3735518, 327681, 5, 3801054, 262145, 5, 3866590, 393217, 5, 3932126, 458753, 2, 3997662, 327681, 5, 4063198, 327681, 5, 4128734, 393217, 5, 4194270, 327681, 5, 4259806, 262145, 5, 4325342, 458753, 5, 4390878, 393217, 5, 4456414, 458753, 5, 4521950, 262145, 5, 4587486, 262145, 5, 4653022, 458753, 5, 4718558, 458753, 5, 4784094, 262145, 5, 4849630, 393217, 5, -1114145, 458753, 5, -1048609, 327681, 5, -983073, 458753, 5, -917537, 327681, 5, -852001, 458753, 5, -786465, 458753, 5, -720929, 393217, 5, -655393, 393217, 5, -589857, 327681, 5, -524321, 458753, 5, -458785, 458753, 5, -393249, 262145, 5, -327713, 393217, 5, -262177, 262145, 5, -196641, 262145, 5, -131105, 393217, 5, -65569, 393217, 5, -33, 262145, 5, 65503, 393217, 5, 131039, 262145, 5, 196575, 393217, 5, 262111, 262145, 5, 327647, 393217, 5, 393183, 458753, 5, 458719, 393217, 5, 524255, 393217, 5, 589791, 327681, 5, 655327, 262145, 5, 720863, 458753, 5, 3473375, 458753, 4, 3538911, 327681, 5, 3604447, 327681, 5, 3669983, 393217, 5, 3735519, 393217, 5, 3801055, 458753, 5, 3866591, 327681, 5, 3932127, 327681, 5, 3997663, 393217, 5, 4063199, 393217, 5, 4128735, 458753, 5, 4194271, 458753, 4, 4259807, 458753, 5, 4325343, 393217, 5, 4390879, 262145, 5, 4456415, 393217, 5, 4521951, 393217, 5, 4587487, 327681, 5, 4653023, 327681, 5, 4718559, 458753, 5, 4784095, 458753, 5, 4849631, 327681, 5, -1179680, 327681, 5, -1114144, 327681, 5, -1048608, 262145, 5, -983072, 262145, 5, -917536, 327681, 5, -852000, 458753, 5, -786464, 393217, 5, -720928, 262145, 5, -655392, 327681, 5, -589856, 393217, 5, -524320, 262145, 5, -458784, 262145, 5, -393248, 262145, 5, -327712, 262145, 5, -262176, 458753, 5, -196640, 458753, 5, -131104, 393217, 5, -65568, 262145, 5, -32, 393217, 5, 65504, 458753, 4, 131040, 262145, 5, 196576, 458753, 5, 262112, 393217, 5, 327648, 262145, 5, 393184, 262145, 5, 458720, 393217, 5, 524256, 458753, 5, 589792, 393217, 5, 655328, 458753, 5, 720864, 327681, 5, 3473376, 458753, 2, 3538912, 458753, 5, 3604448, 327681, 5, 3669984, 458753, 5, 3735520, 393217, 5, 3801056, 262145, 5, 3866592, 393217, 5, 3932128, 327681, 5, 3997664, 458753, 5, 4063200, 458753, 5, 4128736, 393217, 5, 4194272, 327681, 5, 4259808, 327681, 4, 4325344, 262145, 5, 4390880, 458753, 5, 4456416, 393217, 5, 4521952, 393217, 5, 4587488, 393217, 5, 4653024, 393217, 5, 4718560, 393217, 5, 4784096, 262145, 5, 4849632, 327681, 5, -1179679, 327681, 5, -1114143, 458753, 5, -1048607, 262145, 5, -983071, 262145, 5, -917535, 458753, 5, -851999, 327681, 5, -786463, 393217, 5, -720927, 458753, 5, -655391, 262145, 5, -589855, 327681, 5, -524319, 458753, 5, -458783, 458753, 5, -393247, 458753, 5, -327711, 262145, 5, -262175, 327681, 5, -196639, 458753, 5, -131103, 393217, 5, -65567, 262145, 5, -31, 327681, 5, 65505, 327681, 4, 131041, 458753, 5, 196577, 458753, 5, 262113, 327681, 5, 327649, 327681, 5, 393185, 393217, 5, 458721, 393217, 5, 524257, 262145, 5, 589793, 393217, 5, 655329, 262145, 5, 720865, 327681, 5, 3473377, 458753, 2, 3538913, 458753, 5, 3604449, 393217, 5, 3669985, 458753, 5, 3735521, 262145, 5, 3801057, 458753, 5, 3866593, 458753, 5, 3932129, 393217, 5, 3997665, 458753, 5, 4063201, 262145, 5, 4128737, 393217, 5, 4194273, 327681, 5, 4259809, 458753, 5, 4325345, 327681, 5, 4390881, 262145, 5, 4456417, 327681, 5, 4521953, 327681, 5, 4587489, 262145, 5, 4653025, 458753, 5, 4718561, 262145, 5, 4784097, 262145, 5, 4849633, 393217, 5, -1179678, 458753, 5, -1114142, 327681, 5, -1048606, 393217, 5, -983070, 393217, 5, -917534, 393217, 5, -851998, 262145, 5, -786462, 458753, 5, -720926, 262145, 5, -655390, 262145, 5, -589854, 393217, 5, -524318, 327681, 5, -458782, 393217, 5, -393246, 458753, 5, -327710, 458753, 5, -262174, 458753, 5, -196638, 458753, 5, -131102, 458753, 5, -65566, 262145, 5, -30, 327681, 4, 65506, 458753, 5, 131042, 262145, 5, 196578, 327681, 5, 262114, 393217, 5, 327650, 458753, 5, 393186, 393217, 5, 458722, 327681, 5, 524258, 393217, 5, 589794, 262145, 5, 655330, 262145, 5, 720866, 393217, 5, 3473378, 393217, 5, 3538914, 262145, 5, 3604450, 262145, 5, 3669986, 327681, 5, 3735522, 262145, 5, 3801058, 458753, 5, 3866594, 458753, 4, 3932130, 393217, 5, 3997666, 196609, 2, 4063202, 262145, 5, 4128738, 458753, 5, 4194274, 327681, 5, 4259810, 262145, 5, 4325346, 327681, 5, 4390882, 393217, 5, -1179677, 458753, 5, -1114141, 393217, 5, -1048605, 393217, 5, -983069, 393217, 5, -917533, 262145, 5, -851997, 393217, 5, -786461, 458753, 5, -720925, 327681, 5, -655389, 262145, 5, -589853, 327681, 5, -524317, 458753, 5, -458781, 393217, 5, -393245, 262145, 5, -327709, 458753, 5, -262173, 262145, 5, -196637, 327681, 5, -131101, 327681, 5, -65565, 393217, 5, -29, 327681, 5, 65507, 458753, 5, 131043, 458753, 5, 196579, 393217, 5, 262115, 327681, 4, 327651, 262145, 5, 393187, 262145, 4, 458723, 458753, 5, 524259, 327681, 5, 589795, 458753, 5, 655331, 393217, 5, 720867, 458753, 5, 3473379, 393217, 5, 3538915, 393217, 5, 3604451, 262145, 5, 3669987, 327681, 5, 3735523, 458753, 5, 3801059, 262145, 5, 3866595, 393217, 5, 3932131, 393217, 5, 3997667, 327681, 5, 4063203, 327681, 5, 4128739, 458753, 4, 4194275, 393217, 5, 4259811, 458753, 5, 4325347, 458753, 5, 4390883, 393217, 5, -1179676, 458753, 5, -1114140, 458753, 5, -1048604, 262145, 5, -983068, 393217, 5, -917532, 262145, 5, -851996, 393217, 5, -786460, 458753, 5, -720924, 458753, 5, -655388, 327681, 5, -589852, 327681, 5, -524316, 262145, 5, -458780, 262145, 5, -393244, 458753, 5, -327708, 393217, 5, -262172, 327681, 5, -196636, 65537, 2, -131100, 262145, 5, -65564, 327681, 5, -28, 458753, 5, 65508, 458753, 5, 131044, 262145, 5, 196580, 458753, 5, 262116, 327681, 5, 327652, 262145, 4, 393188, 458753, 2, 458724, 393217, 5, 524260, 458753, 5, 589796, 327681, 5, 655332, 262145, 5, 720868, 458753, 5, 3473380, 262145, 4, 3538916, 458753, 2, 3604452, 458753, 5, 3669988, 327681, 5, 3735524, 393217, 5, 3801060, 262145, 5, 3866596, 393217, 5, 3932132, 327681, 5, 3997668, 262145, 5, 4063204, 262145, 5, 4128740, 327681, 5, 4194276, 393217, 5, 4259812, 327681, 5, 4325348, 393217, 5, 4390884, 262145, 5, -1179675, 262145, 5, -1114139, 458753, 5, -1048603, 458753, 5, -983067, 327681, 5, -917531, 262145, 5, -851995, 393217, 5, -786459, 458753, 5, -720923, 262145, 5, -655387, 393217, 5, -589851, 458753, 5, -524315, 393217, 5, -458779, 458753, 5, -393243, 458753, 5, -327707, 393217, 5, -262171, 393217, 5, -196635, 262145, 5, -131099, 458753, 5, -65563, 393217, 5, -27, 393217, 5, 65509, 327681, 5, 131045, 393217, 5, 196581, 458753, 5, 262117, 327681, 5, 327653, 327681, 2, 393189, 458753, 2, 458725, 327681, 5, 524261, 393217, 5, 589797, 458753, 5, 655333, 458753, 5, 720869, 327681, 5, 786405, 262145, 5, 851941, 458753, 5, 917477, 327681, 5, 3473381, 262145, 5, 3538917, 458753, 5, 3604453, 393217, 5, 3669989, 393217, 5, 3735525, 262145, 5, 3801061, 262145, 5, 3866597, 393217, 5, 3932133, 393217, 5, 3997669, 458753, 5, 4063205, 393217, 5, 4128741, 458753, 5, 4194277, 458753, 5, 4259813, 327681, 5, 4325349, 393217, 5, 4390885, 393217, 5, -1179674, 458753, 5, -1114138, 458753, 5, -1048602, 262145, 5, -983066, 458753, 5, -917530, 262145, 5, -851994, 458753, 5, -786458, 458753, 5, -720922, 327681, 5, -655386, 393217, 5, -589850, 458753, 5, -524314, 327681, 5, -458778, 458753, 5, -393242, 393217, 5, -327706, 262145, 5, -262170, 327681, 5, -196634, 262145, 5, -131098, 262145, 5, -65562, 327681, 5, -26, 393217, 5, 65510, 393217, 5, 131046, 262145, 5, 196582, 458753, 5, 262118, 262145, 4, 327654, 458753, 5, 393190, 458753, 2, 458726, 262145, 5, 524262, 262145, 5, 589798, 393217, 5, 655334, 458753, 5, 720870, 327681, 5, 786406, 262145, 5, 851942, 262145, 5, 917478, 393217, 5, 3473382, 262145, 4, 3538918, 458753, 5, 3604454, 262145, 2, 3669990, 327681, 5, 3735526, 327681, 5, 3801062, 458753, 5, 3866598, 327681, 5, 3932134, 327681, 5, 3997670, 393217, 5, 4063206, 393217, 5, 4128742, 393217, 5, 4194278, 262145, 5, 4259814, 327681, 5, 4325350, 393217, 5, 4390886, 262145, 5, 3670012, 262145, 5, 3735548, 393217, 5, 3801084, 393217, 5, 3866620, 327681, 5, 3670013, 327681, 5, 3735549, 458753, 5, 3801085, 458753, 5, 3866621, 458753, 5, 3670014, 458753, 5, 3735550, 262145, 5, 3801086, 327681, 5, 3866622, 393217, 5, 3670015, 458753, 5, 3735551, 393217, 5, 3801087, 393217, 5, 3866623, 327681, 5, 3604480, 262145, 5, 3670016, 458753, 5, 3735552, 393217, 5, 3801088, 262145, 5, 3604481, 458753, 5, 3670017, 327681, 5, 3735553, 393217, 5, 3801089, 327681, 5, 3604482, 393217, 5, 3670018, 327681, 5, 3735554, 327681, 5, 3801090, 262145, 5, 3604483, 262145, 5, 3670019, 327681, 5, 3735555, 262145, 5, 3801091, 393217, 5, 3604484, 262145, 5, 3670020, 393217, 5, 3735556, 458753, 5, 3801092, 458753, 5, 3604485, 262145, 5, 3670021, 393217, 5, 3735557, 393217, 5, 3801093, 458753, 5, 3604486, 262145, 5, 3670022, 262145, 5, 3735558, 458753, 5, 3801094, 458753, 5, 3604487, 262145, 5, 3670023, 458753, 5, 3735559, 327681, 5, 3801095, 262145, 5, 3604488, 393217, 5, 3670024, 458753, 5, 3735560, 393217, 5, 3801096, 393217, 5, 3604489, 327681, 5, 3670025, 262145, 5, 3735561, 327681, 5, 3801097, 458753, 5, 3604490, 327681, 5, 3670026, 327681, 5, 3735562, 393217, 5, 3801098, 262145, 5, 3604491, 458753, 5, 3670027, 458753, 5, 3735563, 393217, 5, 3801099, 327681, 5, 3604492, 393217, 5, 3670028, 458753, 5, 3735564, 458753, 5, 3801100, 262145, 5, 3604493, 458753, 5, 3670029, 393217, 5, 3735565, 393217, 5, 3801101, 393217, 5, 3604494, 327681, 5, 3670030, 458753, 5, 3735566, 458753, 5, 3801102, 262145, 5, 3604495, 393217, 5, 3670031, 458753, 5, 3735567, 327681, 5, 3801103, 262145, 5, 2359284, 262145, 5, 2424820, 327681, 5, 2490356, 327681, 5, 2555892, 458753, 5, 2621428, 327681, 5, 2686964, 327681, 3, 2752500, 327681, 3, 2818036, 458753, 5, 2883572, 458753, 5, 2949108, 327681, 5, 3014644, 393217, 5, 2359285, 458753, 5, 2424821, 262145, 5, 2490357, 327681, 5, 2555893, 458753, 5, 2621429, 393217, 5, 2686965, 131073, 1, 2818037, 327681, 5, 2883573, 458753, 5, 2949109, 1, 2, 3014645, 327681, 4, 2359286, 393217, 5, 2424822, 262145, 5, 2490358, 393217, 5, 2555894, 458753, 5, 2621430, 327681, 5, 2818038, 327681, 5, 2883574, 458753, 5, 2949110, 262145, 5, 3014646, 458753, 5, 2359287, 393217, 5, 2424823, 262145, 5, 2490359, 262145, 4, 2555895, 458753, 5, 2621431, 262145, 5, 2686967, 131073, 1, 2752503, 65537, 1, 2818039, 262145, 5, 2883575, 458753, 5, 2949111, 458753, 5, 3014647, 327681, 5, 2359288, 262145, 5, 2424824, 458753, 5, 2490360, 458753, 5, 2555896, 262145, 5, 2621432, 262145, 5, 2686968, 131073, 1, 2752504, 65537, 1, 2818040, 262145, 4, 2883576, 393217, 5, 2949112, 393217, 5, 3014648, 458753, 2, 2359289, 393217, 5, 2424825, 458753, 5, 2490361, 393217, 5, 2555897, 458753, 5, 2621433, 327681, 5, 2686969, 131073, 1, 2752505, 65537, 1, 2818041, 393217, 5, 2883577, 458753, 4, 2949113, 262145, 5, 3014649, 327681, 5, 2359290, 393217, 5, 2424826, 327681, 5, 2490362, 393217, 5, 2555898, 393217, 5, 2621434, 262145, 5, 2686970, 131073, 1, 2752506, 65537, 1, 2818042, 458753, 5, 2883578, 262145, 5, 2949114, 327681, 5, 3014650, 393217, 5, 2359291, 393217, 5, 2424827, 262145, 5, 2490363, 262145, 5, 2555899, 458753, 5, 2621435, 458753, 5, 2686971, 131073, 1, 2752507, 65537, 1, 2818043, 262145, 5, 2883579, 327681, 5, 2949115, 393217, 5, 3014651, 327681, 5, 2359292, 262145, 5, 2424828, 458753, 5, 2490364, 262145, 5, 2555900, 458753, 4, 2621436, 327681, 5, 2686972, 327681, 3, 2752508, 327681, 3, 2818044, 262145, 5, 2883580, 327681, 5, 2949116, 327681, 5, 3014652, 393217, 5, 2359293, 393217, 5, 2424829, 327681, 5, 2490365, 327681, 5, 2555901, 393217, 5, 2621437, 393217, 5, 2686973, 458753, 5, 2752509, 393217, 5, 2818045, 327681, 5, 2883581, 327681, 5, 2949117, 458753, 5, 3014653, 393217, 5, 2359294, 262145, 5, 2424830, 327681, 4, 2490366, 327681, 4, 2555902, 327681, 5, 2621438, 458753, 5, 2686974, 327681, 5, 2752510, 393217, 5, 2818046, 393217, 5, 2883582, 327681, 5, 2949118, 262145, 5, 3014654, 262145, 5, 2359295, 262145, 5, 2424831, 262145, 5, 2490367, 327681, 4, 2555903, 327681, 5, 2621439, 327681, 5, 2686975, 327681, 5, 2752511, 327681, 5, 2818047, 458753, 5, 2883583, 458753, 5, 2949119, 393217, 5, 3014655, 393217, 5, 2293760, 262145, 5, 2359296, 327681, 5, 2424832, 458753, 5, 2490368, 458753, 5, 2555904, 458753, 5, 2621440, 262145, 5, 2686976, 393217, 5, 2752512, 262145, 4, 2818048, 327681, 4, 2883584, 458753, 5, 2949120, 393217, 5, 2293761, 393217, 5, 2359297, 458753, 5, 2424833, 262145, 5, 2490369, 327681, 5, 2555905, 327681, 5, 2621441, 458753, 5, 2686977, 327681, 5, 2752513, 458753, 5, 2818049, 458753, 5, 2883585, 327681, 5, 2949121, 327681, 5, 2359283, 262145, 5, 2424819, 327681, 5, 2490355, 393217, 5, 2555891, 262145, 5, 2621427, 393217, 5, 2686963, 458753, 5, 2752499, 458753, 5, 2818035, 262145, 5, 2883571, 458753, 5, 2949107, 262145, 5, 3014643, 262145, 5, 3080179, 327681, 5, 3145715, 393217, 5, 3080180, 393217, 5, 3145716, 393217, 5, 3080181, 393217, 5, 3145717, 393217, 5, 2293747, 327681, 5, 2293748, 327681, 5, 2293749, 393217, 5, 2293750, 327681, 5, 2293751, 327681, 5, 2293752, 327681, 5, 2293753, 327681, 5, 2293754, 327681, 5, 2293755, 262145, 5, 2293756, 458753, 5, 2293757, 458753, 5, 2293758, 327681, 5, 2293759, 262145, 5, 2228224, 262145, 5, 2228225, 458753, 5, 1376243, 262145, 5, 1441779, 327681, 5, 1507315, 327681, 5, 1572851, 262145, 5, 1638387, 393217, 5, 1703923, 393217, 5, 1769459, 393217, 5, 1834995, 327681, 5, 1900531, 262145, 5, 1966067, 393217, 5, 1376244, 458753, 5, 1441780, 327681, 5, 1507316, 327681, 5, 1572852, 327681, 5, 1638388, 262145, 5, 1703924, 262145, 5, 1769460, 393217, 5, 1834996, 393217, 5, 1900532, 393217, 5, 1966068, 327681, 5, 1376245, 458753, 5, 1441781, 458753, 5, 1507317, 393217, 5, 1572853, 262145, 5, 1638389, 393217, 5, 1703925, 262145, 5, 1769461, 458753, 5, 1834997, 458753, 5, 1900533, 262145, 5, 1966069, 327681, 5, 1376246, 327681, 5, 1441782, 327681, 5, 1507318, 458753, 5, 1572854, 262145, 5, 1638390, 393217, 5, 1703926, 458753, 5, 1769462, 327681, 4, 1834998, 196609, 2, 1900534, 327681, 5, 1966070, 393217, 5, 1376247, 458753, 4, 1441783, 262145, 5, 1507319, 327681, 5, 1572855, 262145, 5, 1638391, 327681, 5, 1703927, 131073, 2, 1769463, 393217, 5, 1834999, 262145, 5, 1900535, 262145, 5, 1966071, 327681, 4, 1376248, 262145, 4, 1441784, 393217, 5, 1507320, 458753, 5, 1572856, 393217, 5, 1638392, 393217, 5, 1703928, 458753, 5, 1769464, 393217, 5, 1835000, 458753, 4, 1900536, 393217, 5, 1966072, 327681, 5, 1376249, 327681, 5, 1441785, 262145, 5, 1507321, 393217, 5, 1572857, 458753, 5, 1638393, 327681, 5, 1703929, 458753, 5, 1769465, 458753, 5, 1835001, 327681, 5, 1900537, 327681, 4, 1966073, 458753, 5, 1376250, 458753, 2, 1441786, 458753, 5, 1507322, 327681, 5, 1572858, 327681, 5, 1638394, 327681, 4, 1703930, 458753, 5, 1769466, 393217, 5, 1835002, 262145, 5, 1900538, 327681, 4, 1966074, 262145, 5, 1376251, 458753, 2, 1441787, 262145, 5, 1507323, 262145, 5, 1572859, 327681, 4, 1638395, 262145, 5, 1703931, 393217, 5, 1769467, 262145, 5, 1835003, 262145, 5, 1900539, 262145, 5, 1966075, 393217, 5, 1376252, 262145, 5, 1441788, 458753, 5, 1507324, 327681, 4, 1572860, 393217, 5, 1638396, 327681, 5, 1703932, 458753, 5, 1769468, 262145, 5, 1835004, 262145, 5, 1900540, 327681, 5, 1966076, 393217, 5, 1376253, 393217, 5, 1441789, 393217, 4, 1507325, 262145, 2, 1572861, 458753, 5, 1638397, 327681, 5, 1703933, 458753, 5, 1769469, 393217, 5, 1835005, 327681, 4, 1900541, 262145, 5, 1966077, 327681, 5, 1376254, 262145, 5, 1441790, 458753, 2, 1507326, 262145, 5, 1572862, 458753, 5, 1638398, 393217, 5, 1703934, 393217, 5, 1769470, 458753, 5, 1835006, 327681, 5, 1900542, 262145, 5, 1966078, 458753, 5, 1376255, 393217, 5, 1441791, 327681, 4, 1507327, 393217, 5, 1572863, 327681, 5, 1638399, 393217, 5, 1703935, 262145, 5, 1769471, 458753, 4, 1835007, 327681, 5, 1900543, 458753, 5, 1966079, 262145, 5, 1310720, 393217, 5, 1376256, 262145, 5, 1441792, 262145, 5, 1507328, 262145, 5, 1572864, 327681, 5, 1638400, 458753, 5, 1703936, 393217, 5, 1769472, 262145, 5, 1835008, 393217, 5, 1900544, 393217, 5, 1310721, 262145, 5, 1376257, 262145, 5, 1441793, 262145, 5, 1507329, 327681, 5, 1572865, 327681, 5, 1638401, 393217, 5, 1703937, 393217, 5, 1769473, 458753, 5, 1835009, 262145, 5, 1900545, 262145, 5, 1310707, 458753, 5, 1310708, 262145, 5, 1310709, 262145, 5, 1310710, 458753, 5, 1310711, 327681, 5, 1310712, 393217, 5, 1310713, 393217, 5, 1310714, 262145, 5, 1310715, 327681, 5, 1310716, 327681, 5, 1310717, 262145, 5, 1310718, 327681, 5, 1310719, 327681, 5, 1245184, 327681, 5, 1245185, 458753, 5, 983027, 262145, 5, 1048563, 262145, 5, 1114099, 393217, 5, 1179635, 458753, 5, 1245171, 458753, 5, 983028, 327681, 5, 1048564, 327681, 5, 1114100, 458753, 5, 1179636, 327681, 5, 1245172, 458753, 5, 983029, 262145, 5, 1048565, 458753, 5, 1114101, 458753, 5, 1179637, 393217, 5, 1245173, 262145, 5, 917475, 262145, 5, 983011, 327681, 5, 1048547, 458753, 5, 1114083, 458753, 5, 1179619, 327681, 4, 917476, 262145, 5, 983012, 458753, 2, 1048548, 262145, 4, 1114084, 327681, 2, 1179620, 262145, 4, 983013, 262145, 4, 1048549, 458753, 2, 1114085, 327681, 5, 1179621, 327681, 5, 983014, 458753, 5, 1048550, 458753, 2, 1114086, 262145, 5, 1179622, 458753, 2, 983015, 458753, 2, 1048551, 262145, 4, 1114087, 393217, 5, 1179623, 393217, 5, 983016, 262145, 5, 1048552, 262145, 4, 1114088, 393217, 5, 1179624, 262145, 5, 983017, 393217, 5, 1048553, 393217, 5, 1114089, 458753, 4, 1179625, 393217, 5, 983018, 327681, 5, 1048554, 458753, 5, 1114090, 458753, 5, 1179626, 262145, 5, 983019, 458753, 5, 1048555, 458753, 5, 1114091, 262145, 5, 1179627, 262145, 5, 983020, 458753, 5, 1048556, 458753, 5, 1114092, 327681, 5, 1179628, 393217, 5, 983021, 262145, 5, 1048557, 262145, 5, 1114093, 458753, 5, 1179629, 458753, 5, 983022, 262145, 5, 1048558, 393217, 5, 1114094, 327681, 5, 1179630, 327681, 5, 983023, 393217, 5, 1048559, 327681, 5, 1114095, 327681, 5, 1179631, 458753, 5, 983024, 262145, 5, 1048560, 262145, 5, 1114096, 262145, 5, 1179632, 262145, 5, 983025, 327681, 5, 1048561, 262145, 5, 1114097, 458753, 5, 1179633, 262145, 5, 983026, 262145, 5, 1048562, 327681, 5, 1114098, 262145, 5, 1179634, 262145, 5, 1245155, 458753, 5, 1310691, 327681, 5, 1376227, 393217, 5, 1441763, 393217, 5, 1507299, 327681, 5, 1572835, 262145, 5, 1638371, 458753, 5, 1703907, 327681, 5, 1769443, 327681, 5, 1834979, 393217, 5, 1900515, 262145, 5, 1966051, 327681, 5, 1245156, 458753, 5, 1310692, 262145, 5, 1376228, 458753, 5, 1441764, 262145, 5, 1507300, 327681, 5, 1572836, 327681, 5, 1638372, 327681, 5, 1703908, 327681, 5, 1769444, 262145, 5, 1834980, 458753, 5, 1900516, 262145, 5, 1966052, 458753, 5, 1245157, 327681, 5, 1310693, 327681, 5, 1376229, 262145, 5, 1441765, 262145, 5, 1507301, 262145, 5, 1572837, 327681, 5, 1638373, 262145, 5, 1703909, 458753, 5, 1769445, 458753, 5, 1834981, 393217, 5, 1900517, 327681, 5, 1966053, 458753, 5, 1245158, 458753, 5, 1310694, 262145, 5, 1376230, 458753, 5, 1441766, 393217, 5, 1507302, 327681, 5, 1572838, 458753, 5, 1638374, 458753, 5, 1703910, 393217, 5, 1769446, 327681, 5, 1834982, 458753, 5, 1900518, 393217, 5, 1966054, 262145, 5, 1769431, 262145, 5, 1834967, 393217, 5, 1900503, 327681, 5, 1966039, 458753, 5, 1769432, 458753, 5, 1834968, 393217, 5, 1900504, 327681, 5, 1966040, 262145, 5, 1769433, 327681, 5, 1834969, 327681, 5, 1900505, 262145, 5, 1966041, 262145, 5, 1769434, 262145, 5, 1834970, 458753, 5, 1900506, 393217, 5, 1966042, 458753, 5, 1769435, 262145, 5, 1834971, 327681, 5, 1900507, 458753, 5, 1966043, 458753, 5, 1769436, 458753, 5, 1834972, 393217, 5, 1900508, 327681, 5, 1966044, 327681, 5, 1769437, 393217, 5, 1834973, 262145, 5, 1900509, 262145, 5, 1966045, 327681, 5, 1769438, 393217, 5, 1834974, 393217, 5, 1900510, 458753, 5, 1966046, 458753, 5, 1769439, 262145, 5, 1834975, 327681, 5, 1900511, 262145, 5, 1966047, 458753, 5, 1769440, 262145, 5, 1834976, 327681, 5, 1900512, 393217, 5, 1966048, 327681, 5, 1769441, 393217, 5, 1834977, 262145, 5, 1900513, 458753, 5, 1966049, 458753, 5, 1769442, 327681, 5, 1834978, 262145, 5, 1900514, 262145, 5, 1966050, 262145, 5, 2293719, 393217, 5, 2359255, 327681, 5, 2424791, 262145, 5, 2490327, 393217, 5, 2293720, 327681, 5, 2359256, 262145, 5, 2424792, 458753, 5, 2490328, 327681, 5, 2293721, 327681, 5, 2359257, 327681, 5, 2424793, 327681, 5, 2490329, 393217, 5, 2293722, 262145, 5, 2359258, 327681, 5, 2424794, 393217, 5, 2490330, 458753, 5, 2293723, 327681, 5, 2359259, 327681, 5, 2424795, 327681, 5, 2490331, 393217, 5, 2293724, 262145, 5, 2359260, 327681, 5, 2424796, 327681, 5, 2490332, 327681, 5, 2293725, 393217, 5, 2359261, 458753, 5, 2424797, 393217, 5, 2490333, 393217, 5, 2293726, 327681, 5, 2359262, 262145, 5, 2424798, 393217, 5, 2490334, 458753, 5, 2293727, 262145, 5, 2359263, 458753, 5, 2424799, 458753, 5, 2490335, 262145, 5, 2293728, 262145, 5, 2359264, 327681, 5, 2424800, 262145, 5, 2490336, 327681, 5, 2293729, 327681, 5, 2359265, 327681, 5, 2424801, 327681, 5, 2490337, 458753, 5, 2293730, 393217, 5, 2359266, 262145, 5, 2424802, 393217, 5, 2490338, 327681, 5, 2293731, 262145, 5, 2359267, 393217, 5, 2424803, 458753, 5, 2490339, 458753, 5, 2293732, 262145, 5, 2359268, 327681, 5, 2424804, 458753, 5, 2490340, 327681, 5, 2293733, 327681, 5, 2359269, 393217, 5, 2424805, 458753, 5, 2490341, 393217, 5, 2293734, 393217, 5, 2359270, 458753, 5, 2424806, 262145, 5, 2490342, 262145, 5, 2555875, 262145, 5, 2621411, 327681, 5, 2686947, 327681, 5, 2752483, 262145, 5, 2818019, 327681, 5, 2883555, 393217, 5, 2949091, 458753, 5, 3014627, 262145, 5, 3080163, 327681, 5, 3145699, 393217, 5, 3211235, 262145, 5, 3276771, 393217, 5, 3342307, 393217, 5, 3407843, 327681, 5, 2555876, 327681, 5, 2621412, 327681, 5, 2686948, 327681, 5, 2752484, 327681, 5, 2818020, 262145, 5, 2883556, 327681, 5, 2949092, 458753, 5, 3014628, 327681, 5, 3080164, 327681, 4, 3145700, 458753, 2, 3211236, 458753, 5, 3276772, 458753, 2, 3342308, 393217, 5, 3407844, 327681, 4, 2555877, 327681, 5, 2621413, 327681, 5, 2686949, 458753, 5, 2752485, 327681, 5, 2818021, 327681, 5, 2883557, 327681, 5, 2949093, 262145, 5, 3014629, 327681, 5, 3080165, 131073, 2, 3145701, 327681, 2, 3211237, 327681, 5, 3276773, 458753, 4, 3342309, 327681, 5, 3407845, 458753, 4, 2555878, 327681, 5, 2621414, 458753, 5, 2686950, 327681, 5, 2752486, 393217, 5, 2818022, 262145, 5, 2883558, 262145, 5, 2949094, 262145, 5, 3014630, 262145, 5, 3080166, 458753, 4, 3145702, 131073, 2, 3211238, 393217, 5, 3276774, 327681, 5, 3342310, 393217, 5, 3407846, 262145, 5, 3080167, 458753, 5, 3145703, 327681, 5, 3211239, 65537, 2, 3276775, 393217, 5, 3342311, 458753, 5, 3407847, 458753, 2, 3080168, 262145, 5, 3145704, 458753, 4, 3211240, 262145, 5, 3276776, 262145, 5, 3342312, 327681, 4, 3407848, 458753, 5, 3080169, 393217, 5, 3145705, 458753, 4, 3211241, 327681, 4, 3276777, 458753, 5, 3342313, 458753, 5, 3407849, 262145, 5, 3080170, 327681, 5, 3145706, 458753, 5, 3211242, 393217, 5, 3276778, 327681, 5, 3342314, 327681, 4, 3407850, 262145, 5, 3080171, 327681, 5, 3145707, 327681, 4, 3211243, 327681, 4, 3276779, 262145, 5, 3342315, 262145, 5, 3407851, 327681, 2, 3080172, 393217, 5, 3145708, 262145, 4, 3211244, 458753, 5, 3276780, 458753, 2, 3342316, 458753, 4, 3407852, 458753, 4, 3080173, 327681, 5, 3145709, 393217, 5, 3211245, 262145, 4, 3276781, 327681, 5, 3342317, 327681, 5, 3407853, 393217, 5, 3080174, 393217, 5, 3145710, 393217, 5, 3211246, 393217, 5, 3276782, 458753, 4, 3342318, 393217, 5, 3407854, 458753, 2, 3080175, 262145, 5, 3145711, 262145, 4, 3211247, 262145, 5, 3276783, 458753, 4, 3342319, 458753, 5, 3407855, 393217, 5, 3080176, 262145, 5, 3145712, 458753, 2, 3211248, 458753, 5, 3276784, 458753, 5, 3342320, 393217, 5, 3407856, 327681, 5, 3080177, 458753, 5, 3145713, 327681, 4, 3211249, 393217, 5, 3276785, 262145, 5, 3342321, 458753, 5, 3407857, 262145, 5, 3080178, 262145, 5, 3145714, 327681, 5, 1507307, 262145, 5, 1572843, 262145, 5, 1638379, 327681, 5, 1703915, 458753, 5, 1769451, 393217, 5, 1834987, 262145, 5, 1900523, 327681, 5, 1966059, 262145, 5, 2031595, 393217, 5, 2097131, 393217, 5, 2162667, 262145, 5, 2228203, 458753, 5, 2293739, 458753, 5, 2359275, 458753, 5, 2424811, 327681, 5, 2490347, 393217, 5, 2555883, 458753, 5, 2621419, 458753, 5, 2686955, 458753, 5, 2752491, 327681, 5, 1507308, 393217, 5, 1572844, 327681, 5, 1638380, 327681, 5, 1703916, 327681, 5, 1769452, 393217, 5, 1834988, 262145, 5, 1900524, 327681, 5, 1966060, 327681, 5, 2031596, 262145, 5, 2097132, 327681, 5, 2162668, 262145, 5, 2228204, 327681, 5, 2293740, 393217, 5, 2359276, 327681, 5, 2424812, 393217, 5, 2490348, 262145, 5, 2555884, 262145, 5, 2621420, 458753, 5, 2686956, 327681, 5, 2752492, 262145, 5, 1507309, 458753, 5, 1572845, 262145, 5, 1638381, 393217, 5, 1703917, 262145, 5, 1769453, 262145, 5, 1834989, 458753, 5, 1900525, 393217, 5, 1966061, 458753, 5, 2031597, 393217, 5, 2097133, 393217, 5, 2162669, 393217, 5, 2228205, 458753, 5, 2293741, 393217, 5, 2359277, 458753, 5, 2424813, 262145, 5, 2490349, 458753, 5, 2555885, 458753, 5, 2621421, 262145, 5, 2686957, 458753, 5, 2752493, 393217, 5, 1507310, 327681, 5, 1572846, 393217, 5, 1638382, 327681, 5, 1703918, 458753, 5, 1769454, 458753, 5, 1834990, 393217, 5, 1900526, 327681, 5, 1966062, 458753, 5, 2031598, 262145, 5, 2097134, 393217, 5, 2162670, 262145, 5, 2228206, 327681, 5, 2293742, 393217, 5, 2359278, 262145, 5, 2424814, 327681, 5, 2490350, 262145, 5, 2555886, 393217, 5, 2621422, 327681, 5, 2686958, 262145, 5, 2752494, 327681, 5, 2818001, 458753, 5, 2883537, 262145, 4, 2949073, 393217, 5, 3014609, 327681, 5, 2818002, 65537, 2, 2883538, 262145, 5, 2949074, 458753, 4, 3014610, 327681, 5, 2818003, 458753, 4, 2883539, 458753, 5, 2949075, 262145, 4, 3014611, 458753, 5, 2818004, 458753, 5, 2883540, 393217, 5, 2949076, 262145, 4, 3014612, 458753, 4, 2818005, 262145, 5, 2883541, 327681, 5, 2949077, 458753, 5, 3014613, 262145, 5, 2818006, 262145, 5, 2883542, 393217, 5, 2949078, 262145, 5, 3014614, 262145, 5, 2818007, 327681, 5, 2883543, 327681, 5, 2949079, 262145, 5, 3014615, 262145, 5, 2818008, 262145, 5, 2883544, 262145, 5, 2949080, 393217, 5, 3014616, 393217, 5, 2818009, 393217, 5, 2883545, 327681, 5, 2949081, 327681, 5, 3014617, 262145, 5, 2818010, 458753, 5, 2883546, 327681, 5, 2949082, 327681, 5, 3014618, 393217, 5, 2818011, 327681, 5, 2883547, 393217, 5, 2949083, 458753, 5, 3014619, 327681, 5, 2818012, 262145, 5, 2883548, 458753, 5, 2949084, 393217, 5, 3014620, 262145, 5, 2818013, 393217, 5, 2883549, 458753, 5, 2949085, 262145, 5, 3014621, 458753, 5, 2818014, 327681, 5, 2883550, 262145, 5, 2949086, 327681, 5, 3014622, 393217, 5, 3342292, 262145, 5, 3407828, 458753, 2, 3473364, 393217, 5, 3538900, 458753, 4, 3604436, 262145, 5, 3342293, 262145, 5, 3407829, 458753, 4, 3473365, 393217, 5, 3538901, 262145, 5, 3604437, 458753, 5, 3342294, 393217, 5, 3407830, 458753, 2, 3473366, 262145, 5, 3538902, 262145, 4, 3604438, 327681, 4, 3342295, 327681, 5, 3407831, 393217, 5, 3473367, 262145, 5, 3538903, 393217, 5, 3604439, 327681, 4, 3342296, 327681, 5, 3407832, 393217, 5, 3473368, 262145, 5, 3538904, 327681, 5, 3604440, 327681, 5, 3342297, 262145, 5, 3407833, 327681, 5, 3473369, 458753, 2, 3538905, 393217, 5, 3604441, 458753, 5, 3342298, 262145, 5, 3407834, 458753, 5, 3473370, 458753, 5, 3538906, 262145, 5, 3604442, 458753, 5, 3342299, 327681, 5, 3407835, 262145, 5, 3473371, 262145, 5, 3538907, 262145, 5, 3604443, 393217, 5, 3342300, 393217, 5, 3407836, 327681, 5, 3342301, 458753, 5, 3407837, 327681, 5, 3342302, 262145, 5, 3407838, 327681, 5, 3342303, 393217, 5, 3407839, 262145, 5, 3342304, 262145, 5, 3407840, 327681, 5, 3342305, 327681, 5, 3407841, 327681, 5, 3342306, 393217, 5, 3407842, 262145, 5, 3342278, 262145, 5, 3342279, 393217, 5, 3407815, 393217, 5, 3342280, 458753, 5, 3407816, 262145, 5, 3473352, 458753, 5, 3342281, 262145, 5, 3407817, 262145, 5, 3473353, 458753, 5, 3538889, 327681, 5, 3342282, 327681, 5, 3407818, 393217, 5, 3473354, 393217, 5, 3538890, 393217, 5, 3604426, 393217, 5, 3342283, 393217, 5, 3407819, 262145, 5, 3473355, 262145, 5, 3538891, 393217, 5, 3604427, 458753, 5, 3669963, 458753, 5, 3342284, 393217, 5, 3407820, 393217, 5, 3473356, 262145, 5, 3538892, 458753, 5, 3604428, 393217, 5, 3669964, 458753, 5, 3735500, 262145, 5, 3801036, 393217, 5, 3342285, 458753, 5, 3407821, 458753, 5, 3473357, 262145, 5, 3538893, 262145, 5, 3604429, 262145, 5, 3669965, 458753, 5, 3735501, 262145, 5, 3801037, 458753, 5, 3866573, 327681, 5, 3342286, 458753, 5, 3407822, 327681, 5, 3473358, 393217, 5, 3538894, 262145, 5, 3604430, 458753, 5, 3669966, 458753, 5, 3735502, 393217, 5, 3801038, 393217, 5, 3866574, 458753, 5, 3342287, 327681, 5, 3407823, 327681, 5, 3473359, 262145, 5, 3538895, 393217, 5, 3604431, 262145, 5, 3669967, 327681, 5, 3735503, 393217, 5, 3801039, 262145, 5, 3866575, 393217, 5, 3342288, 458753, 5, 3407824, 393217, 5, 3473360, 327681, 5, 3538896, 458753, 5, 3604432, 393217, 5, 3669968, 458753, 5, 3735504, 262145, 5, 3801040, 262145, 5, 3866576, 393217, 5, 3342289, 327681, 5, 3407825, 458753, 5, 3473361, 327681, 5, 3538897, 327681, 5, 3604433, 327681, 5, 3669969, 458753, 5, 3735505, 393217, 5, 3801041, 327681, 5, 3866577, 262145, 5, 3342290, 262145, 5, 3407826, 262145, 5, 3473362, 393217, 5, 3538898, 327681, 5, 3604434, 458753, 5, 3669970, 458753, 5, 3735506, 458753, 5, 3801042, 327681, 5, 3866578, 327681, 5, 3342291, 393217, 5, 3407827, 393217, 5, 3473363, 458753, 2, 3538899, 393217, 5, 3604435, 327681, 5, 3669971, 458753, 5, 3735507, 327681, 5, 3801043, 262145, 5, 3866579, 262145, 5, 3669972, 327681, 5, 3735508, 262145, 5, 3801044, 327681, 5, 3866580, 327681, 5, 3932110, 458753, 5, 3932111, 393217, 5, 3932112, 393217, 5, 3997648, 458753, 5, 3932113, 327681, 5, 3997649, 458753, 5, 4063185, 458753, 5, 3932114, 458753, 5, 3997650, 458753, 5, 4063186, 458753, 5, 4128722, 458753, 5, 3932115, 262145, 5, 3997651, 458753, 5, 4063187, 262145, 5, 4128723, 458753, 5, 3932116, 393217, 5, 3997652, 458753, 5, 4063188, 262145, 5, 4128724, 393217, 5, 3669973, 458753, 5, 3735509, 393217, 5, 3801045, 458753, 5, 3866581, 458753, 5, 3932117, 262145, 5, 3997653, 262145, 5, 4063189, 458753, 5, 4128725, 262145, 5, 3669974, 262145, 5, 3735510, 262145, 5, 3801046, 393217, 5, 3866582, 327681, 5, 3932118, 393217, 5, 3997654, 458753, 5, 4063190, 262145, 5, 4128726, 458753, 5, 3669975, 393217, 5, 3735511, 458753, 5, 3801047, 393217, 5, 3866583, 262145, 5, 3932119, 262145, 5, 3997655, 458753, 5, 4063191, 458753, 5, 4128727, 393217, 5, 3669976, 327681, 5, 3735512, 327681, 5, 3801048, 327681, 5, 3866584, 327681, 5, 3932120, 327681, 5, 3997656, 393217, 5, 4063192, 458753, 5, 4128728, 393217, 5, 3669977, 393217, 5, 3735513, 327681, 5, 3801049, 262145, 5, 3866585, 393217, 5, 3932121, 262145, 5, 3997657, 262145, 5, 4063193, 327681, 5, 4128729, 262145, 5, 3669978, 262145, 5, 3735514, 262145, 5, 3801050, 393217, 5, 3866586, 393217, 5, 3932122, 458753, 5, 3997658, 458753, 5, 4063194, 262145, 5, 4128730, 393217, 5, 3669979, 262145, 5, 3735515, 327681, 4, 3801051, 393217, 5, 3866587, 393217, 5, 3932123, 262145, 5, 3997659, 327681, 5, 4063195, 327681, 5, 4128731, 327681, 5, 4194259, 327681, 5, 4194260, 458753, 5, 4259796, 458753, 5, 4194261, 458753, 5, 4259797, 458753, 5, 4325333, 393217, 5, 4194262, 327681, 5, 4259798, 262145, 5, 4325334, 327681, 5, 4390870, 458753, 5, 4194263, 458753, 5, 4259799, 458753, 5, 4325335, 262145, 5, 4390871, 262145, 5, 4456407, 393217, 5, 4194264, 327681, 5, 4259800, 393217, 5, 4325336, 262145, 5, 4390872, 393217, 5, 4456408, 393217, 5, 4521944, 262145, 5, 4194265, 393217, 5, 4259801, 458753, 5, 4325337, 327681, 5, 4390873, 393217, 5, 4456409, 458753, 5, 4521945, 458753, 5, 4194266, 327681, 5, 4259802, 327681, 5, 4325338, 393217, 5, 4390874, 393217, 5, 4456410, 393217, 5, 4521946, 327681, 5, 4194267, 327681, 5, 4259803, 393217, 5, 4325339, 327681, 5, 4390875, 262145, 5, 4456411, 393217, 5, 4521947, 262145, 5, 4587481, 458753, 5, 4587482, 327681, 5, 4653018, 393217, 5, 4587483, 262145, 5, 4653019, 458753, 5, 4718555, 262145, 5, 4915166, 393217, 5, 4915167, 458753, 5, 4980703, 262145, 5, 4915168, 458753, 5, 4980704, 262145, 5, 5046240, 262145, 5, 4915169, 393217, 5, 4980705, 262145, 5, 5046241, 458753, 5, 5111777, 458753, 5, 2293773, 262145, 5, 2359309, 458753, 4, 2293774, 262145, 5, 2359310, 262145, 5, 2293775, 393217, 5, 2359311, 458753, 2, 2293776, 393217, 5, 2359312, 327681, 5, 2293777, 327681, 5, 2359313, 327681, 4, 2293778, 393217, 5, 2359314, 327681, 5, 2293779, 458753, 5, 2359315, 327681, 4, 2228233, 262145, 5, 2228234, 262145, 5, 2228235, 393217, 5, 2228236, 327681, 5, 2228237, 458753, 5, 2424845, 262145, 4, 2228238, 327681, 5, 2424846, 327681, 2, 2228239, 262145, 5, 2424847, 393217, 5, 2228240, 458753, 5, 2424848, 458753, 5, 2228241, 458753, 5, 2424849, 262145, 5, 2228242, 393217, 5, 2424850, 262145, 4, 2228243, 262145, 5, 2424851, 262145, 4, 2228244, 458753, 5, 2293780, 458753, 5, 2359316, 262145, 4, 2424852, 327681, 5, 2228245, 262145, 5, 2293781, 262145, 5, 2359317, 458753, 5, 2424853, 393217, 5, 2228246, 393217, 5, 2293782, 393217, 5, 2359318, 458753, 5, 2424854, 458753, 5, 2228247, 262145, 5, 2293783, 262145, 5, 2359319, 458753, 5, 2424855, 327681, 5, 2228248, 262145, 5, 2293784, 262145, 5, 2359320, 262145, 5, 2424856, 393217, 5, 2490390, 458753, 5, 2555926, 262145, 5, 2621462, 393217, 5, 2686998, 393217, 5, 2752534, 327681, 5, 2818070, 262145, 4, 2883606, 458753, 5, 2949142, 327681, 4, 3014678, 262145, 5, 2490391, 393217, 5, 2555927, 327681, 5, 2621463, 458753, 5, 2686999, 393217, 5, 2752535, 393217, 5, 2818071, 458753, 5, 2883607, 262145, 5, 2949143, 327681, 4, 3014679, 327681, 4, 3080215, 327681, 5, 3145751, 262145, 5, 2490392, 393217, 5, 2555928, 458753, 5, 2621464, 458753, 5, 2687000, 458753, 5, 2752536, 458753, 5, 2818072, 327681, 5, 2883608, 458753, 5, 2949144, 327681, 5, 3014680, 262145, 5, 3080216, 458753, 5, 3145752, 327681, 5, 3014681, 393217, 5, 3080217, 393217, 5, 3145753, 262145, 5, 3014682, 327681, 5, 3080218, 327681, 5, 3145754, 327681, 5, 3014683, 458753, 5, 3080219, 327681, 5, 3145755, 393217, 5, 3014684, 393217, 5, 3080220, 327681, 5, 3145756, 262145, 4, 3014685, 458753, 5, 3080221, 327681, 5, 3014686, 393217, 5, 3080222, 262145, 5, 3014687, 458753, 5, 3080223, 458753, 2, 3014688, 393217, 5, 3080224, 262145, 4, 3014689, 458753, 5, 3080225, 393217, 5, 3014690, 393217, 5, 3080226, 458753, 5, 3014691, 393217, 5, 3080227, 262145, 5, 3014692, 327681, 5, 3080228, 327681, 5, 3145764, 262145, 5, 3211300, 458753, 2, 3276836, 458753, 5, 3342372, 327681, 5, 3407908, 327681, 5, 3014693, 327681, 4, 3080229, 262145, 4, 3145765, 458753, 5, 3211301, 393217, 5, 3276837, 196609, 2, 3342373, 458753, 5, 3407909, 262145, 5, 3014694, 458753, 2, 3080230, 65537, 2, 3145766, 327681, 4, 3211302, 327681, 5, 3276838, 262145, 5, 3342374, 262145, 5, 3407910, 327681, 5, 3014695, 327681, 2, 3080231, 458753, 2, 3145767, 327681, 5, 3211303, 262145, 5, 3276839, 327681, 4, 3342375, 458753, 5, 3407911, 458753, 5, 3014696, 458753, 5, 3080232, 458753, 4, 3145768, 393217, 5, 3211304, 458753, 4, 3276840, 262145, 5, 3342376, 393217, 5, 3407912, 393217, 5, 2228261, 458753, 5, 2293797, 393217, 5, 2359333, 327681, 5, 2424869, 458753, 5, 2490405, 458753, 5, 2555941, 458753, 5, 2621477, 327681, 5, 2687013, 393217, 5, 2752549, 393217, 5, 2818085, 327681, 5, 2883621, 262145, 5, 2949157, 458753, 5, 2228262, 327681, 5, 2293798, 327681, 5, 2359334, 327681, 5, 2424870, 327681, 5, 2490406, 327681, 5, 2555942, 327681, 5, 2621478, 327681, 5, 2687014, 393217, 5, 2752550, 458753, 5, 2818086, 327681, 5, 2883622, 393217, 5, 2949158, 327681, 5, 2228263, 393217, 5, 2293799, 458753, 5, 2359335, 458753, 5, 2424871, 327681, 5, 2490407, 458753, 5, 2555943, 458753, 5, 2621479, 262145, 5, 2687015, 327681, 5, 2752551, 393217, 5, 2818087, 393217, 5, 2883623, 458753, 5, 2949159, 458753, 5, 2228264, 327681, 5, 2293800, 393217, 5, 2359336, 262145, 5, 2424872, 393217, 5, 2490408, 458753, 5, 2555944, 458753, 5, 2621480, 327681, 5, 2687016, 327681, 5, 2752552, 458753, 5, 2818088, 327681, 5, 2883624, 262145, 5, 2949160, 327681, 5, 2228265, 262145, 5, 2293801, 327681, 5, 2359337, 458753, 5, 2424873, 327681, 5, 2228266, 458753, 5, 2293802, 327681, 5, 2359338, 327681, 5, 2424874, 393217, 5, 2228267, 327681, 5, 2293803, 393217, 5, 2359339, 458753, 5, 2424875, 327681, 5, 2228268, 393217, 5, 2293804, 458753, 5, 2359340, 262145, 5, 2424876, 327681, 5, 2228269, 262145, 5, 2293805, 327681, 5, 2359341, 458753, 5, 2424877, 393217, 5, 2228270, 458753, 5, 2293806, 262145, 5, 2359342, 393217, 5, 2424878, 327681, 5, 2228271, 393217, 5, 2293807, 458753, 5, 2359343, 327681, 5, 2424879, 327681, 5, 2228272, 327681, 5, 2293808, 262145, 5, 2359344, 327681, 5, 2424880, 393217, 5, 2228273, 262145, 5, 2293809, 393217, 5, 2359345, 262145, 5, 2424881, 393217, 5, 2228274, 393217, 5, 2293810, 327681, 5, 2359346, 327681, 5, 2424882, 393217, 5, 2228275, 458753, 5, 2293811, 393217, 5, 2359347, 458753, 5, 2424883, 393217, 5, 2228276, 262145, 5, 2293812, 262145, 5, 2359348, 327681, 5, 2424884, 262145, 5, 1703973, 262145, 5, 1769509, 262145, 5, 1835045, 327681, 5, 1900581, 393217, 5, 1703974, 327681, 5, 1769510, 393217, 5, 1835046, 262145, 5, 1900582, 262145, 5, 1703975, 458753, 5, 1769511, 327681, 5, 1835047, 327681, 5, 1900583, 327681, 5, 1703976, 262145, 5, 1769512, 327681, 5, 1835048, 458753, 5, 1900584, 262145, 5, 1703977, 458753, 5, 1769513, 262145, 5, 1835049, 262145, 5, 1900585, 327681, 5, 1703978, 262145, 5, 1769514, 458753, 5, 1835050, 458753, 5, 1900586, 327681, 5, 1703979, 262145, 5, 1769515, 393217, 5, 1835051, 458753, 5, 1900587, 393217, 5, 1703980, 262145, 5, 1769516, 458753, 5, 1835052, 327681, 5, 1900588, 262145, 5, 1703981, 393217, 5, 1769517, 262145, 5, 1835053, 262145, 5, 1900589, 262145, 5, 1703982, 458753, 5, 1769518, 458753, 5, 1835054, 393217, 5, 1900590, 327681, 5, 1703983, 262145, 5, 1769519, 458753, 5, 1835055, 327681, 5, 1900591, 458753, 5, 1703984, 393217, 5, 1769520, 327681, 5, 1835056, 393217, 5, 1900592, 262145, 5, 1703985, 262145, 5, 1769521, 458753, 5, 1835057, 262145, 5, 1900593, 327681, 5, 1703986, 327681, 5, 1769522, 327681, 5, 1835058, 262145, 5, 1900594, 327681, 5, 1703987, 393217, 5, 1769523, 458753, 5, 1835059, 262145, 5, 1900595, 458753, 5, 1703988, 393217, 5, 1769524, 327681, 5, 1835060, 262145, 5, 1900596, 458753, 5, 786469, 262145, 5, 852005, 262145, 4, 917541, 393217, 5, 983077, 327681, 4, 1048613, 131073, 2, 1114149, 458753, 4, 1179685, 393217, 5, 1245221, 458753, 5, 1310757, 458753, 5, 1376293, 327681, 5, 1441829, 393217, 5, 1507365, 393217, 5, 1572901, 393217, 5, 1638437, 327681, 5, 786470, 327681, 5, 852006, 393217, 5, 917542, 393217, 5, 983078, 458753, 4, 1048614, 393217, 5, 1114150, 327681, 4, 1179686, 458753, 5, 1245222, 393217, 5, 1310758, 327681, 5, 1376294, 327681, 5, 1441830, 393217, 5, 1507366, 393217, 5, 1572902, 458753, 5, 1638438, 393217, 5, 786471, 262145, 5, 852007, 458753, 4, 917543, 458753, 4, 983079, 458753, 4, 1048615, 458753, 5, 1114151, 458753, 4, 1179687, 327681, 5, 1245223, 262145, 5, 1310759, 393217, 5, 1376295, 393217, 5, 1441831, 393217, 5, 1507367, 458753, 5, 1572903, 262145, 5, 1638439, 458753, 5, 786472, 262145, 5, 852008, 393217, 5, 917544, 458753, 5, 983080, 458753, 4, 1048616, 327681, 4, 1114152, 458753, 2, 1179688, 458753, 5, 1245224, 458753, 5, 1310760, 393217, 5, 1376296, 327681, 5, 1441832, 393217, 5, 1507368, 262145, 5, 1572904, 393217, 5, 1638440, 262145, 5, 1114136, 327681, 5, 1114137, 393217, 5, 1114138, 393217, 5, 1114139, 393217, 5, 1114140, 262145, 5, 1114141, 458753, 5, 1114142, 458753, 5, 1114143, 262145, 5, 1114144, 458753, 5, 1114145, 393217, 5, 1048610, 393217, 5, 1114146, 458753, 5, 1048611, 327681, 5, 1114147, 327681, 5, 1048612, 327681, 5, 1114148, 262145, 5, 1179672, 327681, 5, 1245208, 458753, 5, 1769496, 393217, 5, 1835032, 458753, 5, 1900568, 393217, 5, 1703876, 327681, 5, 1769412, 327681, 5, 1834948, 393217, 5, 1900484, 262145, 5, 1966020, 262145, 5, 2031556, 327681, 5, 2097092, 327681, 5, 2162628, 393217, 5, 2228164, 393217, 5, 2293700, 262145, 4, 2359236, 458753, 4, 2424772, 327681, 2, 2490308, 262145, 5, 2555844, 327681, 5, 2621380, 327681, 2, 2686916, 458753, 2, 2752452, 458753, 2, 1703877, 458753, 5, 1769413, 393217, 5, 1834949, 262145, 5, 1900485, 262145, 5, 1966021, 458753, 5, 2031557, 327681, 5, 2097093, 327681, 5, 2162629, 327681, 5, 2228165, 327681, 5, 2293701, 327681, 6, 2359237, 327681, 6, 2424773, 393217, 6, 2490309, 262145, 6, 2555845, 458753, 6, 2621381, 327681, 5, 2686917, 327681, 4, 2752453, 196609, 6, 1703878, 393217, 5, 1769414, 458753, 5, 1834950, 262145, 5, 1900486, 458753, 5, 1966022, 327681, 5, 2031558, 458753, 5, 2097094, 393217, 5, 2162630, 458753, 5, 2228166, 327681, 5, 2293702, 327681, 6, 2359238, 458753, 6, 2424774, 327681, 6, 2490310, 393217, 6, 2555846, 262145, 6, 2621382, 1, 1, 2686918, 1, 1, 2752454, 327681, 6, 1703879, 262145, 5, 1769415, 262145, 5, 1834951, 458753, 5, 1900487, 327681, 5, 1966023, 327681, 5, 2031559, 458753, 5, 2097095, 393217, 5, 2162631, 327681, 5, 2228167, 393217, 5, 2293703, 262145, 5, 2359239, 1, 0, 2424775, 65537, 6, 2490311, 262145, 6, 2555847, 65537, 6, 2621383, 196609, 6, 2686919, 458753, 6, 2752455, 262145, 6, 1703880, 327681, 5, 1769416, 393217, 5, 1834952, 262145, 5, 1900488, 262145, 5, 1966024, 327681, 5, 2031560, 262145, 5, 2097096, 262145, 5, 2162632, 458753, 5, 2228168, 327681, 5, 2293704, 327681, 5, 2359240, 1, 0, 2424776, 1, 6, 2490312, 262145, 6, 2555848, 65537, 6, 2621384, 393217, 6, 2686920, 327681, 6, 2752456, 393217, 6, 1703881, 262145, 5, 1769417, 393217, 5, 1834953, 327681, 5, 1900489, 327681, 5, 1966025, 327681, 5, 2031561, 327681, 5, 2097097, 262145, 5, 2162633, 262145, 5, 2228169, 262145, 5, 2293705, 262145, 5, 2359241, 1, 0, 2424777, 262145, 6, 2490313, 262145, 6, 2555849, 65537, 6, 2621385, 65537, 6, 2686921, 262145, 6, 2752457, 327681, 6, 1703882, 458753, 5, 1769418, 327681, 5, 1834954, 393217, 5, 1900490, 393217, 5, 1966026, 393217, 5, 2031562, 262145, 5, 2097098, 458753, 5, 2162634, 327681, 5, 2228170, 327681, 5, 2293706, 393217, 5, 2359242, 458753, 2, 2424778, 262145, 6, 2490314, 131073, 6, 2555850, 327681, 6, 2621386, 65537, 6, 2686922, 458753, 6, 2752458, 262145, 6, 1703883, 262145, 5, 1769419, 327681, 5, 1834955, 458753, 5, 1900491, 458753, 4, 1966027, 393217, 5, 2031563, 327681, 5, 2097099, 458753, 5, 2162635, 262145, 5, 2228171, 458753, 5, 2293707, 458753, 5, 2359243, 458753, 2, 2424779, 262145, 5, 2490315, 131073, 6, 2555851, 327681, 6, 2621387, 393217, 6, 2686923, 393217, 6, 2752459, 458753, 5, 1703884, 393217, 5, 1769420, 327681, 5, 1834956, 458753, 5, 1900492, 393217, 5, 1966028, 262145, 5, 2031564, 458753, 5, 2097100, 393217, 5, 2162636, 262145, 5, 2228172, 458753, 5, 2293708, 458753, 5, 2359244, 262145, 5, 2424780, 393217, 5, 2490316, 393217, 5, 2555852, 393217, 5, 2621388, 262145, 5, 2686924, 327681, 5, 2752460, 393217, 5, 1703885, 327681, 5, 1769421, 458753, 5, 1834957, 393217, 5, 1900493, 262145, 5, 1966029, 327681, 5, 2031565, 393217, 5, 2097101, 458753, 5, 2162637, 393217, 5, 2228173, 262145, 5, 2293709, 458753, 5, 2359245, 393217, 2, 2424781, 393217, 5, 2490317, 262145, 5, 2555853, 393217, 5, 2621389, 393217, 5, 2686925, 262145, 5, 2752461, 327681, 5, 1703886, 327681, 5, 1769422, 327681, 5, 1834958, 458753, 5, 1900494, 262145, 5, 1966030, 458753, 5, 2031566, 262145, 5, 2097102, 458753, 5, 2162638, 393217, 5, 2228174, 262145, 5, 2293710, 393217, 5, 2359246, 458753, 4, 2424782, 458753, 4, 2490318, 327681, 5, 2555854, 262145, 5, 2621390, 393217, 5, 2686926, 327681, 4, 2752462, 458753, 2, 1703887, 393217, 5, 1769423, 327681, 5, 1834959, 458753, 5, 1900495, 393217, 5, 1966031, 393217, 5, 2031567, 262145, 4, 2097103, 327681, 5, 2162639, 262145, 4, 2228175, 262145, 4, 2293711, 458753, 5, 2359247, 458753, 4, 2424783, 262145, 4, 2490319, 393217, 5, 2555855, 458753, 5, 2621391, 327681, 5, 2686927, 262145, 4, 2752463, 262145, 5, 1703888, 262145, 5, 1769424, 327681, 5, 1834960, 327681, 5, 1900496, 393217, 5, 1966032, 458753, 5, 2031568, 458753, 5, 2097104, 327681, 5, 2162640, 327681, 5, 2228176, 262145, 5, 2293712, 262145, 5, 2359248, 262145, 5, 2424784, 327681, 5, 2490320, 393217, 5, 2555856, 327681, 5, 2621392, 327681, 5, 2686928, 393217, 5, 2752464, 262145, 5, 1703889, 327681, 4, 1769425, 458753, 5, 1834961, 262145, 5, 1900497, 327681, 5, 1966033, 327681, 5, 2031569, 327681, 5, 2097105, 327681, 5, 2162641, 262145, 5, 2228177, 262145, 5, 2293713, 262145, 5, 2359249, 262145, 5, 2424785, 393217, 5, 2490321, 327681, 5, 2555857, 327681, 5, 2621393, 458753, 5, 2686929, 393217, 5, 2752465, 262145, 5, 1703890, 262145, 5, 1769426, 458753, 5, 1834962, 393217, 5, 1900498, 327681, 5, 1966034, 393217, 5, 2031570, 458753, 5, 2097106, 327681, 5, 2162642, 262145, 5, 2228178, 327681, 5, 2293714, 327681, 5, 2359250, 393217, 5, 2424786, 393217, 5, 2490322, 262145, 5, 2555858, 393217, 5, 2621394, 393217, 5, 2686930, 458753, 5, 2752466, 458753, 5, 2817985, 393217, 5, 2883521, 262145, 5, 2949057, 327681, 5, 3014593, 458753, 5, 2817986, 458753, 5, 2883522, 327681, 5, 2949058, 262145, 5, 3014594, 458753, 5, 2817987, 262145, 5, 2883523, 393217, 5, 2949059, 327681, 5, 3014595, 327681, 5, 2817988, 327681, 5, 2883524, 262145, 5, 2949060, 327681, 5, 3014596, 393217, 5, 2817989, 458753, 5, 2883525, 458753, 5, 2949061, 393217, 5, 3014597, 262145, 5, 2817990, 393217, 5, 2883526, 458753, 5, 2949062, 327681, 5, 3014598, 327681, 5, 2817991, 196609, 0, 2883527, 262145, 5, 2949063, 393217, 5, 3014599, 327681, 5, 2817992, 65537, 0, 2883528, 327681, 5, 2949064, 327681, 5, 3014600, 327681, 5, 2817993, 327681, 5, 2883529, 393217, 5, 2949065, 327681, 5, 3014601, 393217, 5, 2817994, 262145, 5, 2883530, 458753, 5, 2949066, 393217, 5, 3014602, 262145, 5, 2817995, 327681, 5, 2883531, 458753, 5, 2949067, 262145, 5, 3014603, 327681, 5, 2817996, 458753, 5, 2883532, 393217, 5, 2949068, 262145, 5, 3014604, 393217, 5, 2817997, 393217, 5, 2883533, 393217, 5, 2949069, 393217, 5, 3014605, 458753, 5, 2817998, 458753, 4, 2883534, 458753, 4, 2949070, 393217, 2, 3014606, 262145, 5, 2817999, 458753, 5, 2883535, 262145, 4, 2949071, 327681, 5, 3014607, 393217, 5, 2818000, 327681, 5, 2883536, 458753, 4, 2949072, 262145, 5, 3014608, 393217, 5, 1245121, 458753, 5, 1310657, 393217, 5, 1376193, 262145, 5, 1441729, 262145, 5, 1507265, 393217, 5, 1572801, 458753, 5, 1638337, 458753, 5, 1703873, 262145, 5, 1769409, 262145, 5, 1834945, 458753, 4, 1900481, 262145, 4, 1966017, 458753, 2, 2031553, 262145, 5, 2097089, 458753, 2, 2162625, 65537, 2, 2228161, 458753, 5, 2293697, 458753, 2, 2359233, 262145, 5, 2424769, 458753, 5, 2490305, 262145, 4, 2555841, 327681, 4, 2621377, 458753, 5, 2686913, 393217, 5, 2752449, 458753, 5, 1245122, 458753, 5, 1310658, 327681, 5, 1376194, 393217, 5, 1441730, 458753, 5, 1507266, 327681, 5, 1572802, 262145, 5, 1638338, 262145, 5, 1703874, 393217, 5, 1769410, 458753, 5, 1834946, 327681, 5, 1900482, 458753, 2, 1966018, 458753, 2, 2031554, 458753, 4, 2097090, 458753, 4, 2162626, 327681, 5, 2228162, 458753, 2, 2293698, 458753, 2, 2359234, 458753, 2, 2424770, 262145, 4, 2490306, 393217, 5, 2555842, 262145, 5, 2621378, 458753, 5, 2686914, 458753, 5, 2752450, 327681, 5, 1245123, 393217, 5, 1310659, 327681, 5, 1376195, 458753, 5, 1441731, 327681, 5, 1507267, 393217, 5, 1572803, 458753, 5, 1638339, 262145, 5, 1703875, 327681, 5, 1769411, 327681, 5, 1834947, 458753, 5, 1900483, 327681, 5, 1966019, 393217, 5, 2031555, 393217, 5, 2097091, 393217, 5, 2162627, 262145, 4, 2228163, 458753, 5, 2293699, 327681, 5, 2359235, 327681, 5, 2424771, 458753, 4, 2490307, 458753, 5, 2555843, 393217, 5, 2621379, 458753, 5, 2686915, 1, 2, 2752451, 458753, 5, 1245124, 327681, 5, 1310660, 393217, 5, 1376196, 458753, 5, 1441732, 327681, 5, 1507268, 458753, 5, 1572804, 458753, 5, 1638340, 458753, 5, 1245125, 393217, 5, 1310661, 327681, 5, 1376197, 393217, 5, 1441733, 262145, 5, 1507269, 458753, 5, 1572805, 458753, 5, 1638341, 393217, 5, 1245126, 393217, 5, 1310662, 393217, 5, 1376198, 262145, 5, 1441734, 393217, 5, 1507270, 262145, 5, 1572806, 196609, 2, 1638342, 458753, 4, 1245127, 327681, 5, 1310663, 327681, 5, 1376199, 458753, 5, 1441735, 327681, 5, 1507271, 393217, 5, 1572807, 262145, 5, 1638343, 393217, 5, 1245128, 262145, 5, 1310664, 262145, 5, 1376200, 327681, 5, 1441736, 262145, 5, 1507272, 327681, 5, 1572808, 327681, 5, 1638344, 262145, 5, 1245129, 458753, 5, 1310665, 458753, 5, 1376201, 262145, 5, 1441737, 393217, 5, 1507273, 327681, 5, 1572809, 262145, 5, 1638345, 393217, 5, 1245130, 393217, 5, 1310666, 262145, 5, 1376202, 458753, 5, 1441738, 458753, 5, 1507274, 458753, 5, 1572810, 327681, 5, 1638346, 393217, 5, 1245131, 393217, 5, 1310667, 262145, 5, 1376203, 458753, 5, 1441739, 262145, 5, 1507275, 393217, 5, 1572811, 262145, 5, 1638347, 262145, 5, 1245132, 262145, 5, 1310668, 327681, 5, 1376204, 393217, 5, 1441740, 327681, 5, 1507276, 393217, 5, 1572812, 262145, 5, 1638348, 393217, 5, 1245133, 327681, 5, 1310669, 393217, 5, 1376205, 393217, 5, 1441741, 458753, 5, 1507277, 458753, 5, 1572813, 327681, 5, 1638349, 262145, 5, 1245134, 458753, 5, 1310670, 327681, 5, 1376206, 327681, 5, 1441742, 393217, 2, 1507278, 262145, 5, 1572814, 458753, 2, 1638350, 327681, 5, 1245135, 393217, 5, 1310671, 327681, 4, 1376207, 458753, 5, 1441743, 262145, 4, 1507279, 458753, 5, 1572815, 458753, 5, 1638351, 327681, 5, 1245136, 327681, 5, 1310672, 327681, 5, 1376208, 327681, 2, 1441744, 393217, 5, 1507280, 327681, 5, 1572816, 458753, 4, 1638352, 458753, 4, 1245137, 458753, 5, 1310673, 458753, 4, 1376209, 458753, 5, 1441745, 327681, 2, 1507281, 262145, 5, 1572817, 327681, 5, 1638353, 393217, 5, 1245138, 327681, 4, 1310674, 458753, 5, 1376210, 393217, 2, 1441746, 458753, 5, 1507282, 458753, 5, 1572818, 458753, 5, 1638354, 458753, 5, 1376211, 458753, 5, 1441747, 327681, 4, 1245140, 262145, 4, 1441748, 458753, 2, 1245141, 327681, 5, 1310677, 327681, 5, 1376213, 458753, 5, 1441749, 458753, 5, 1245142, 262145, 5, 1310678, 262145, 5, 1376214, 262145, 5, 1441750, 262145, 5, 1245143, 262145, 5, 1310679, 393217, 5, 1376215, 262145, 5, 1441751, 262145, 5, 1245144, 262145, 5, 1310680, 327681, 5, 1376216, 327681, 5, 1441752, 327681, 5, 1245145, 327681, 5, 1310681, 393217, 5, 1376217, 262145, 5, 1441753, 327681, 5, 1245146, 393217, 5, 1310682, 458753, 5, 1376218, 327681, 5, 1441754, 262145, 5, 1245147, 393217, 5, 1310683, 262145, 5, 1376219, 262145, 5, 1441755, 262145, 5, 1245148, 262145, 5, 1310684, 262145, 5, 1376220, 262145, 5, 1441756, 327681, 5, 1245149, 458753, 5, 1310685, 458753, 5, 1376221, 393217, 5, 1441757, 262145, 5, 1245150, 327681, 5, 1310686, 393217, 5, 1376222, 262145, 5, 1441758, 393217, 5, 655310, 458753, 5, 720846, 327681, 5, 786382, 262145, 5, 851918, 262145, 5, 917454, 327681, 5, 655311, 458753, 5, 720847, 327681, 5, 786383, 262145, 5, 851919, 327681, 5, 917455, 458753, 5, 655312, 393217, 5, 720848, 327681, 5, 786384, 327681, 5, 851920, 262145, 5, 917456, 393217, 5, 655313, 458753, 5, 720849, 327681, 5, 786385, 262145, 5, 851921, 327681, 5, 917457, 458753, 5, 655314, 393217, 5, 720850, 393217, 5, 786386, 327681, 5, 851922, 458753, 5, 917458, 393217, 5, 655315, 327681, 5, 720851, 327681, 5, 786387, 393217, 5, 851923, 458753, 5, 917459, 327681, 5, 655316, 393217, 5, 720852, 262145, 5, 786388, 458753, 5, 851924, 393217, 5, 917460, 262145, 5, 655317, 327681, 5, 720853, 262145, 5, 786389, 327681, 5, 851925, 262145, 5, 917461, 262145, 5, 655318, 458753, 5, 720854, 262145, 5, 786390, 458753, 5, 851926, 458753, 5, 917462, 458753, 5, 655319, 393217, 5, 720855, 458753, 5, 786391, 393217, 5, 851927, 262145, 5, 917463, 458753, 5, 655320, 327681, 4, 720856, 458753, 5, 786392, 327681, 5, 851928, 262145, 5, 917464, 458753, 5, 655321, 327681, 4, 720857, 393217, 5, 786393, 458753, 5, 851929, 327681, 5, 917465, 458753, 5, 655322, 327681, 5, 720858, 327681, 5, 786394, 458753, 5, 851930, 262145, 5, 917466, 262145, 5, 655323, 327681, 5, 720859, 262145, 5, 786395, 262145, 5, 851931, 327681, 5, 917467, 393217, 5, 786396, 458753, 5, 851932, 327681, 5, 917468, 458753, 5, 786397, 327681, 5, 851933, 393217, 5, 917469, 327681, 5, 786398, 393217, 5, 851934, 393217, 5, 917470, 327681, 5, 786399, 458753, 5, 851935, 393217, 5, 917471, 262145, 5, 786400, 327681, 5, 851936, 327681, 5, 917472, 262145, 5, 786401, 393217, 5, 851937, 327681, 5, 917473, 262145, 5, 786402, 262145, 5, 851938, 262145, 5, 917474, 458753, 5, 786403, 393217, 5, 851939, 458753, 5, 786404, 393217, 5, 851940, 262145, 5, 589762, 262145, 5, 655298, 262145, 5, 720834, 393217, 5, 786370, 327681, 5, 851906, 262145, 5, 917442, 393217, 5, 589763, 327681, 5, 655299, 393217, 5, 720835, 393217, 5, 786371, 458753, 5, 851907, 393217, 5, 917443, 458753, 5, 589764, 458753, 5, 655300, 393217, 5, 720836, 262145, 5, 786372, 262145, 5, 851908, 393217, 5, 917444, 458753, 5, 589765, 262145, 5, 655301, 262145, 5, 720837, 262145, 5, 786373, 458753, 5, 851909, 458753, 5, 917445, 327681, 5, 589766, 327681, 5, 655302, 327681, 5, 720838, 262145, 5, 786374, 327681, 5, 851910, 327681, 5, 917446, 393217, 5, 589767, 458753, 5, 655303, 262145, 5, 720839, 458753, 5, 786375, 327681, 5, 851911, 327681, 5, 917447, 393217, 5, 589768, 393217, 5, 655304, 262145, 5, 720840, 262145, 5, 786376, 393217, 5, 851912, 327681, 5, 917448, 393217, 5, 589769, 327681, 5, 655305, 262145, 5, 720841, 327681, 5, 786377, 458753, 5, 851913, 458753, 5, 917449, 327681, 5, 589770, 327681, 5, 655306, 327681, 5, 720842, 458753, 5, 786378, 327681, 5, 851914, 327681, 5, 917450, 458753, 5, 589771, 393217, 5, 655307, 458753, 5, 720843, 327681, 5, 786379, 458753, 5, 851915, 393217, 5, 917451, 458753, 5, 589772, 327681, 5, 655308, 262145, 5, 720844, 458753, 5, 786380, 458753, 5, 851916, 327681, 5, 917452, 327681, 5, 589773, 393217, 5, 655309, 393217, 5, 720845, 393217, 5, 786381, 327681, 5, 851917, 327681, 5, 917453, 327681, 5, 589774, 327681, 5, 196553, 262145, 5, 262089, 393217, 5, 327625, 458753, 5, 393161, 327681, 5, 458697, 327681, 5, 524233, 393217, 5, 131018, 327681, 5, 196554, 393217, 5, 262090, 458753, 5, 327626, 393217, 5, 393162, 393217, 5, 458698, 458753, 5, 524234, 262145, 5, 65483, 327681, 5, 131019, 327681, 5, 196555, 262145, 5, 262091, 458753, 5, 327627, 458753, 5, 393163, 393217, 5, 458699, 327681, 5, 524235, 393217, 5, -52, 327681, 5, 65484, 393217, 5, 131020, 262145, 5, 196556, 458753, 5, 262092, 262145, 5, 327628, 393217, 5, 393164, 458753, 5, 458700, 458753, 5, 524236, 327681, 5, -65587, 393217, 5, -51, 327681, 5, 65485, 262145, 5, 131021, 262145, 5, 196557, 458753, 5, 262093, 262145, 5, 327629, 327681, 5, 393165, 393217, 5, 458701, 262145, 5, 524237, 262145, 5, -131122, 393217, 5, -65586, 393217, 5, -50, 458753, 5, 65486, 262145, 5, 131022, 393217, 5, 196558, 327681, 5, 262094, 262145, 5, 327630, 393217, 5, 393166, 262145, 5, 458702, 458753, 5, 524238, 458753, 5, -196657, 458753, 5, -131121, 262145, 5, -65585, 393217, 5, -49, 262145, 5, 65487, 458753, 5, 131023, 458753, 5, 196559, 262145, 5, 262095, 262145, 5, 327631, 393217, 5, 393167, 262145, 5, 458703, 393217, 5, 524239, 327681, 5, 589775, 262145, 5, -262192, 458753, 5, -196656, 458753, 5, -131120, 458753, 5, -65584, 393217, 5, -48, 262145, 5, 65488, 327681, 5, 131024, 458753, 5, 196560, 393217, 5, 262096, 393217, 5, 327632, 393217, 5, 393168, 393217, 5, 458704, 327681, 5, 524240, 327681, 5, 589776, 327681, 5, -327727, 458753, 5, -262191, 393217, 5, -196655, 262145, 5, -131119, 262145, 5, -65583, 458753, 5, -47, 262145, 5, 65489, 458753, 5, 131025, 327681, 5, 196561, 393217, 5, 262097, 327681, 5, 327633, 327681, 5, 393169, 458753, 5, 458705, 262145, 5, 524241, 458753, 5, 589777, 327681, 5, -393262, 458753, 5, -327726, 458753, 5, -262190, 458753, 5, -196654, 327681, 5, -131118, 458753, 5, -65582, 262145, 5, -46, 327681, 5, 65490, 327681, 5, 131026, 327681, 5, 196562, 458753, 5, 262098, 458753, 5, 327634, 393217, 5, 393170, 262145, 5, 458706, 458753, 5, 524242, 327681, 5, 589778, 458753, 5, -458797, 327681, 5, -393261, 393217, 5, -327725, 458753, 5, -262189, 458753, 5, -196653, 262145, 5, -131117, 262145, 5, -65581, 458753, 5, -45, 262145, 5, 65491, 262145, 5, 131027, 327681, 5, 196563, 393217, 5, 262099, 262145, 5, 327635, 458753, 5, 393171, 458753, 5, 458707, 262145, 5, 524243, 393217, 5, 589779, 262145, 5, -458796, 327681, 5, -393260, 393217, 5, -327724, 262145, 5, -262188, 262145, 5, -196652, 327681, 5, -131116, 327681, 5, -65580, 393217, 5, -44, 458753, 5, 65492, 262145, 5, 131028, 393217, 5, 196564, 458753, 5, 262100, 327681, 5, 327636, 458753, 5, 393172, 458753, 5, 458708, 262145, 5, 524244, 262145, 5, 589780, 458753, 5, -458795, 393217, 5, -393259, 262145, 5, -327723, 262145, 5, -262187, 262145, 5, -196651, 458753, 5, -131115, 458753, 5, -65579, 327681, 5, -43, 262145, 5, 65493, 458753, 5, 131029, 458753, 5, 196565, 327681, 5, 262101, 458753, 5, 327637, 458753, 5, 393173, 458753, 5, 458709, 327681, 5, 524245, 262145, 5, 589781, 458753, 5, -524330, 458753, 5, -458794, 262145, 5, -393258, 262145, 5, -327722, 262145, 5, -262186, 393217, 5, -196650, 458753, 5, -131114, 458753, 5, -65578, 458753, 5, -42, 458753, 5, 65494, 262145, 5, 131030, 327681, 5, 196566, 393217, 5, 262102, 327681, 5, 327638, 458753, 5, 393174, 327681, 5, 458710, 393217, 5, 524246, 458753, 5, 589782, 393217, 5, -589865, 262145, 5, -524329, 327681, 5, -458793, 393217, 5, -393257, 327681, 5, -327721, 327681, 5, -262185, 327681, 5, -196649, 458753, 5, -131113, 327681, 5, -65577, 458753, 5, -41, 393217, 5, 65495, 458753, 5, 131031, 393217, 5, 196567, 327681, 5, 262103, 458753, 5, 327639, 327681, 5, 393175, 262145, 5, 458711, 458753, 5, 524247, 327681, 4, 589783, 65537, 2, -655400, 327681, 5, -589864, 458753, 5, -524328, 327681, 5, -458792, 458753, 5, -393256, 262145, 5, -327720, 458753, 5, -262184, 393217, 5, -196648, 327681, 5, -131112, 393217, 5, -65576, 262145, 5, -40, 393217, 5, 65496, 262145, 5, 131032, 458753, 5, 196568, 458753, 5, 262104, 393217, 5, 327640, 262145, 5, 393176, 327681, 5, 458712, 327681, 5, 524248, 393217, 5, 589784, 458753, 4, -720935, 262145, 5, -655399, 262145, 5, -589863, 458753, 5, -524327, 393217, 5, -458791, 262145, 5, -393255, 393217, 5, -327719, 393217, 5, -262183, 262145, 5, -196647, 393217, 5, -131111, 393217, 5, -65575, 458753, 5, -39, 393217, 5, 65497, 327681, 5, 131033, 458753, 5, 196569, 458753, 5, 262105, 458753, 5, 327641, 458753, 5, 393177, 262145, 5, 458713, 458753, 5, 524249, 262145, 4, 589785, 458753, 5, -786470, 262145, 5, -720934, 262145, 5, -655398, 458753, 5, -589862, 327681, 5, -524326, 262145, 5, -458790, 262145, 5, -393254, 458753, 5, -327718, 262145, 5, -262182, 393217, 5, -196646, 262145, 5, -131110, 458753, 5, -65574, 393217, 5, -38, 393217, 5, 65498, 327681, 5, 131034, 262145, 5, 196570, 393217, 5, 262106, 393217, 5, 327642, 458753, 5, 393178, 393217, 5, 458714, 458753, 5, 524250, 458753, 4, 589786, 393217, 5, -852005, 393217, 5, -786469, 458753, 5, -720933, 393217, 5, -655397, 393217, 5, -589861, 458753, 5, -524325, 393217, 5, -458789, 262145, 5, -393253, 458753, 5, -327717, 458753, 5, -262181, 393217, 5, -196645, 393217, 5, -131109, 262145, 5, -65573, 393217, 5, -37, 327681, 5, 65499, 327681, 5, 131035, 327681, 5, 196571, 393217, 5, 262107, 393217, 5, 327643, 458753, 5, 393179, 327681, 5, 458715, 393217, 5, 524251, 262145, 5, 589787, 458753, 5, 1179693, 458753, 5, 1245229, 458753, 5, 1310765, 262145, 5, 1376301, 327681, 5, 1179694, 393217, 5, 1245230, 458753, 5, 1310766, 458753, 5, 1376302, 262145, 5, 1179695, 458753, 5, 1245231, 262145, 5, 1310767, 262145, 5, 1376303, 393217, 5, 1179696, 262145, 5, 1245232, 327681, 5, 1310768, 393217, 5, 1376304, 262145, 5, 1179697, 458753, 5, 1245233, 262145, 5, 1310769, 327681, 5, 1376305, 393217, 5, 1179698, 262145, 5, 1245234, 393217, 5, 1310770, 327681, 5, 1376306, 393217, 5, 1179699, 327681, 5, 1245235, 262145, 5, 1310771, 393217, 5, 1376307, 327681, 5, 1179700, 393217, 5, 1245236, 262145, 5, 1310772, 458753, 5, 1376308, 458753, 5, 1179701, 262145, 5, 1245237, 262145, 5, 1310773, 327681, 5, 1376309, 393217, 5, 1179702, 327681, 5, 1245238, 393217, 5, 1310774, 458753, 5, 1376310, 393217, 5, 1179703, 458753, 4, 1245239, 327681, 5, 1310775, 458753, 2, 1376311, 458753, 5, 1179704, 327681, 4, 1245240, 458753, 4, 1310776, 262145, 4, 1376312, 458753, 5, 1179705, 393217, 5, 1245241, 327681, 4, 1310777, 327681, 5, 1376313, 262145, 4, 1441849, 458753, 5, 1507385, 458753, 5, 1572921, 262145, 5, 1638457, 262145, 5, 1703993, 262145, 5, 1769529, 458753, 5, 1835065, 262145, 5, 1179706, 327681, 5, 1245242, 262145, 2, 1310778, 262145, 5, 1376314, 262145, 4, 1441850, 458753, 5, 1507386, 327681, 5, 1572922, 393217, 5, 1638458, 458753, 5, 1703994, 458753, 5, 1769530, 262145, 5, 1835066, 458753, 5, 1179707, 262145, 5, 1245243, 327681, 5, 1310779, 458753, 5, 1376315, 327681, 5, 1441851, 1, 2, 1507387, 327681, 5, 1572923, 327681, 5, 1638459, 393217, 5, 1703995, 262145, 5, 1769531, 458753, 5, 1835067, 262145, 5, 1179708, 393217, 5, 1245244, 393217, 5, 1310780, 393217, 5, 1376316, 327681, 5, 1441852, 327681, 4, 1507388, 458753, 5, 1572924, 393217, 5, 1638460, 393217, 5, 1703996, 458753, 5, 1769532, 393217, 5, 1835068, 327681, 5, 1900601, 458753, 5, 1966137, 458753, 5, 2031673, 458753, 5, 2097209, 393217, 5, 2162745, 393217, 5, 2228281, 458753, 5, 2293817, 262145, 5, 2359353, 327681, 5, 2424889, 458753, 5, 2490425, 458753, 5, 2555961, 458753, 5, 2621497, 458753, 5, 2687033, 458753, 5, 2752569, 262145, 5, 2818105, 393217, 5, 2883641, 262145, 4, 2949177, 262145, 4, 1900602, 393217, 5, 1966138, 262145, 5, 2031674, 327681, 5, 2097210, 327681, 5, 2162746, 393217, 5, 2228282, 262145, 5, 2293818, 262145, 5, 2359354, 262145, 5, 2424890, 393217, 5, 2490426, 327681, 5, 2555962, 393217, 5, 2621498, 393217, 5, 2687034, 327681, 5, 2752570, 1, 2, 2818106, 262145, 5, 2883642, 458753, 4, 2949178, 262145, 5, 1900603, 393217, 5, 1966139, 393217, 5, 2031675, 458753, 5, 2097211, 262145, 5, 2162747, 393217, 5, 2228283, 262145, 5, 2293819, 458753, 5, 2359355, 327681, 5, 2424891, 458753, 5, 2490427, 393217, 5, 2555963, 262145, 5, 2621499, 458753, 5, 2687035, 262145, 5, 2752571, 458753, 4, 2818107, 458753, 5, 2883643, 262145, 4, 2949179, 327681, 5, 1900604, 458753, 5, 1966140, 327681, 5, 2031676, 327681, 5, 2097212, 327681, 5, 2162748, 393217, 5, 2228284, 458753, 5, 2293820, 262145, 5, 2359356, 327681, 5, 2424892, 327681, 5, 2490428, 327681, 5, 2555964, 458753, 5, 2621500, 262145, 5, 2687036, 327681, 5, 2752572, 458753, 5, 2818108, 393217, 5, 2883644, 393217, 2, 2949180, 327681, 5, 1900605, 327681, 5, 1966141, 327681, 5, 2031677, 393217, 5, 2097213, 327681, 5, 2162749, 393217, 5, 2228285, 458753, 5, 2293821, 458753, 5, 2359357, 393217, 5, 2424893, 393217, 5, 2490429, 262145, 5, 2555965, 262145, 5, 2621501, 458753, 5, 2687037, 393217, 5, 2752573, 393217, 5, 2818109, 393217, 4, 2883645, 262145, 5, 2949181, 458753, 5, 2752557, 327681, 5, 2818093, 262145, 5, 2883629, 262145, 5, 2949165, 458753, 5, 2752558, 327681, 5, 2818094, 458753, 5, 2883630, 458753, 5, 2949166, 393217, 5, 2752559, 262145, 5, 2818095, 393217, 5, 2883631, 262145, 5, 2949167, 327681, 5, 2752560, 262145, 5, 2818096, 327681, 5, 2883632, 458753, 5, 2949168, 327681, 5, 2752561, 327681, 5, 2818097, 262145, 5, 2883633, 393217, 5, 2949169, 327681, 5, 2752562, 458753, 5, 2818098, 458753, 5, 2883634, 393217, 5, 2949170, 393217, 5, 2752563, 327681, 5, 2818099, 393217, 5, 2883635, 393217, 5, 2949171, 262145, 5, 2752564, 262145, 5, 2818100, 458753, 5, 2883636, 458753, 5, 2949172, 393217, 5, 2752565, 262145, 5, 2818101, 393217, 5, 2883637, 262145, 5, 2949173, 458753, 5, 2752566, 327681, 5, 2818102, 327681, 5, 2883638, 393217, 5, 2949174, 262145, 5, 2752567, 458753, 2, 2818103, 65537, 2, 2883639, 458753, 2, 2949175, 393217, 5, 2752568, 327681, 4, 2818104, 327681, 4, 2883640, 327681, 5, 2949176, 262145, 2, 3276841, 262145, 5, 3342377, 262145, 5, 3407913, 262145, 5, 3276842, 458753, 5, 3342378, 327681, 5, 3407914, 458753, 5, 3276843, 458753, 5, 3342379, 327681, 5, 3407915, 327681, 5, 3276844, 393217, 5, 3342380, 458753, 5, 3407916, 458753, 5, 3276845, 393217, 5, 3342381, 327681, 5, 3407917, 393217, 5, 3276846, 458753, 5, 3342382, 327681, 5, 3407918, 262145, 5, 3276847, 327681, 5, 3342383, 458753, 5, 3407919, 327681, 5, 3276848, 327681, 5, 3342384, 458753, 4, 3407920, 458753, 5, 3276849, 262145, 5, 3342385, 262145, 5, 3407921, 393217, 5, 3276850, 393217, 5, 3342386, 393217, 5, 3407922, 262145, 5, 3276851, 262145, 5, 3342387, 458753, 5, 3407923, 458753, 5, 3473459, 262145, 4, 3538995, 458753, 5, 3604531, 458753, 5, 3670067, 393217, 5, 3276852, 327681, 5, 3342388, 393217, 5, 3407924, 327681, 5, 3473460, 458753, 5, 3538996, 458753, 5, 3604532, 327681, 5, 3670068, 393217, 5, 3276853, 458753, 5, 3342389, 458753, 5, 3407925, 458753, 5, 3473461, 393217, 5, 3538997, 458753, 5, 3604533, 327681, 5, 3670069, 458753, 5, 3276854, 458753, 5, 3342390, 327681, 5, 3407926, 327681, 5, 3473462, 327681, 5, 3538998, 393217, 5, 3604534, 327681, 5, 3670070, 327681, 5, 3276855, 262145, 5, 3342391, 327681, 5, 3407927, 458753, 5, 3473463, 327681, 5, 3538999, 327681, 5, 3604535, 458753, 5, 3670071, 458753, 5, 3276856, 393217, 5, 3342392, 393217, 5, 3407928, 458753, 5, 3473464, 393217, 5, 3539000, 393217, 5, 3604536, 262145, 5, 3670072, 327681, 5, 3276857, 393217, 5, 3342393, 458753, 5, 3407929, 458753, 5, 3473465, 327681, 5, 3539001, 393217, 5, 3604537, 262145, 5, 3670073, 262145, 5, 3276858, 393217, 5, 3342394, 393217, 5, 3407930, 393217, 5, 3473466, 393217, 5, 3539002, 458753, 5, 3604538, 458753, 5, 3670074, 458753, 5, 3276859, 327681, 5, 3342395, 458753, 5, 3407931, 458753, 5, 3473467, 262145, 5, 3539003, 262145, 5, 3604539, 393217, 5, 3670075, 458753, 5, 3276860, 393217, 5, 3342396, 262145, 5, 3407932, 458753, 5, 3473468, 262145, 5, 3539004, 393217, 5, 3604540, 262145, 5, 3670076, 393217, 5, 3276861, 458753, 5, 3342397, 393217, 5, 3407933, 458753, 5, 3473469, 327681, 5, 3539005, 458753, 5, 3604541, 458753, 5, 3670077, 327681, 5, 3276862, 458753, 5, 3342398, 458753, 5, 3407934, 393217, 5, 3473470, 262145, 5, 3539006, 393217, 5, 3604542, 262145, 5, 3670078, 393217, 5, 3276863, 458753, 5, 3342399, 327681, 5, 3407935, 262145, 5, 3473471, 327681, 5, 3539007, 393217, 5, 3604543, 393217, 5, 3670079, 262145, 5, 3276864, 327681, 5, 3342400, 327681, 5, 3407936, 458753, 5, 3473472, 458753, 5, 3539008, 393217, 5, 3604544, 262145, 5, 3670080, 327681, 5, 3276865, 458753, 5, 3342401, 393217, 5, 3407937, 458753, 5, 3473473, 262145, 5, 3539009, 393217, 5, 3604545, 327681, 5, 3670081, 393217, 5, 3276866, 327681, 5, 3342402, 458753, 5, 3407938, 262145, 5, 3473474, 458753, 5, 3539010, 327681, 5, 3604546, 327681, 5, 3670082, 393217, 5, 3276867, 458753, 5, 3342403, 262145, 5, 3407939, 393217, 5, 3473475, 393217, 5, 3539011, 393217, 5, 3604547, 458753, 5, 3670083, 458753, 5, 3276868, 393217, 5, 3342404, 393217, 5, 3407940, 262145, 5, 3473476, 262145, 5, 3539012, 393217, 5, 3604548, 458753, 5, 3670084, 393217, 5, 3276869, 327681, 5, 3342405, 393217, 5, 3407941, 327681, 5, 3473477, 327681, 5, 3539013, 327681, 5, 3604549, 393217, 5, 3670085, 327681, 5, 3276870, 262145, 5, 3342406, 262145, 5, 3407942, 458753, 5, 3473478, 327681, 5, 3539014, 327681, 5, 3604550, 458753, 5, 3670086, 458753, 5, 3276871, 327681, 5, 3342407, 327681, 5, 3407943, 458753, 5, 3473479, 458753, 5, 3539015, 393217, 5, 3604551, 262145, 5, 3670087, 393217, 5, 3276872, 393217, 5, 3342408, 327681, 5, 3407944, 262145, 5, 3473480, 262145, 5, 3539016, 393217, 5, 3604552, 458753, 5, 3670088, 458753, 5, 3276873, 393217, 5, 3342409, 393217, 5, 3407945, 458753, 5, 3473481, 458753, 5, 3539017, 262145, 5, 3604553, 393217, 5, 3670089, 458753, 5, 3276874, 458753, 5, 3342410, 458753, 5, 3407946, 458753, 5, 3473482, 393217, 5, 3539018, 262145, 5, 3604554, 393217, 5, 3670090, 262145, 5, 3276875, 393217, 5, 3342411, 327681, 5, 3407947, 327681, 5, 3473483, 327681, 5, 3539019, 327681, 5, 3604555, 327681, 5, 3670091, 327681, 5, 3735603, 262145, 5, 3801139, 262145, 5, 3866675, 393217, 5, 3932211, 393217, 5, 3997747, 327681, 5, 4063283, 327681, 5, 4128819, 393217, 5, 4194355, 393217, 5, 4259891, 393217, 5, 4325427, 393217, 5, 4390963, 262145, 5, 4456499, 327681, 5, 4522035, 458753, 5, 4587571, 327681, 5, 4653107, 458753, 5, 4718643, 262145, 5, 4784179, 262145, 5, 4849715, 262145, 5, 4915251, 458753, 5, 4980787, 458753, 5, 5046323, 393217, 5, 5111859, 327681, 5, 3735604, 327681, 5, 3801140, 262145, 5, 3866676, 393217, 5, 3932212, 458753, 5, 3997748, 393217, 5, 4063284, 262145, 5, 4128820, 262145, 5, 4194356, 262145, 5, 4259892, 458753, 5, 4325428, 458753, 5, 4390964, 327681, 5, 4456500, 458753, 5, 4522036, 327681, 5, 4587572, 262145, 5, 4653108, 458753, 5, 4718644, 458753, 5, 4784180, 262145, 5, 4849716, 327681, 5, 4915252, 262145, 5, 4980788, 393217, 5, 5046324, 393217, 5, 5111860, 327681, 5, 3735605, 327681, 5, 3801141, 262145, 5, 3866677, 262145, 5, 3932213, 393217, 5, 3997749, 393217, 5, 4063285, 327681, 5, 4128821, 393217, 5, 4194357, 327681, 5, 4259893, 327681, 5, 4325429, 327681, 5, 4390965, 393217, 5, 4456501, 262145, 5, 4522037, 393217, 5, 4587573, 327681, 5, 4653109, 393217, 5, 4718645, 458753, 5, 4784181, 393217, 5, 4849717, 458753, 5, 4915253, 262145, 5, 4980789, 262145, 5, 5046325, 262145, 5, 3735606, 458753, 5, 3801142, 327681, 5, 3866678, 262145, 5, 3932214, 327681, 5, 3997750, 327681, 5, 4063286, 458753, 5, 4128822, 262145, 5, 4194358, 262145, 5, 4259894, 393217, 5, 4325430, 327681, 5, 4390966, 393217, 5, 4456502, 262145, 5, 4522038, 458753, 5, 4587574, 458753, 5, 4653110, 458753, 5, 4718646, 327681, 5, 4784182, 393217, 5, 4849718, 393217, 5, 4915254, 393217, 5, 4980790, 262145, 5, 3735607, 262145, 5, 3801143, 393217, 5, 3866679, 262145, 5, 3932215, 262145, 5, 3997751, 393217, 5, 4063287, 327681, 5, 4128823, 458753, 5, 4194359, 327681, 5, 4259895, 262145, 5, 4325431, 262145, 5, 4390967, 458753, 5, 4456503, 262145, 5, 4522039, 393217, 5, 4587575, 262145, 5, 4653111, 262145, 5, 4718647, 458753, 5, 4784183, 393217, 5, 4849719, 327681, 5, 4915255, 262145, 5, 3735608, 262145, 5, 3801144, 458753, 5, 3866680, 393217, 5, 3932216, 262145, 5, 3997752, 262145, 5, 4063288, 262145, 5, 4128824, 393217, 5, 4194360, 327681, 5, 4259896, 393217, 5, 4325432, 458753, 5, 4390968, 327681, 5, 4456504, 327681, 5, 4522040, 393217, 5, 4587576, 458753, 5, 4653112, 458753, 5, 4718648, 458753, 5, 4784184, 262145, 5, 4849720, 327681, 5, 3735609, 262145, 5, 3801145, 262145, 5, 3866681, 393217, 5, 3932217, 327681, 5, 3997753, 458753, 5, 4063289, 393217, 5, 4128825, 458753, 5, 4194361, 262145, 5, 4259897, 327681, 5, 4325433, 393217, 5, 4390969, 458753, 5, 4456505, 458753, 5, 4522041, 458753, 5, 4587577, 327681, 5, 4653113, 458753, 5, 4718649, 458753, 5, 4784185, 262145, 5, 3735610, 393217, 5, 3801146, 458753, 5, 3866682, 262145, 5, 3932218, 327681, 5, 3997754, 262145, 5, 4063290, 262145, 5, 4128826, 327681, 5, 4194362, 458753, 5, 4259898, 262145, 5, 4325434, 262145, 5, 4390970, 458753, 5, 4456506, 458753, 5, 4522042, 327681, 5, 4587578, 393217, 5, 4653114, 327681, 5, 4718650, 458753, 5, 3735611, 262145, 5, 3801147, 262145, 5, 3866683, 458753, 5, 3932219, 393217, 5, 3997755, 262145, 5, 4063291, 393217, 5, 4128827, 458753, 5, 4194363, 458753, 5, 4259899, 458753, 5, 4325435, 327681, 5, 4390971, 393217, 5, 4456507, 262145, 5, 4522043, 458753, 5, 4587579, 327681, 5, 4653115, 458753, 5, 3735612, 393217, 5, 3801148, 327681, 5, 3866684, 458753, 5, 3932220, 458753, 5, 3997756, 327681, 5, 4063292, 262145, 5, 4128828, 458753, 5, 4194364, 327681, 5, 4259900, 393217, 5, 4325436, 262145, 5, 4390972, 458753, 5, 4456508, 262145, 5, 4522044, 262145, 5, 4587580, 327681, 5, 3735613, 262145, 5, 3801149, 458753, 5, 3866685, 327681, 5, 3932221, 262145, 5, 3997757, 393217, 5, 4063293, 262145, 5, 4128829, 393217, 5, 4194365, 262145, 5, 4259901, 327681, 5, 4325437, 327681, 5, 4390973, 262145, 5, 4456509, 393217, 5, 4522045, 327681, 5, 3735614, 393217, 5, 3801150, 458753, 5, 3866686, 327681, 5, 3932222, 458753, 5, 3997758, 393217, 5, 4063294, 393217, 5, 4128830, 262145, 5, 4194366, 393217, 5, 4259902, 393217, 5, 4325438, 458753, 5, 4390974, 327681, 5, 4456510, 458753, 5, 4522046, 327681, 5, 3735615, 262145, 5, 3801151, 458753, 5, 3866687, 458753, 5, 3932223, 393217, 5, 3997759, 458753, 5, 4063295, 262145, 5, 4128831, 262145, 5, 4194367, 458753, 5, 4259903, 327681, 5, 4325439, 393217, 5, 4390975, 327681, 5, 4456511, 262145, 5, 3735616, 393217, 5, 3801152, 393217, 5, 3866688, 327681, 5, 3932224, 458753, 5, 3997760, 393217, 5, 4063296, 327681, 5, 4128832, 262145, 5, 4194368, 327681, 5, 4259904, 393217, 5, 4325440, 327681, 5, 4390976, 327681, 5, 3735617, 393217, 5, 3801153, 393217, 5, 3866689, 458753, 5, 3932225, 458753, 5, 3997761, 262145, 5, 4063297, 458753, 5, 4128833, 458753, 5, 4194369, 393217, 5, 4259905, 262145, 5, 4325441, 262145, 5, 3735618, 327681, 5, 3801154, 262145, 5, 3866690, 262145, 5, 3932226, 393217, 5, 3997762, 327681, 5, 4063298, 327681, 5, 4128834, 327681, 5, 4194370, 393217, 5, 4259906, 458753, 5, 3735619, 262145, 5, 3801155, 393217, 5, 3866691, 327681, 5, 3932227, 262145, 5, 3997763, 327681, 5, 4063299, 262145, 5, 4128835, 458753, 5, 4194371, 327681, 5, 3735620, 458753, 5, 3801156, 327681, 5, 3866692, 393217, 5, 3932228, 262145, 5, 3997764, 393217, 5, 4063300, 262145, 5, 4128836, 262145, 5, 3735621, 262145, 5, 3801157, 327681, 5, 3866693, 458753, 5, 3932229, 458753, 5, 3997765, 393217, 5, 4063301, 458753, 5, 3735622, 262145, 5, 3801158, 262145, 5, 3866694, 327681, 5, 3932230, 393217, 5, 3997766, 458753, 5, 3735623, 262145, 5, 3801159, 458753, 5, 3866695, 327681, 5, 3932231, 393217, 5, 3735624, 393217, 5, 3801160, 262145, 5, 3866696, 393217, 5, 3735625, 458753, 5, 3801161, 327681, 5, 3735626, 327681, 5, 1703998, 393217, 5, 1769534, 327681, 5, 1835070, 262145, 5, 1900606, 262145, 5, 1966142, 458753, 5, 2031678, 393217, 5, 2097214, 262145, 5, 2162750, 458753, 5, 2228286, 458753, 5, 2293822, 262145, 5, 2359358, 327681, 5, 2424894, 393217, 5, 2490430, 262145, 5, 2555966, 262145, 5, 2621502, 327681, 5, 2687038, 393217, 5, 2752574, 458753, 5, 2818110, 327681, 5, 2883646, 327681, 5, 2949182, 327681, 5, 1703999, 393217, 5, 1769535, 458753, 5, 1835071, 262145, 5, 1900607, 262145, 5, 1966143, 327681, 5, 2031679, 262145, 5, 2097215, 262145, 5, 2162751, 458753, 5, 2228287, 393217, 5, 2293823, 327681, 5, 2359359, 458753, 5, 2424895, 458753, 5, 2490431, 327681, 5, 2555967, 393217, 5, 2621503, 327681, 5, 2687039, 262145, 5, 2752575, 327681, 5, 2818111, 262145, 5, 2883647, 262145, 5, 2949183, 393217, 5, 1704000, 327681, 5, 1769536, 327681, 5, 1835072, 262145, 5, 1900608, 327681, 5, 1966144, 393217, 5, 2031680, 458753, 5, 2097216, 393217, 5, 2162752, 327681, 5, 2228288, 327681, 5, 2293824, 458753, 5, 2359360, 262145, 5, 2424896, 458753, 5, 2490432, 393217, 5, 2555968, 393217, 5, 2621504, 327681, 5, 2687040, 262145, 5, 2752576, 458753, 5, 2818112, 393217, 5, 2883648, 262145, 5, 2949184, 327681, 5, 1704001, 262145, 5, 1769537, 262145, 5, 1835073, 262145, 5, 1900609, 262145, 5, 1966145, 262145, 5, 2031681, 393217, 5, 2097217, 458753, 5, 2162753, 327681, 5, 2228289, 393217, 5, 2293825, 327681, 5, 2359361, 262145, 5, 2424897, 393217, 5, 2490433, 327681, 5, 2555969, 327681, 5, 2621505, 393217, 5, 2687041, 458753, 5, 2752577, 393217, 5, 2818113, 458753, 5, 2883649, 327681, 5, 2949185, 458753, 5, 1704002, 458753, 5, 1769538, 393217, 5, 1835074, 458753, 5, 1900610, 393217, 5, 1966146, 458753, 5, 2031682, 327681, 5, 2097218, 458753, 5, 2162754, 393217, 5, 2228290, 262145, 5, 2293826, 458753, 5, 2359362, 393217, 5, 2424898, 327681, 5, 2490434, 458753, 5, 2555970, 458753, 5, 2621506, 393217, 5, 2687042, 458753, 5, 2752578, 458753, 5, 2818114, 262145, 5, 2883650, 458753, 5, 2949186, 393217, 5, 1704003, 458753, 5, 1769539, 458753, 5, 1835075, 458753, 5, 1900611, 327681, 5, 1966147, 458753, 5, 2031683, 327681, 5, 2097219, 458753, 5, 2162755, 262145, 5, 2228291, 262145, 5, 2293827, 262145, 5, 2359363, 262145, 5, 2424899, 262145, 5, 2490435, 393217, 5, 2555971, 393217, 5, 2621507, 327681, 5, 2687043, 458753, 5, 2752579, 393217, 5, 2818115, 458753, 5, 2883651, 393217, 5, 2949187, 393217, 5, 1704004, 458753, 5, 1769540, 458753, 5, 1835076, 327681, 5, 1900612, 327681, 5, 1966148, 393217, 5, 2031684, 458753, 5, 2097220, 262145, 5, 2162756, 327681, 5, 2228292, 393217, 5, 2293828, 458753, 5, 2359364, 327681, 5, 2424900, 393217, 5, 2490436, 327681, 5, 2555972, 327681, 5, 2621508, 262145, 5, 2687044, 393217, 5, 2752580, 458753, 5, 2818116, 262145, 5, 2883652, 327681, 5, 2949188, 458753, 5, 1704005, 393217, 5, 1769541, 393217, 5, 1835077, 327681, 5, 1900613, 327681, 5, 1966149, 262145, 5, 2031685, 262145, 5, 2097221, 327681, 5, 2162757, 458753, 5, 2228293, 327681, 5, 2293829, 393217, 5, 2359365, 393217, 5, 2424901, 393217, 5, 2490437, 458753, 5, 2555973, 327681, 5, 2621509, 458753, 5, 2687045, 262145, 5, 2752581, 393217, 5, 2818117, 458753, 5, 2883653, 393217, 5, 2949189, 262145, 5, 1704006, 262145, 5, 1769542, 327681, 5, 1835078, 327681, 5, 1900614, 262145, 5, 1966150, 393217, 5, 2031686, 327681, 5, 2097222, 458753, 5, 2162758, 262145, 5, 2228294, 458753, 5, 2293830, 327681, 5, 2359366, 327681, 5, 2424902, 458753, 5, 2490438, 393217, 5, 2555974, 458753, 5, 2621510, 458753, 5, 2687046, 393217, 5, 2752582, 458753, 5, 2818118, 262145, 5, 2883654, 262145, 5, 2949190, 262145, 5, 1704007, 262145, 5, 1769543, 262145, 5, 1835079, 458753, 5, 1900615, 393217, 5, 1966151, 327681, 5, 2031687, 262145, 5, 2097223, 262145, 5, 2162759, 458753, 5, 2228295, 327681, 5, 2293831, 327681, 5, 2359367, 393217, 5, 2424903, 393217, 5, 2490439, 393217, 5, 2555975, 327681, 5, 2621511, 262145, 5, 2687047, 327681, 5, 2752583, 393217, 5, 2818119, 327681, 5, 2883655, 327681, 5, 2949191, 327681, 5, 1704008, 262145, 5, 1769544, 262145, 5, 1835080, 393217, 5, 1900616, 262145, 5, 1966152, 262145, 5, 2031688, 327681, 5, 2097224, 458753, 5, 2162760, 327681, 5, 2228296, 458753, 5, 2293832, 327681, 5, 2359368, 458753, 5, 2424904, 458753, 5, 2490440, 327681, 5, 2555976, 262145, 5, 2621512, 393217, 5, 2687048, 327681, 5, 2752584, 327681, 5, 2818120, 458753, 5, 2883656, 458753, 5, 2949192, 458753, 5, 1704009, 393217, 5, 1769545, 262145, 5, 1835081, 393217, 5, 1900617, 262145, 5, 1966153, 458753, 5, 2031689, 262145, 5, 2097225, 458753, 5, 2162761, 327681, 5, 2228297, 458753, 5, 2293833, 327681, 5, 2359369, 327681, 5, 2424905, 458753, 5, 2490441, 262145, 5, 2555977, 458753, 5, 2621513, 458753, 5, 2687049, 458753, 5, 2752585, 327681, 5, 2818121, 327681, 5, 2883657, 458753, 5, 2949193, 393217, 5, 1704010, 458753, 5, 1769546, 393217, 5, 1835082, 458753, 5, 1900618, 393217, 5, 1966154, 327681, 5, 2031690, 458753, 5, 2097226, 262145, 5, 2162762, 262145, 5, 2228298, 393217, 5, 2293834, 327681, 5, 2359370, 458753, 5, 2424906, 458753, 5, 2490442, 393217, 5, 2555978, 458753, 5, 2621514, 393217, 5, 2687050, 393217, 5, 2752586, 262145, 5, 2818122, 262145, 5, 2883658, 393217, 5, 2949194, 327681, 5, 1179709, 327681, 5, 1245245, 262145, 5, 1310781, 262145, 2, 1376317, 327681, 4, 1441853, 262145, 5, 1507389, 458753, 5, 1572925, 393217, 5, 1638461, 458753, 5, 1179710, 458753, 5, 1245246, 458753, 5, 1310782, 327681, 5, 1376318, 327681, 5, 1441854, 262145, 5, 1507390, 458753, 5, 1572926, 262145, 5, 1638462, 262145, 5, 1179711, 262145, 5, 1245247, 393217, 5, 1310783, 327681, 5, 1376319, 393217, 5, 1441855, 393217, 5, 1507391, 327681, 5, 1572927, 262145, 5, 1638463, 458753, 5, 1179712, 458753, 5, 1245248, 327681, 5, 1310784, 262145, 5, 1376320, 393217, 5, 1441856, 262145, 5, 1507392, 262145, 5, 1572928, 458753, 5, 1638464, 262145, 5, 1179713, 327681, 5, 1245249, 458753, 5, 1310785, 262145, 5, 1376321, 393217, 5, 1441857, 393217, 5, 1507393, 393217, 5, 1572929, 393217, 5, 1638465, 458753, 5, 1179714, 458753, 5, 1245250, 262145, 5, 1310786, 262145, 5, 1376322, 393217, 5, 1441858, 393217, 5, 1507394, 458753, 5, 1572930, 458753, 5, 1638466, 393217, 5, 1179715, 327681, 5, 1245251, 393217, 5, 1310787, 262145, 5, 1376323, 393217, 5, 1441859, 458753, 5, 1507395, 262145, 5, 1572931, 458753, 5, 1638467, 327681, 5, 1179716, 458753, 5, 1245252, 327681, 5, 1310788, 458753, 5, 1376324, 327681, 5, 1441860, 458753, 5, 1507396, 327681, 5, 1572932, 458753, 5, 1638468, 327681, 5, 1179717, 327681, 5, 1245253, 458753, 5, 1310789, 327681, 5, 1376325, 262145, 5, 1441861, 262145, 5, 1507397, 458753, 5, 1572933, 327681, 5, 1638469, 262145, 5, 1179718, 327681, 5, 1245254, 393217, 5, 1310790, 458753, 5, 1376326, 393217, 5, 1441862, 393217, 5, 1507398, 262145, 5, 1572934, 262145, 5, 1638470, 458753, 5, 1179719, 458753, 5, 1245255, 458753, 5, 1310791, 262145, 5, 1376327, 458753, 5, 1441863, 393217, 5, 1507399, 458753, 5, 1572935, 262145, 5, 1638471, 262145, 5, 1179720, 458753, 5, 1245256, 393217, 5, 1310792, 327681, 5, 1376328, 458753, 5, 1441864, 458753, 5, 1507400, 262145, 5, 1572936, 458753, 5, 1638472, 327681, 5, 1179721, 458753, 5, 1245257, 327681, 5, 1310793, 458753, 5, 1376329, 262145, 5, 1441865, 393217, 5, 1507401, 327681, 5, 1572937, 262145, 5, 1638473, 393217, 5, 1179722, 327681, 5, 1245258, 327681, 5, 1310794, 393217, 5, 1376330, 262145, 5, 1441866, 458753, 5, 1507402, 393217, 5, 1572938, 327681, 5, 1638474, 458753, 5, 1703997, 262145, 5, 1769533, 262145, 5, 1835069, 458753, 5, 1310795, 393217, 5, 1376331, 458753, 5, 1441867, 393217, 5, 1507403, 327681, 5, 1572939, 393217, 5, 1638475, 327681, 5, 1704011, 327681, 5, 1769547, 458753, 5, 1835083, 262145, 5, 1900619, 458753, 5, 1966155, 458753, 5, 2031691, 458753, 5, 2097227, 393217, 5, 2162763, 458753, 5, 2228299, 458753, 5, 2293835, 393217, 5, 589882, 393217, 5, 655418, 393217, 5, 720954, 458753, 5, 786490, 327681, 5, 852026, 458753, 5, 589883, 458753, 5, 655419, 262145, 5, 720955, 393217, 5, 786491, 458753, 5, 852027, 327681, 5, 589884, 393217, 5, 655420, 458753, 5, 720956, 327681, 5, 786492, 393217, 5, 852028, 458753, 5, 589885, 393217, 5, 655421, 327681, 5, 720957, 458753, 5, 786493, 327681, 5, 852029, 393217, 5, 589886, 458753, 5, 655422, 458753, 5, 720958, 458753, 5, 786494, 262145, 5, 852030, 458753, 5, 589887, 458753, 5, 655423, 458753, 5, 720959, 458753, 5, 786495, 327681, 5, 852031, 327681, 5, 589888, 327681, 5, 655424, 458753, 5, 720960, 458753, 5, 786496, 393217, 5, 852032, 458753, 5, 589889, 458753, 5, 655425, 327681, 5, 720961, 262145, 5, 786497, 458753, 5, 852033, 327681, 5, 589890, 262145, 5, 655426, 262145, 5, 720962, 458753, 5, 786498, 458753, 5, 852034, 393217, 5, 655427, 262145, 5, 720963, 458753, 5, 786499, 393217, 5, 852035, 262145, 5, 720964, 327681, 5, 786500, 327681, 5, 852036, 393217, 5, 786501, 327681, 5, 852037, 327681, 5, 786473, 458753, 5, 852009, 262145, 5, 327722, 196609, 2, 393258, 458753, 5, 458794, 393217, 5, 524330, 262145, 5, 589866, 327681, 2, 655402, 458753, 2, 720938, 327681, 5, 786474, 262145, 5, 852010, 262145, 5, 327723, 458753, 5, 393259, 262145, 5, 458795, 262145, 5, 524331, 262145, 5, 589867, 458753, 5, 655403, 393217, 5, 720939, 393217, 5, 786475, 393217, 5, 852011, 262145, 5, 327724, 262145, 4, 393260, 458753, 2, 458796, 458753, 5, 524332, 393217, 5, 589868, 262145, 5, 655404, 393217, 5, 720940, 327681, 5, 786476, 262145, 5, 852012, 262145, 5, 327725, 458753, 2, 393261, 458753, 2, 458797, 262145, 5, 524333, 262145, 5, 589869, 393217, 5, 655405, 458753, 2, 720941, 327681, 5, 786477, 327681, 5, 852013, 393217, 5, 327726, 327681, 5, 393262, 393217, 5, 458798, 458753, 5, 524334, 458753, 5, 589870, 262145, 5, 655406, 327681, 4, 720942, 327681, 5, 786478, 262145, 5, 852014, 327681, 5, 327727, 262145, 4, 393263, 262145, 5, 458799, 327681, 5, 524335, 458753, 5, 589871, 327681, 5, 655407, 458753, 4, 720943, 262145, 5, 786479, 393217, 5, 852015, 458753, 5, 327728, 458753, 2, 393264, 458753, 2, 458800, 393217, 5, 524336, 393217, 5, 589872, 327681, 5, 655408, 1, 2, 720944, 327681, 5, 786480, 262145, 5, 852016, 458753, 5, 327729, 458753, 5, 393265, 327681, 5, 458801, 327681, 5, 524337, 327681, 5, 589873, 327681, 5, 655409, 327681, 5, 720945, 262145, 5, 786481, 393217, 5, 852017, 458753, 5, 327730, 262145, 5, 393266, 262145, 5, 458802, 327681, 4, 524338, 327681, 5, 589874, 327681, 5, 655410, 262145, 5, 720946, 393217, 5, 786482, 393217, 5, 852018, 458753, 5, 327731, 327681, 5, 393267, 393217, 5, 458803, 458753, 5, 524339, 327681, 4, 589875, 393217, 5, 655411, 458753, 2, 720947, 458753, 5, 786483, 393217, 5, 852019, 327681, 5, 327732, 458753, 5, 393268, 327681, 5, 458804, 262145, 5, 524340, 327681, 5, 589876, 458753, 5, 655412, 458753, 2, 720948, 458753, 5, 786484, 458753, 5, 852020, 327681, 5, 327733, 458753, 5, 393269, 262145, 5, 458805, 458753, 5, 524341, 393217, 5, 589877, 458753, 4, 655413, 262145, 4, 720949, 327681, 5, 786485, 327681, 5, 852021, 262145, 5, 327734, 262145, 5, 393270, 458753, 5, 458806, 458753, 5, 524342, 458753, 5, 589878, 458753, 2, 655414, 458753, 5, 720950, 393217, 5, 786486, 262145, 5, 852022, 327681, 5, 327735, 262145, 5, 393271, 262145, 5, 458807, 327681, 5, 524343, 458753, 5, 589879, 458753, 2, 655415, 458753, 5, 720951, 458753, 5, 786487, 262145, 5, 852023, 458753, 5, 327736, 327681, 5, 393272, 393217, 5, 458808, 393217, 5, 524344, 393217, 5, 589880, 458753, 2, 655416, 458753, 5, 720952, 327681, 5, 786488, 327681, 5, 852024, 393217, 5, 327737, 458753, 5, 393273, 458753, 5, 458809, 393217, 5, 524345, 393217, 5, 589881, 458753, 5, 655417, 262145, 5, 720953, 458753, 5, 786489, 458753, 5, 852025, 327681, 5, 327738, 262145, 5, 393274, 458753, 5, 458810, 393217, 5, 524346, 393217, 5, -524251, 262145, 5, -458715, 458753, 5, -393179, 393217, 5, -524250, 262145, 5, -458714, 458753, 5, -393178, 262145, 5, -524249, 327681, 5, -458713, 393217, 5, -393177, 393217, 5, -524248, 327681, 5, -458712, 327681, 5, -393176, 393217, 5, -524247, 393217, 5, -458711, 327681, 5, -393175, 262145, 5, -524246, 262145, 5, -458710, 458753, 5, -393174, 393217, 5, -327638, 262145, 5, -262102, 458753, 5, -196566, 327681, 5, -131030, 262145, 5, -65494, 262145, 5, 42, 393217, 5, 65578, 458753, 2, 131114, 327681, 4, 196650, 458753, 5, 262186, 458753, 5, -524245, 458753, 5, -458709, 458753, 5, -393173, 393217, 5, -327637, 458753, 5, -262101, 458753, 5, -196565, 458753, 5, -131029, 393217, 5, -65493, 458753, 5, 43, 327681, 5, 65579, 458753, 5, 131115, 327681, 5, 196651, 196609, 2, 262187, 458753, 5, -524244, 327681, 5, -458708, 393217, 5, -393172, 262145, 5, -327636, 262145, 5, -262100, 393217, 5, -196564, 458753, 5, -131028, 327681, 5, -65492, 393217, 5, 44, 262145, 5, 65580, 458753, 5, 131116, 262145, 5, 196652, 458753, 5, 262188, 327681, 5, -524243, 262145, 5, -458707, 262145, 5, -393171, 458753, 5, -327635, 327681, 5, -262099, 458753, 5, -196563, 393217, 5, -131027, 262145, 5, -65491, 393217, 5, 45, 458753, 5, 65581, 458753, 5, 131117, 327681, 5, 196653, 131073, 2, 262189, 262145, 5, -524242, 393217, 5, -458706, 393217, 5, -393170, 327681, 5, -327634, 458753, 5, -262098, 262145, 5, -196562, 393217, 5, -131026, 327681, 5, -65490, 262145, 5, 46, 262145, 5, 65582, 262145, 5, 131118, 393217, 5, 196654, 393217, 5, 262190, 262145, 5, -524241, 327681, 5, -458705, 393217, 5, -393169, 458753, 5, -327633, 327681, 5, -262097, 393217, 5, -196561, 393217, 5, -131025, 393217, 5, -65489, 262145, 5, 47, 262145, 5, 65583, 393217, 5, 131119, 458753, 5, 196655, 393217, 5, 262191, 327681, 5, -524240, 393217, 5, -458704, 262145, 5, -393168, 393217, 5, -327632, 262145, 5, -262096, 393217, 5, -196560, 327681, 5, -131024, 393217, 5, -65488, 327681, 5, 48, 327681, 5, 65584, 393217, 5, 131120, 458753, 5, 196656, 327681, 5, 262192, 262145, 5, -524239, 262145, 5, -458703, 458753, 5, -393167, 262145, 5, -327631, 458753, 5, -262095, 393217, 5, -196559, 262145, 5, -131023, 327681, 5, -65487, 458753, 5, 49, 393217, 5, 65585, 393217, 5, 131121, 458753, 5, 196657, 458753, 5, 262193, 393217, 5, -393166, 327681, 5, -327630, 327681, 5, -262094, 458753, 5, -196558, 327681, 5, -131022, 393217, 5, -65486, 393217, 5, 50, 393217, 5, 65586, 262145, 5, 131122, 393217, 5, 196658, 393217, 5, 262194, 327681, 5, -327629, 262145, 5, -262093, 393217, 5, -196557, 327681, 5, -131021, 327681, 5, -65485, 327681, 5, 51, 327681, 5, 65587, 393217, 5, 131123, 327681, 5, 196659, 327681, 5, 262195, 327681, 5, -262092, 327681, 5, -196556, 458753, 5, -131020, 262145, 5, -65484, 393217, 5, 52, 458753, 5, 65588, 458753, 5, 131124, 327681, 5, 196660, 262145, 5, 262196, 327681, 5, -262091, 458753, 5, -196555, 262145, 5, -131019, 393217, 5, -65483, 393217, 5, 53, 327681, 5, 65589, 393217, 5, 131125, 458753, 5, 196661, 262145, 5, 262197, 393217, 5, -131018, 327681, 5, -65482, 393217, 5, 54, 458753, 5, 65590, 393217, 5, 131126, 327681, 5, 196662, 262145, 5, 262198, 327681, 5, -65481, 458753, 5, 55, 393217, 5, 65591, 458753, 5, 131127, 458753, 5, 196663, 393217, 5, 262199, 327681, 5, 65592, 327681, 5, 131128, 327681, 5, 196664, 458753, 5, 262200, 393217, 5, 131129, 458753, 5, 196665, 393217, 5, 262201, 393217, 5, 196666, 458753, 5, 262202, 262145, 5, 196667, 458753, 5, 262203, 262145, 5, 327739, 262145, 5, 393275, 327681, 5, 458811, 327681, 5, 196668, 393217, 5, 262204, 327681, 5, 327740, 327681, 5, 393276, 262145, 5, 458812, 393217, 5, 262205, 458753, 5, 327741, 327681, 5, 393277, 327681, 5, 458813, 458753, 5, 327742, 262145, 5, 393278, 262145, 5, 458814, 262145, 5, -851931, 458753, 5, -786395, 458753, 5, -720859, 327681, 5, -655323, 327681, 5, -589787, 458753, 5, -851930, 393217, 5, -786394, 393217, 5, -720858, 262145, 5, -655322, 458753, 5, -589786, 393217, 5, -851929, 327681, 5, -786393, 393217, 5, -720857, 393217, 5, -655321, 393217, 5, -589785, 458753, 5, -851928, 262145, 5, -786392, 262145, 5, -720856, 393217, 5, -655320, 393217, 5, -589784, 393217, 5, -851927, 458753, 5, -786391, 327681, 5, -720855, 458753, 5, -655319, 458753, 5, -589783, 458753, 5, -851926, 458753, 5, -786390, 262145, 5, -720854, 393217, 5, -655318, 262145, 5, -589782, 327681, 5, -851925, 262145, 5, -786389, 393217, 5, -720853, 262145, 5, -655317, 458753, 5, -589781, 458753, 5, -786388, 458753, 5, -720852, 327681, 5, -655316, 262145, 5, -589780, 393217, 5, -786387, 458753, 5, -720851, 327681, 5, -655315, 262145, 5, -589779, 458753, 5, -720850, 327681, 5, -655314, 262145, 5, -589778, 393217, 5, -655313, 393217, 5, -589777, 458753, 5, -589776, 327681, 5, 524347, 458753, 5, 524348, 458753, 5, 524349, 327681, 5, 524350, 327681, 5, 393279, 327681, 5, 458815, 327681, 5, 524351, 327681, 5, 458816, 393217, 5, 524352, 262145, 5, 524353, 262145, 5, -1179611, 262145, 5, -1114075, 327681, 5, -1048539, 327681, 5, -983003, 393217, 5, -917467, 327681, 5, -1179610, 262145, 5, -1114074, 262145, 5, -1048538, 393217, 5, -983002, 393217, 5, -917466, 327681, 5, -1114073, 393217, 5, -1048537, 458753, 5, -983001, 262145, 5, -917465, 458753, 5, -1048536, 262145, 5, -983000, 327681, 5, -917464, 327681, 5, -982999, 327681, 5, -917463, 393217, 5, -982998, 458753, 5, -917462, 458753, 5, 2097181, 262145, 5, 2162717, 262145, 5, 2228253, 327681, 5, 2293789, 458753, 5, 2359325, 393217, 5, 2424861, 327681, 5, 2490397, 262145, 5, 2555933, 458753, 5, 2621469, 458753, 5, 2687005, 327681, 5, 2097182, 458753, 5, 2162718, 458753, 5, 2228254, 393217, 5, 2293790, 327681, 5, 2359326, 262145, 5, 2424862, 458753, 5, 2490398, 327681, 5, 2555934, 458753, 5, 2621470, 327681, 5, 2687006, 393217, 5, 2097183, 262145, 5, 2162719, 262145, 5, 2228255, 327681, 5, 2293791, 458753, 5, 2359327, 262145, 5, 2424863, 458753, 5, 2490399, 262145, 5, 2555935, 262145, 5, 2621471, 458753, 5, 2687007, 262145, 5, 2097184, 458753, 5, 2162720, 458753, 5, 2228256, 458753, 5, 2293792, 393217, 5, 2359328, 393217, 5, 2424864, 393217, 5, 2490400, 327681, 5, 2555936, 262145, 5, 2621472, 458753, 5, 2687008, 393217, 5, 1441821, 458753, 5, 1507357, 393217, 5, 1572893, 262145, 5, 1638429, 393217, 5, 1703965, 458753, 5, 1769501, 327681, 5, 1835037, 262145, 5, 1900573, 393217, 5, 1966109, 262145, 5, 2031645, 393217, 5, 1441822, 393217, 5, 1507358, 393217, 5, 1572894, 327681, 5, 1638430, 327681, 5, 1703966, 327681, 5, 1769502, 458753, 5, 1835038, 393217, 5, 1900574, 393217, 5, 1966110, 262145, 5, 2031646, 393217, 5, 1441823, 262145, 5, 1507359, 458753, 5, 1572895, 393217, 5, 1638431, 262145, 5, 1703967, 327681, 5, 1769503, 327681, 5, 1835039, 262145, 5, 1900575, 393217, 5, 1966111, 393217, 5, 2031647, 393217, 5, 1441824, 458753, 5, 1507360, 393217, 5, 1572896, 458753, 5, 1638432, 393217, 5, 1703968, 393217, 5, 1769504, 327681, 5, 1835040, 327681, 5, 1900576, 393217, 5, 1966112, 327681, 5, 2031648, 393217, 5, 524226, 393217, 5, 524227, 327681, 5, 458692, 262145, 5, 524228, 393217, 5, 393157, 327681, 5, 458693, 262145, 5, 524229, 327681, 5, 327622, 458753, 5, 393158, 327681, 5, 458694, 458753, 5, 524230, 393217, 5, 327623, 262145, 5, 393159, 262145, 5, 458695, 458753, 5, 524231, 458753, 5, 196552, 262145, 5, 262088, 458753, 5, 327624, 393217, 5, 393160, 262145, 5, 458696, 393217, 5, 524232, 327681, 5, 1376332, 327681, 5, 1441868, 393217, 5, 1441869, 458753, 5, 1507404, 458753, 5, 1572940, 393217, 5, 1638476, 393217, 5, 1704012, 458753, 5, 1507405, 393217, 5, 1572941, 458753, 5, 1638477, 262145, 5, 1704013, 327681, 5, 1507406, 327681, 5, 1572942, 262145, 5, 1638478, 262145, 5, 1704014, 262145, 5, 1572943, 393217, 5, 1638479, 393217, 5, 1704015, 327681, 5, 1638480, 458753, 5, 1704016, 393217, 5, 1704017, 393217, 5, 1835084, 262145, 5, 1900620, 262145, 5, 1966156, 262145, 5, 2031692, 327681, 5, 1835085, 458753, 5, 1900621, 262145, 5, 1966157, 458753, 5, 2031693, 327681, 5, 1835086, 393217, 5, 1900622, 327681, 5, 1966158, 393217, 5, 2031694, 393217, 5, 1835087, 458753, 5, 1900623, 327681, 5, 1966159, 327681, 5, 2031695, 458753, 5, 1835088, 262145, 5, 1900624, 327681, 5, 1966160, 458753, 5, 2031696, 393217, 5, 1835089, 393217, 5, 1900625, 393217, 5, 1966161, 393217, 5, 2031697, 393217, 5, 1835090, 262145, 5, 1900626, 327681, 5, 1966162, 327681, 5, 2031698, 327681, 5, 1769548, 458753, 5, 1769549, 393217, 5, 1769550, 393217, 5, 1769551, 393217, 5, 1769552, 393217, 5, 1769553, 458753, 5, 2097228, 458753, 5, 2162764, 458753, 5, 2228300, 262145, 5, 2293836, 262145, 5, 2097229, 393217, 5, 2162765, 458753, 5, 2228301, 327681, 5, 2293837, 393217, 5, 2097230, 262145, 5, 2162766, 458753, 5, 2228302, 262145, 5, 2293838, 327681, 5, 2097231, 393217, 5, 2162767, 327681, 5, 2228303, 327681, 5, 2293839, 458753, 5, 2097232, 458753, 5, 2162768, 262145, 5, 2228304, 393217, 5, 2293840, 393217, 5, 2097233, 262145, 5, 2162769, 393217, 5, 2228305, 262145, 5, 2293841, 327681, 5, 2359371, 327681, 5, 2424907, 458753, 5, 2490443, 262145, 5, 2359372, 393217, 5, 2424908, 393217, 5, 2490444, 393217, 5, 2359373, 458753, 5, 2424909, 458753, 5, 2490445, 262145, 5, 2555979, 327681, 5, 2621515, 393217, 5, 2687051, 458753, 5, 2555980, 393217, 5, 2621516, 262145, 5, 2687052, 327681, 5, 2555981, 262145, 5, 2621517, 262145, 5, 2687053, 262145, 5, 2555982, 393217, 5, 2621518, 327681, 5, 2687054, 327681, 5, 2359374, 262145, 5, 2424910, 393217, 5, 2490446, 458753, 5, 2359375, 327681, 5, 2424911, 262145, 5, 2490447, 327681, 5, 2359376, 458753, 5, 2424912, 327681, 5, 2359377, 262145, 5, 2424913, 262145, 5, 2162770, 458753, 5, 2228306, 393217, 5, 2293842, 393217, 5, 2162771, 327681, 5, 2228307, 262145, 5, 2293843, 327681, 5, 2097234, 262145, 5, 2031699, 458753, 5, 2097235, 393217, 5, 2031700, 458753, 5, 2097236, 327681, 5, 2162772, 327681, 5, 2031701, 458753, 5, 2097237, 458753, 5, 2162773, 458753, 5, 1900627, 458753, 5, 1966163, 327681, 5, 1900628, 262145, 5, 1966164, 458753, 5, 1966165, 393217, 5, 2031702, 262145, 5, 2097238, 327681, 5, 2097239, 393217, 5, 1769554, 327681, 5, 1835091, 327681, 5, 2686908, 262145, 5, 2686909, 393217, 5, 2752445, 262145, 5, 2686910, 262145, 5, 2752446, 458753, 5, 2817982, 262145, 5, 2686911, 458753, 5, 2752447, 458753, 5, 2817983, 393217, 5, 2883519, 458753, 5, 2686912, 327681, 5, 2752448, 262145, 5, 2817984, 458753, 5, 2883520, 458753, 5, 2949056, 458753, 5, 1900465, 393217, 5, 1966001, 458753, 5, 1900466, 327681, 5, 1966002, 393217, 5, 2031538, 262145, 5, 1900467, 327681, 5, 1966003, 458753, 5, 2031539, 327681, 5, 2097075, 393217, 5, 1900468, 393217, 5, 1966004, 327681, 5, 2031540, 458753, 5, 2097076, 458753, 5, 2162612, 262145, 5, 1900469, 262145, 5, 1966005, 393217, 5, 2031541, 327681, 5, 2097077, 393217, 5, 2162613, 327681, 5, 2228149, 458753, 5, 1900470, 393217, 5, 1966006, 458753, 5, 2031542, 458753, 5, 2097078, 393217, 5, 2162614, 393217, 5, 2228150, 393217, 5, 2293686, 327681, 5, 1900471, 327681, 5, 1966007, 327681, 5, 2031543, 458753, 5, 2097079, 458753, 5, 2162615, 327681, 5, 2228151, 393217, 5, 2293687, 458753, 5, 2359223, 458753, 5, 1900472, 327681, 5, 1966008, 262145, 5, 2031544, 262145, 5, 2097080, 458753, 5, 2162616, 262145, 5, 2228152, 393217, 5, 2293688, 327681, 5, 2359224, 393217, 5, 2424760, 262145, 5, 1900473, 458753, 5, 1966009, 262145, 5, 2031545, 458753, 5, 2097081, 458753, 5, 2162617, 262145, 5, 2228153, 458753, 5, 2293689, 262145, 5, 2359225, 262145, 5, 2424761, 327681, 5, 2490297, 327681, 5, 1900474, 393217, 5, 1966010, 327681, 5, 2031546, 458753, 5, 2097082, 327681, 5, 2162618, 393217, 5, 2228154, 327681, 5, 2293690, 327681, 5, 2359226, 327681, 5, 2424762, 393217, 5, 2490298, 393217, 5, 2555834, 393217, 5, 1900475, 262145, 5, 1966011, 262145, 5, 2031547, 393217, 5, 2097083, 393217, 5, 2162619, 262145, 5, 2228155, 262145, 5, 2293691, 327681, 5, 2359227, 327681, 5, 2424763, 458753, 5, 2490299, 262145, 5, 2555835, 262145, 5, 2621371, 327681, 5, 1900476, 327681, 5, 1966012, 262145, 5, 2031548, 262145, 5, 2097084, 327681, 5, 2162620, 327681, 5, 2228156, 327681, 5, 2293692, 327681, 5, 2359228, 327681, 5, 2424764, 262145, 5, 2490300, 458753, 5, 2555836, 327681, 5, 2621372, 262145, 5, 1900477, 327681, 5, 1966013, 458753, 5, 2031549, 327681, 2, 2097085, 262145, 4, 2162621, 327681, 4, 2228157, 393217, 5, 2293693, 458753, 2, 2359229, 262145, 4, 2424765, 327681, 5, 2490301, 327681, 4, 2555837, 393217, 5, 2621373, 262145, 5, 1900478, 458753, 4, 1966014, 393217, 5, 2031550, 458753, 5, 2097086, 458753, 4, 2162622, 327681, 4, 2228158, 262145, 4, 2293694, 327681, 2, 2359230, 262145, 5, 2424766, 327681, 5, 2490302, 393217, 5, 2555838, 458753, 2, 2621374, 458753, 5, 1900479, 458753, 2, 1966015, 458753, 5, 2031551, 327681, 5, 2097087, 458753, 4, 2162623, 327681, 5, 2228159, 262145, 4, 2293695, 458753, 5, 2359231, 458753, 5, 2424767, 327681, 4, 2490303, 327681, 4, 2555839, 393217, 5, 2621375, 458753, 5, 1900480, 458753, 4, 1966016, 393217, 5, 2031552, 458753, 2, 2097088, 393217, 5, 2162624, 458753, 4, 2228160, 458753, 4, 2293696, 458753, 4, 2359232, 458753, 4, 2424768, 262145, 4, 2490304, 393217, 5, 2555840, 458753, 4, 2621376, 458753, 5, 1638330, 262145, 5, 1703866, 262145, 5, 1769402, 327681, 5, 1834938, 458753, 5, 1638331, 327681, 5, 1703867, 327681, 5, 1769403, 393217, 5, 1834939, 262145, 5, 1638332, 393217, 5, 1703868, 393217, 5, 1769404, 327681, 5, 1834940, 327681, 5, 1638333, 458753, 5, 1703869, 458753, 5, 1769405, 327681, 5, 1834941, 458753, 5, 1638334, 393217, 5, 1703870, 393217, 5, 1769406, 458753, 5, 1834942, 262145, 4, 1638335, 327681, 5, 1703871, 262145, 5, 1769407, 393217, 5, 1834943, 262145, 5, 1638336, 458753, 5, 1703872, 262145, 5, 1769408, 327681, 5, 1834944, 458753, 5, 1507261, 327681, 5, 1572797, 327681, 5, 1507262, 262145, 5, 1572798, 262145, 5, 1507263, 262145, 5, 1572799, 327681, 5, 1507264, 262145, 5, 1572800, 393217, 5, 1441727, 262145, 5, 1441728, 458753, 5, -2686981, 327681, 5, -2621445, 458753, 5, -2555909, 327681, 5, -2490373, 327681, 5, -2686980, 262145, 5, -2621444, 327681, 5, -2555908, 393217, 5, -2490372, 262145, 5, -2686979, 262145, 5, -2621443, 327681, 5, -2555907, 327681, 5, -2490371, 393217, 5, -2686978, 327681, 5, -2621442, 393217, 5, -2555906, 327681, 5, -2490370, 393217, 5, -2686977, 327681, 5, -2621441, 327681, 5, -2555905, 458753, 5, -2490369, 393217, 5, -2752512, 393217, 5, -2686976, 327681, 5, -2621440, 262145, 5, -2555904, 327681, 5, -2752511, 262145, 5, -2686975, 393217, 5, -2621439, 327681, 5, -2555903, 458753, 5, -2490375, 262145, 5, -2490374, 327681, 5, -2555910, 393217, 5, -2883584, 393217, 5, -2818048, 327681, 5, -2883583, 393217, 5, -2818047, 458753, 5, -2883582, 393217, 5, -2818046, 262145, 5, -2752510, 393217, 5, -2686974, 327681, 5, -2621438, 393217, 5, -2555902, 262145, 5, -2883581, 458753, 5, -2818045, 458753, 5, -2752509, 393217, 5, -2686973, 262145, 5, -2621437, 262145, 5, -2555901, 262145, 5, -2883580, 393217, 5, -2818044, 458753, 5, -2752508, 458753, 5, -2686972, 327681, 5, -2621436, 262145, 5, -2555900, 458753, 5, -2883579, 327681, 5, -2818043, 262145, 5, -2752507, 458753, 5, -2686971, 393217, 5, -2621435, 327681, 5, -2555899, 327681, 5, -2883578, 262145, 5, -2818042, 393217, 5, -2752506, 458753, 5, -2686970, 458753, 5, -2621434, 262145, 5, -2555898, 327681, 5, -2883577, 458753, 5, -2818041, 327681, 5, -2752505, 262145, 5, -2686969, 393217, 5, -2621433, 458753, 5, -2555897, 327681, 5, -2818052, 327681, 5, -2752516, 458753, 5, -2818051, 458753, 5, -2752515, 458753, 5, -2818050, 393217, 5, -2752514, 393217, 5, -2818049, 262145, 5, -2752513, 327681, 5, -3014655, 393217, 5, -2949119, 393217, 5, -3014654, 393217, 5, -2949118, 393217, 5, -3014653, 262145, 5, -2949117, 458753, 5, -3014652, 458753, 5, -2949116, 458753, 5, -3014651, 458753, 5, -2949115, 262145, 5, -3014650, 327681, 5, -2949114, 262145, 5, -3014649, 262145, 5, -2949113, 262145, 5, -3145725, 327681, 5, -3080189, 327681, 5, -3145724, 393217, 5, -3080188, 393217, 5, -3145723, 393217, 5, -3080187, 458753, 5, -3145722, 327681, 5, -3080186, 393217, 5, -3145721, 327681, 5, -3080185, 393217, 5, -3080184, 327681, 5, -3014648, 393217, 5, -2949112, 458753, 5, -3014647, 458753, 5, -2949111, 458753, 5, -2949110, 327681, 5, -3342332, 327681, 5, -3276796, 393217, 5, -3211260, 327681, 5, -3276795, 262145, 5, -3211259, 458753, 5, -3211258, 262145, 5, -2883575, 393217, 5, -2883574, 327681, 5, -2883573, 262145, 5, -2883576, 393217, 5, -2818040, 393217, 5, -2752504, 393217, 5, -2686968, 262145, 5, -2621432, 458753, 5, -2555896, 262145, 5, -2818039, 458753, 5, -2752503, 458753, 5, -2686967, 393217, 5, -2621431, 393217, 5, -2555895, 327681, 5, -2818038, 458753, 5, -2752502, 393217, 5, -2686966, 458753, 5, -2621430, 458753, 5, -2555894, 458753, 5, -2818037, 393217, 5, -2752501, 393217, 5, -2686965, 262145, 5, -2621429, 393217, 5, -2555893, 327681, 5, -2818036, 393217, 5, -2752500, 327681, 5, -2686964, 458753, 5, -2621428, 327681, 5, -2555892, 327681, 5, -2752499, 458753, 5, -2686963, 327681, 5, -2621427, 458753, 5, -2555891, 327681, 5, -2686962, 262145, 5, -2621426, 262145, 5, -2555890, 262145, 5, -2621425, 458753, 5, -2555889, 393217, 5, -2555888, 393217, 5, -1245147, 262145, 5, -1245146, 458753, 5, -1310683, 327681, 5, 7077892, 262145, 5, 7143428, 262145, 5, 7077893, 262145, 5, 7143429, 393217, 5, 7077894, 327681, 5, 7143430, 262145, 5, 7077895, 327681, 5, 7143431, 458753, 5, 7077896, 458753, 5, 7143432, 458753, 5, 7077897, 393217, 5, 7143433, 393217, 5, 7077889, 393217, 5, 7143425, 262145, 5, 7208961, 327681, 5, 7077890, 458753, 5, 7143426, 327681, 5, 7208962, 458753, 5, 7274498, 327681, 5, 7077891, 393217, 5, 7143427, 393217, 5, 7208963, 458753, 5, 7274499, 458753, 5, 7340035, 458753, 5, 7208964, 458753, 5, 7274500, 262145, 5, 7340036, 327681, 5, 7208965, 327681, 5, 7274501, 262145, 5, 7340037, 327681, 5, 7208966, 458753, 5, 7274502, 327681, 5, 7340038, 327681, 5, 7405572, 393217, 5, 7143424, 393217, 5, 7208967, 262145, 5, 7143423, 458753, 5, 7077888, 327681, 5, 7536645, 458753, 5, 7536646, 458753, 5, 7405573, 262145, 5, 7471109, 262145, 5, 7405574, 327681, 5, 7471110, 327681, 5, 7405575, 393217, 5, 7471111, 393217, 5, 7274503, 393217, 5, 7340039, 262145, 5, 7274504, 458753, 5, 7340040, 327681, 5, 7405576, 262145, 5, 7274505, 262145, 5, 7340041, 393217, 5, 7405577, 327681, 5, 7208968, 327681, 5, 7208969, 327681, 5, 7208970, 458753, 5, 7274506, 458753, 5, 7340042, 327681, 5, 7208971, 393217, 5, 7274507, 262145, 5, 7340043, 458753, 5, 7077898, 327681, 5, 7143434, 327681, 5, 7077899, 262145, 5, 7143435, 458753, 5, 7077900, 327681, 5, 7143436, 262145, 5, 7208972, 327681, 5, 7077901, 262145, 5, 7143437, 327681, 5, 7208973, 458753, 5, 7077902, 393217, 5, 7143438, 458753, 5, 7208974, 393217, 5, 6946832, 393217, 5, 7012368, 393217, 5, 6946833, 458753, 5, 7012369, 262145, 5, 6881296, 327681, 5, 6881297, 327681, 5, 6881298, 393217, 5, 6881299, 458753, 5, 6946834, 262145, 5, 6946835, 458753, 5, 2752587, 327681, 5, 2818123, 458753, 5, 2883659, 327681, 5, 2949195, 458753, 5, 2752588, 262145, 5, 2818124, 393217, 5, 2883660, 262145, 5, 2949196, 262145, 5, 2752589, 393217, 5, 2818125, 327681, 5, 2883661, 458753, 5, 2949197, 262145, 5, 2752590, 327681, 5, 2818126, 262145, 5, 2883662, 458753, 5, 2949198, 393217, 5, 2752591, 327681, 5, 2818127, 458753, 5, 2883663, 393217, 5, 2949199, 327681, 5, 2752592, 327681, 5, 2818128, 262145, 5, 2883664, 327681, 5, 2949200, 262145, 5, 2555983, 327681, 5, 2621519, 327681, 5, 2687055, 458753, 5, 2555984, 458753, 5, 2621520, 458753, 5, 2687056, 262145, 5, 2555985, 458753, 5, 2621521, 262145, 5, 2687057, 458753, 5, 2752593, 393217, 5, 2555986, 262145, 5, 2621522, 327681, 5, 2687058, 393217, 5, 2752594, 393217, 5, 2555987, 393217, 5, 2621523, 458753, 5, 2687059, 458753, 5, 2752595, 262145, 5, 2490448, 458753, 5, 2490449, 327681, 5, 2424914, 262145, 5, 2490450, 458753, 5, 2424915, 327681, 5, 2490451, 458753, 5, 2424916, 458753, 5, 2490452, 393217, 5, 2555988, 327681, 5, 2424917, 262145, 5, 2490453, 458753, 5, 2555989, 393217, 5, 2359378, 458753, 5, 2359379, 327681, 5, 2293844, 458753, 5, 2359380, 458753, 5, 2293845, 262145, 5, 2359381, 393217, 5, 2293846, 262145, 5, 2359382, 458753, 5, 2424918, 262145, 5, 2490454, 327681, 5, 2293847, 262145, 5, 2359383, 327681, 5, 2424919, 458753, 5, 2490455, 458753, 5, 2228308, 262145, 5, 2228309, 327681, 5, 2162774, 327681, 5, 2228310, 393217, 5, 2162775, 458753, 5, 2228311, 327681, 5, 2162776, 458753, 5, 2228312, 393217, 5, 2293848, 262145, 5, 2359384, 262145, 5, 2228313, 262145, 5, 2293849, 327681, 5, 2359385, 262145, 5, 2293850, 458753, 5, 2359386, 262145, 5, 2555990, 262145, 5, 2555991, 262145, 5, 2424920, 393217, 5, 2490456, 458753, 5, 2555992, 327681, 5, 2424921, 393217, 5, 2490457, 327681, 5, 2555993, 393217, 5, 2424922, 262145, 5, 2490458, 393217, 5, 2621524, 262145, 5, 2687060, 327681, 5, 2752596, 262145, 5, 2621525, 327681, 5, 2687061, 393217, 5, 2752597, 458753, 5, 2621526, 393217, 5, 2687062, 262145, 5, 2752598, 458753, 5, 2621527, 262145, 5, 2687063, 458753, 5, 2752599, 262145, 5, 2621528, 327681, 5, 2687064, 327681, 5, 2621529, 327681, 5, 2883665, 393217, 5, 2949201, 327681, 5, 2883666, 327681, 5, 2949202, 262145, 5, 2883667, 393217, 5, 2949203, 262145, 5, 2883668, 262145, 5, 2818129, 393217, 5, 2818130, 262145, 5, 2818131, 393217, 5, 2818132, 327681, 5, 2818133, 393217, 5, 2818134, 393217, 5, 7077903, 327681, 5, 7143439, 393217, 5, 7208975, 327681, 5, 7077904, 458753, 5, 7143440, 262145, 5, 7208976, 393217, 5, 7077905, 458753, 5, 7143441, 327681, 5, 7208977, 327681, 5, 7012370, 393217, 5, 7077906, 327681, 5, 7143442, 393217, 5, 7012371, 262145, 5, 7077907, 327681, 5, 7405578, 458753, 5, 7405579, 458753, 5, 7274508, 327681, 5, 7340044, 458753, 5, 7405580, 458753, 5, 7274509, 262145, 5, 7340045, 262145, 5, 7405581, 393217, 5, 7274510, 262145, 5, 7340046, 458753, 5, 7405582, 393217, 5, 7274511, 327681, 5, 7340047, 458753, 5, 7274512, 262145, 5, 7274513, 262145, 5, 7536647, 458753, 5, 7471112, 262145, 5, 7536648, 262145, 5, 7471113, 327681, 5, 7536649, 262145, 5, 7471114, 393217, 5, 7536650, 458753, 5, 7471115, 327681, 5, 7536651, 262145, 5, 7471116, 262145, 5, 7536652, 262145, 5, 7471117, 393217, 5, 7536653, 393217, 5, 7471118, 327681, 5, 7602183, 393217, 5, 7602184, 393217, 5, 7667720, 327681, 5, 7602185, 393217, 5, 7667721, 458753, 5, 7733257, 262145, 5, 7602186, 393217, 5, 7667722, 327681, 5, 7602187, 327681, 5, 1834928, 458753, 5, 1900464, 262145, 5, 1834929, 393217, 5, 1769394, 393217, 5, 1834930, 458753, 5, 1638323, 262145, 5, 1703859, 393217, 5, 1769395, 393217, 5, 1834931, 327681, 5, 1638324, 458753, 5, 1703860, 327681, 5, 1769396, 393217, 5, 1834932, 262145, 5, 1638325, 393217, 5, 1703861, 458753, 5, 1769397, 327681, 5, 1834933, 327681, 5, 1638326, 458753, 5, 1703862, 393217, 5, 1769398, 393217, 5, 1834934, 262145, 5, 1638327, 393217, 5, 1703863, 262145, 5, 1769399, 262145, 5, 1834935, 393217, 5, 1638328, 262145, 5, 1703864, 262145, 5, 1769400, 262145, 5, 1834936, 262145, 5, 1638329, 262145, 5, 1703865, 458753, 5, 1769401, 262145, 5, 1834937, 393217, 5, 1572788, 327681, 5, 1507253, 327681, 5, 1572789, 458753, 5, 1441718, 458753, 5, 1507254, 458753, 5, 1572790, 393217, 5, 1441719, 393217, 5, 1507255, 327681, 5, 1572791, 262145, 5, 1441720, 458753, 5, 1507256, 327681, 5, 1572792, 327681, 5, 1441721, 458753, 5, 1507257, 458753, 5, 1572793, 458753, 5, 1441722, 393217, 5, 1507258, 262145, 5, 1572794, 458753, 5, 1441723, 458753, 5, 1507259, 458753, 5, 1572795, 393217, 5, 1441724, 393217, 5, 1507260, 393217, 5, 1572796, 262145, 5, 1441725, 458753, 5, 1376184, 393217, 5, 1310649, 262145, 5, 1376185, 262145, 5, 1245114, 393217, 5, 1310650, 458753, 5, 1376186, 262145, 5, 1245115, 458753, 5, 1310651, 327681, 5, 1376187, 327681, 5, 1245116, 262145, 5, 1310652, 327681, 5, 1376188, 327681, 5, 1245117, 393217, 5, 1310653, 393217, 5, 1376189, 458753, 5, 1245118, 393217, 5, 1310654, 393217, 5, 1376190, 327681, 5, 1441726, 393217, 5, 1245119, 393217, 5, 1310655, 393217, 5, 1376191, 262145, 5, 1245120, 458753, 5, 1310656, 262145, 5, 1376192, 262145, 5, 917436, 327681, 5, 851901, 262145, 5, 917437, 393217, 5, 786366, 327681, 5, 851902, 458753, 5, 917438, 262145, 5, 720831, 262145, 5, 786367, 393217, 5, 851903, 393217, 5, 917439, 393217, 5, 655296, 327681, 5, 720832, 262145, 5, 786368, 393217, 5, 851904, 327681, 5, 917440, 458753, 5, 589761, 458753, 5, 655297, 262145, 5, 720833, 458753, 5, 786369, 262145, 5, 851905, 327681, 5, 917441, 262145, 5, -1310751, 262145, 5, -1245215, 327681, 5, -1376286, 262145, 5, -1310750, 458753, 5, -1245214, 458753, 5, -1376285, 458753, 5, -1310749, 458753, 5, -1245213, 458753, 5, -1441820, 458753, 5, -1376284, 393217, 5, -1310748, 393217, 5, -1245212, 327681, 5, -1507355, 393217, 5, -1441819, 393217, 5, -1376283, 458753, 5, -1310747, 393217, 5, -1245211, 262145, 5, -1507354, 262145, 5, -1441818, 327681, 5, -1376282, 262145, 5, -1310746, 327681, 5, -1245210, 458753, 5, -1638427, 327681, 5, -1572891, 458753, 5, -1638426, 393217, 5, -1572890, 393217, 5, -1638425, 393217, 5, -1572889, 458753, 5, -1507353, 262145, 5, -1441817, 393217, 5, -1376281, 458753, 5, -1638424, 327681, 5, -1572888, 327681, 5, -1507352, 458753, 5, -1441816, 393217, 5, -1638423, 393217, 5, -1572887, 327681, 5, -1507351, 262145, 5, -1638422, 262145, 5, -1572886, 393217, 5, -1703962, 393217, 5, -1703961, 262145, 5, -1703960, 393217, 5, -1703959, 393217, 5, -1703958, 393217, 5, -1703957, 327681, 5, -1638421, 262145, 5, -1703956, 327681, 5, -1769497, 393217, 5, -1835032, 262145, 5, -1769496, 458753, 5, -1900567, 327681, 5, -1835031, 393217, 5, -1769495, 393217, 5, -1900566, 458753, 5, -1835030, 393217, 5, -1769494, 262145, 5, -1900565, 262145, 5, -1835029, 393217, 5, -1769493, 262145, 5, -1900564, 458753, 5, -1835028, 458753, 5, -1769492, 458753, 5, -1900563, 458753, 5, -1835027, 327681, 5, -1769491, 327681, 5, -1900562, 458753, 5, -1835026, 327681, 5, -1900561, 458753, 5, -1966102, 327681, 5, -2031637, 262145, 5, -1966101, 393217, 5, -2097172, 393217, 5, -2031636, 458753, 5, -1966100, 458753, 5, -2097171, 458753, 5, -2031635, 458753, 5, -1966099, 458753, 5, -2097170, 393217, 5, -2031634, 393217, 5, -1966098, 327681, 5, -2097169, 458753, 5, -2031633, 393217, 5, -1966097, 393217, 5, -2097168, 393217, 5, -2031632, 262145, 5, -1966096, 327681, 5, -2162707, 458753, 5, -2228242, 262145, 5, -2162706, 458753, 5, -2228241, 262145, 5, -2162705, 393217, 5, -2228240, 458753, 5, -2162704, 262145, 5, -2228239, 458753, 5, -2162703, 393217, 5, -2097167, 458753, 5, -2031631, 458753, 5, -2228238, 393217, 5, -2162702, 327681, 5, -2097166, 327681, 5, -2293776, 393217, 5, -2359311, 262145, 5, -2293775, 262145, 5, -2359310, 393217, 5, -2293774, 393217, 5, -2424845, 262145, 5, -2359309, 458753, 5, -2293773, 393217, 5, -2228237, 458753, 5, -2162701, 458753, 5, -2818056, 327681, 5, -2752520, 393217, 5, -2686984, 393217, 5, -2621448, 262145, 5, -2555912, 262145, 5, -2490376, 458753, 5, -2883591, 327681, 5, -2818055, 393217, 5, -2752519, 327681, 5, -2686983, 327681, 5, -2621447, 458753, 5, -2555911, 458753, 5, -2949126, 262145, 5, -2883590, 458753, 5, -2818054, 458753, 5, -2752518, 393217, 5, -2686982, 327681, 5, -2621446, 262145, 5, -2949125, 262145, 5, -2883589, 262145, 5, -2818053, 327681, 5, -2752517, 393217, 5, -3145731, 262145, 5, -3080195, 327681, 5, -3014659, 262145, 5, -2949123, 327681, 5, -2883587, 458753, 5, -3014660, 262145, 5, -2949124, 327681, 5, -2883588, 327681, 5, -3211266, 327681, 5, -3145730, 327681, 5, -3080194, 393217, 5, -3014658, 327681, 5, -2949122, 458753, 5, -2883586, 393217, 5, -3276801, 458753, 5, -3211265, 262145, 5, -3145729, 393217, 5, -3080193, 458753, 5, -3014657, 393217, 5, -2949121, 327681, 5, -2883585, 458753, 5, -3342336, 262145, 5, -3276800, 393217, 5, -3211264, 327681, 5, -3145728, 393217, 5, -3080192, 327681, 5, -3014656, 393217, 5, -2949120, 262145, 5, -3407871, 458753, 5, -3342335, 393217, 5, -3276799, 393217, 5, -3211263, 327681, 5, -3145727, 327681, 5, -3080191, 262145, 5, -3473406, 327681, 5, -3407870, 458753, 5, -3342334, 393217, 5, -3276798, 393217, 5, -3211262, 262145, 5, -3145726, 262145, 5, -3080190, 262145, 5, -3407869, 393217, 5, -3342333, 393217, 5, -3276797, 458753, 5, -3211261, 393217, 5, 3276876, 262145, 5, 3342412, 327681, 5, 3407948, 327681, 5, 3473484, 393217, 5, 3276877, 262145, 5, 3342413, 458753, 5, 3407949, 327681, 5, 3473485, 327681, 5, 3276878, 393217, 5, 3342414, 458753, 5, 3407950, 327681, 5, 3276879, 458753, 5, 3342415, 393217, 5, 3276880, 262145, 5, 3342356, 262145, 5, 3407892, 393217, 5, 3473428, 262145, 5, 3538964, 458753, 5, 3604500, 458753, 5, 3670036, 393217, 5, 3735572, 393217, 5, 3801108, 262145, 5, 3866644, 327681, 5, 3932180, 262145, 5, 3997716, 393217, 5, 4063252, 458753, 5, 1376212, 458753, 4, 1310676, 327681, 4, 1310675, 393217, 5, 1245139, 327681, 5, -65514, 393217, 5, 22, 327681, 5, 65558, 458753, 5, 131094, 458753, 2, 196630, 458753, 4, 262166, 327681, 5, 327702, 458753, 5, 393238, 327681, 2, 458774, 327681, 5, 524310, 327681, 4, 589846, 458753, 4, 655382, 131073, 5, -65513, 458753, 5, 23, 327681, 5, 65559, 327681, 2, 131095, 262145, 5, 196631, 393217, 5, 262167, 393217, 5, 327703, 262145, 5, 393239, 393217, 5, 458775, 327681, 5, 524311, 327681, 4, 589847, 458753, 5, 655383, 458753, 5, -65512, 458753, 2, 24, 327681, 5, 65560, 327681, 5, 131096, 458753, 4, 196632, 458753, 5, 262168, 393217, 5, 327704, 458753, 5, 393240, 1, 2, 458776, 458753, 5, 524312, 262145, 5, 589848, 393217, 5, 655384, 458753, 5, -65511, 327681, 4, 25, 262145, 4, 65561, 458753, 4, 131097, 327681, 2, 196633, 262145, 5, 262169, 327681, 5, 327705, 327681, 2, 393241, 458753, 2, 458777, 458753, 2, 524313, 327681, 5, 589849, 327681, 5, 655385, 393217, 5, -65510, 458753, 5, 26, 327681, 5, 65562, 458753, 4, 131098, 393217, 5, 196634, 393217, 2, 262170, 262145, 4, 327706, 327681, 5, 393242, 327681, 4, 458778, 196609, 6, 524314, 458753, 5, 589850, 327681, 5, 655386, 262145, 5, -65509, 327681, 5, 27, 458753, 5, 65563, 262145, 5, 131099, 458753, 4, 196635, 131073, 6, 262171, 1, 1, 327707, 1, 1, 393243, 1, 1, 458779, 327681, 6, 524315, 393217, 5, 589851, 262145, 5, 655387, 458753, 5, -65508, 393217, 5, 28, 262145, 5, 65564, 1, 0, 131100, 65537, 6, 196636, 262145, 6, 262172, 65537, 6, 327708, 196609, 6, 393244, 458753, 6, 458780, 262145, 6, 524316, 196609, 0, 589852, 327681, 5, 655388, 327681, 5, -65507, 262145, 5, 29, 327681, 5, 65565, 1, 0, 131101, 1, 6, 196637, 262145, 6, 262173, 65537, 6, 327709, 393217, 6, 393245, 327681, 6, 458781, 393217, 6, 524317, 65537, 0, 589853, 458753, 5, 655389, 458753, 5, -65506, 393217, 5, 30, 262145, 5, 65566, 1, 0, 131102, 262145, 6, 196638, 262145, 6, 262174, 65537, 6, 327710, 65537, 6, 393246, 262145, 6, 458782, 327681, 6, 524318, 327681, 5, 589854, 393217, 5, 655390, 458753, 5, -65505, 327681, 5, 31, 393217, 5, 65567, 458753, 2, 131103, 262145, 6, 196639, 131073, 6, 262175, 327681, 6, 327711, 65537, 6, 393247, 458753, 6, 458783, 262145, 6, 524319, 262145, 5, 589855, 393217, 5, 655391, 327681, 5, -65504, 458753, 5, 32, 458753, 5, 65568, 458753, 2, 131104, 262145, 5, 196640, 131073, 6, 262176, 327681, 6, 327712, 393217, 6, 393248, 393217, 6, 458784, 458753, 5, 524320, 327681, 5, 589856, 393217, 5, 655392, 393217, 5, -65503, 262145, 5, 33, 458753, 5, 65569, 262145, 5, 131105, 393217, 5, 196641, 393217, 5, 262177, 393217, 5, 327713, 262145, 5, 393249, 327681, 5, 458785, 393217, 5, 524321, 458753, 5, 589857, 458753, 5, 655393, 393217, 5, -65502, 393217, 5, 34, 393217, 5, 65570, 458753, 5, 131106, 262145, 5, 196642, 393217, 5, 262178, 327681, 5, 327714, 327681, 5, 393250, 262145, 5, 458786, 262145, 5, 524322, 327681, 5, 589858, 327681, 4, 655394, 131073, 2, -65501, 262145, 5, 35, 458753, 2, 65571, 327681, 5, 131107, 393217, 5, 196643, 262145, 4, 262179, 262145, 5, 327715, 458753, 2, 393251, 262145, 5, 458787, 393217, 5, 524323, 458753, 5, 589859, 458753, 5, 655395, 327681, 5, -65500, 458753, 5, 36, 262145, 5, 65572, 327681, 4, 131108, 1, 2, 196644, 393217, 5, 262180, 327681, 5, 327716, 327681, 5, 393252, 458753, 5, 458788, 327681, 5, 524324, 393217, 5, 589860, 327681, 5, 655396, 458753, 2, -65499, 327681, 5, 37, 327681, 5, 65573, 458753, 5, 131109, 65537, 2, 196645, 458753, 5, 262181, 327681, 5, 327717, 262145, 5, 393253, 393217, 5, 458789, 458753, 5, 524325, 65537, 2, 589861, 458753, 5, 655397, 458753, 5, -65498, 327681, 5, 38, 327681, 5, 65574, 327681, 5, 131110, 327681, 2, 196646, 458753, 5, 262182, 393217, 5, 327718, 327681, 5, 393254, 327681, 5, 458790, 327681, 5, 524326, 327681, 5, 589862, 393217, 5, 655398, 458753, 5, 2752501, 65537, 1, 2686966, 131073, 1, 2752502, 65537, 1)\nlayer_3/name = \"lvl2-tall\"\nlayer_3/y_sort_enabled = true\nlayer_3/z_index = 20\nlayer_3/tile_data = PackedInt32Array(851971, 65536, 1, 851976, 196608, 1, -786448, 458761, 1, -720912, 458761, 1, -655376, 458761, 1, -589840, 327689, 4, -851984, 458761, 4, -589841, 327689, 0, -851985, 131081, 3, -851989, 9, 10, -655377, 65586, 2, -786449, 65586, 2, -1703949, 65536, 1, -1703944, 196608, 1, -1769453, 131072, 1, -1769448, 131072, 1, -1703943, 131081, 12, -1703942, 131081, 12, -1703941, 131081, 12, -1703950, 131081, 12, -1703951, 131081, 12, -1703952, 131081, 12, -1769454, 131081, 12, -1769455, 131081, 12, -1769456, 131081, 12, -1769447, 131081, 12, -1769446, 131081, 12, -1441786, 65545, 2, -1441787, 327689, 1, -1441788, 327689, 1, -1441790, 65545, 4, -1441791, 65545, 4, -1441798, 393225, 4, -1441797, 393225, 2, -1376259, 458761, 11, -1441795, 196617, 2, -1245191, 196611, 1, -1245190, 196611, 3, -1376239, 327689, 12, -1376238, 65545, 2, 1114124, 131122, 2, 1179643, 131132, 1, 1179644, 131132, 1, 1114108, 327689, 4, 1114107, 65545, 1, 1114106, 65545, 1, 1048572, 458761, 1, 983036, 196617, 3, 983035, 393225, 2, 983034, 131081, 12, 983033, 131081, 12, 1114105, 65545, 12, 655346, 60, 0, -589795, 131081, 11, -524259, 196617, 10, -524260, 65545, 10, -589796, 9, 11, -2359278, 196617, 12, -2293742, 196617, 12, -2162670, 196617, 12, -2097134, 196617, 12, -2031598, 458761, 10, -1966062, 196617, 3, -1900526, 196617, 12, 2293769, 196608, 1, 2293762, 65536, 1, 1835010, 0, 1, 1835017, 131072, 1, 4194325, 65536, 1, 5439481, 65539, 2, 3211237, 65539, 2, 1376211, 196611, 2, 1179621, 131132, 1, 2883539, 65586, 2, 1048615, 65586, 2, 1310777, 65586, 0, 1310778, 65586, 0, 3080230, 131081, 3, 2818105, 9, 4, 1900481, 9, 10, 1900485, 131081, 3, 1966021, 65586, 2, 2097093, 65586, 2, 2162629, 327689, 0, 1900486, 458761, 4, 1966022, 458761, 1, 2031558, 458761, 1, 2097094, 458761, 1, 2162630, 327689, 4, 2752527, 393225, 4, 2752528, 393225, 2, 2752530, 196617, 2, 2818066, 458761, 11, 2621458, 393225, 2, 2686974, 9, 11, 2752510, 65545, 10, 2686975, 131081, 11, 5832688, 131081, 12, 5832689, 131081, 12, 5242866, 196617, 12, 5308402, 196617, 12, 5439474, 196617, 12, 5505010, 196617, 12, 5570546, 458761, 10, 5636082, 196617, 3, 5701618, 196617, 12, 5832690, 131081, 12, 1638353, 196617, 12, 1703889, 196617, 12, 1834961, 196617, 12, 2818049, 196617, 10, 2555900, 9, 10, 2490368, 131081, 13, 2818044, 9, 13, 2621433, 0, 1, 2621431, 131072, 1, 2621429, 131072, 1, 2818039, 65536, 1, 2818037, 0, 1, 2818041, 65536, 1)\n\n[node name=\"DecorationTileMap\" type=\"TileMap\" parent=\".\"]\ny_sort_enabled = true\ntile_set = ExtResource(\"12_axlbe\")\nformat = 2\nlayer_0/name = \"lvl1-flat\"\nlayer_0/y_sort_enabled = true\nlayer_0/z_index = 1\nlayer_0/tile_data = PackedInt32Array(-4521991, 262152, 0, -4653061, 393224, 0, -4784131, 262152, 65536, -4653064, 196623, 0, -4784133, 196623, 1, -4521989, 196623, 1, -4718595, 196623, 196608, -2293767, 196623, 1, -2162696, 9, 1, -1376290, 262152, 0, -1179670, 393224, 0, -1245202, 8, 0, -1376264, 393224, 65537, -1114132, 196623, 65536, -1572894, 196623, 1, -1638437, 196623, 131072, -1310744, 196623, 131072, -1245191, 196623, 65537, -1376262, 196623, 196608, -1179687, 196623, 196608, -1900551, 393224, 65536, -2031621, 262152, 65536, -3932162, 393224, 65536, -1179686, 196618, 1, -3473410, 262152, 0, -5963813, 15, 65536, -1835043, 8, 65536, -3538983, 196623, 131072, -3932200, 196623, 131072, 6422553, 131087, 0, 6357019, 131087, 0, 5701660, 131087, 65537, 5570584, 196623, 196609, 6160413, 131087, 65536, 6357015, 131087, 65537, 2686990, 131087, 196609, 2686986, 196623, 327680, 3145733, 131087, 131072, 3080172, 196623, 327680, 2752490, 131087, 196609, 1769449, 131087, 65536, 851946, 196623, 65536, 1834991, 196623, 131073, 2752502, 131087, 196609, 2686967, 196623, 65537, 2621428, 131087, 1, -3866600, 196623, 393216, -4849634, 196623, 131073, -4849640, 131087, 196608, 851996, 196618, 1, 655440, 131076, 0, -5242791, 9, 1, -5373863, 9, 65538, -4325332, 196623, 196608, -4325331, 196618, 1, -4456389, 196623, 131072, -4325315, 393224, 0, -4259777, 196623, 65536, -4390847, 8, 0, -982967, 196623, 196608, -982966, 196618, 1, -982950, 393224, 0, -917412, 196623, 65536, -1048482, 8, 0, 917574, 10, 3, 917576, 262152, 0, 1179720, 196623, 131073, 655433, 393224, 1, 1179722, 393224, 0, 852046, 393224, 65536, 3342365, 10, 3, 3014686, 196623, 196609, 3211294, 10, 3, 3342367, 262152, 0, 3604511, 196623, 131073, 3080224, 393224, 1, 3604513, 393224, 0, 3276837, 393224, 65536, -4521935, 262152, 0, -4980781, 6, 65540, -4718633, 262152, 0, -4915240, 131087, 0, -3801096, 10, 3, -4128775, 196623, 196609, -3932167, 10, 3, -3801094, 262152, 0, -3538950, 196623, 131073, -4259845, 196623, 131072, -4063237, 393224, 1, -3538948, 393224, 0, -1376200, 10, 3, -1703879, 196623, 196609, -1507271, 10, 3, -1376198, 262152, 0, -1114054, 196623, 131073, -1834949, 196623, 131072, -1638341, 393224, 1, -1114052, 393224, 0, -1114034, 8, 65536, -3604521, 262152, 0, -3407908, 262152, 0, 11665518, 10, 3, 11665520, 262152, 0, 11927664, 196623, 131073, 11403377, 393224, 1, 11927666, 393224, 0, 11599990, 393224, 65536, 11403384, 131076, 0, 18219094, 10, 3, 18219096, 262152, 0, 18481240, 196623, 131073, 17956953, 393224, 1, 18481242, 393224, 0, 18153566, 393224, 65536, 17956960, 131076, 0, 11665411, 131087, 65536, 10747908, 196623, 65536, 12648452, 131087, 196609, 12976134, 196623, 327680, 11730953, 196623, 131073, 12517390, 131087, 1, 12648464, 131087, 196609, 12582929, 196623, 65537, 12845081, 131087, 65536, 11927578, 196623, 65536, 13828122, 131087, 196609, 14155804, 196623, 327680, 12910623, 196623, 131073, 13697060, 131087, 1, 13828134, 131087, 196609, 13762599, 196623, 65537, 9568086, 131087, 65536, 8650583, 196623, 65536, 10551127, 131087, 196609, 10878809, 196623, 327680, 9633628, 196623, 131073, 10420065, 131087, 1, 10551139, 131087, 196609, 10485604, 196623, 65537, 16318487, 262152, 0, 15990808, 196623, 131072, 16384025, 196623, 131072, 18743321, 196623, 196608, 18743322, 196618, 1, 18284571, 196623, 131072, 16515100, 262152, 0, 18087965, 8, 65536, 18546718, 262152, 0, 8126684, 262152, 0, 7799005, 196623, 131072, 8192222, 196623, 131072, 10551518, 196623, 196608, 10551519, 196618, 1, 10092768, 196623, 131072, 8323297, 262152, 0, 9896162, 8, 65536, 10354915, 262152, 0, 20250619, 10, 3, 19922940, 196623, 196609, 20119548, 10, 3, 20250621, 262152, 0, 20512765, 196623, 131073, 19791870, 196623, 131072, 19988478, 393224, 1, 20512767, 393224, 0, 12386182, 10, 3, 12058503, 196623, 196609, 12255111, 10, 3, 12386184, 262152, 0, 12648328, 196623, 131073, 11927433, 196623, 131072, 12124041, 393224, 1, 12648330, 393224, 0, 8847303, 10, 3, 8519624, 196623, 196609, 8716232, 10, 3, 8847305, 262152, 0, 9109449, 196623, 131073, 8388554, 196623, 131072, 8585162, 393224, 1, 9109451, 393224, 0, 6291284, 196623, 0, 7143252, 10, 3, 6422357, 262152, 0, 6815573, 196623, 196609, 7012181, 10, 3, 7143254, 262152, 0, 7405398, 196623, 131073, 6160215, 196623, 1, 6291287, 393224, 0, 6422359, 196623, 1, 6684503, 196623, 131072, 6881111, 393224, 1, 7405400, 393224, 0, 6160217, 262152, 65536, 6225753, 196623, 196608, 7012186, 393224, 65536, 7470938, 262152, 0, 11141295, 196623, 0, 11993263, 10, 3, 11272368, 262152, 0, 11665584, 196623, 196609, 11862192, 10, 3, 11993265, 262152, 0, 12255409, 196623, 131073, 11010226, 196623, 1, 11141298, 393224, 0, 11272370, 196623, 1, 11534514, 196623, 131072, 11731122, 393224, 1, 12255411, 393224, 0, 11010228, 262152, 65536, 11075764, 196623, 196608, 11862197, 393224, 65536, 12320949, 262152, 0)\nlayer_1/name = \"lvl1-tall\"\nlayer_1/y_sort_enabled = true\nlayer_1/z_index = 10\nlayer_1/tile_data = PackedInt32Array(-917544, 131074, 18, -917542, 524290, 17, -4915198, 524290, 20, -3669992, 2, 65554, -983042, 17, 0, -1245224, 131089, 0, -3342344, 131089, 65536, -4784136, 17, 65536, -3473383, 65553, 65538, -4849633, 393218, 16, 1245160, 2, 18, 1441768, 393218, 16, 1114088, 2, 0, 2883560, 131074, 65554, 3211241, 458754, 0, 6094872, 2, 65554, 6225943, 458754, 10, 5898264, 458754, 0, -3669991, 17, 2, -4915168, 65553, 0, -4784097, 17, 65538, 1245162, 17, 65538, 1507306, 17, 2, 983018, 65553, 0, 3211244, 131089, 65536, 2818025, 65553, 65536, 5767194, 65553, 65536, 6094874, 17, 0, 5963803, 17, 65536, 6619161, 17, 2, 5111833, 17, 0, 2686988, 65553, 2, 524292, 131100, 0, 2555914, 28, 0, -2621417, 65568, 0, -2162665, 65568, 1, 2555912, 65568, 0, 2555917, 262176, 0, 2555916, 327712, 0, 2293734, 22, 1, -1048625, 65554, 131074, -1376301, 131090, 131072, -1703979, 16, 1, -1507371, 65552, 1, 1114144, 65553, 65536, -1179614, 524290, 17, 589904, 262146, 8, 1572937, 9, 1, 720975, 16, 0, -1048542, 65553, 2, -4849599, 131089, 0, -4784063, 65553, 0, -1179587, 196623, 1, -5373864, 65553, 2, -1048520, 131074, 18, -917448, 458766, 1, -1179591, 65552, 1, -1048519, 65553, 0, 4718615, 22, 0, 17956823, 22, 0, 19464151, 458754, 10, 19136472, 458754, 0, 19333080, 2, 65554, 18350041, 17, 0, 19857369, 17, 2, 19005402, 65553, 65536, 19333082, 17, 0, 19202011, 17, 65536, 11730853, 2, 0, 11861925, 2, 18, 12058533, 393218, 16, 11599783, 65553, 0, 11861927, 17, 65538, 12124071, 17, 2, 10682541, 2, 0, 10813613, 2, 18, 11010221, 393218, 16, 10551471, 65553, 0, 10813615, 17, 65538, 11075759, 17, 2, 8978519, 17, 65536, 8912993, 524290, 20, 13893700, 17, 65536, 13828174, 524290, 20, 14024682, 131089, 0, 14090218, 65553, 0, 23199843, 131089, 0, 23265379, 65553, 0, 22740954, 131089, 0, 22806490, 65553, 0, 11796504, 2, 65554, 11796505, 17, 2, 11993113, 65553, 65538, 12845229, 2, 65554, 12845230, 17, 2, 13041838, 65553, 65538, 6160611, 2, 65554, 6160612, 17, 2, 6357220, 65553, 65538, 13565929, 131074, 65554, 13500394, 65553, 65536, 13893610, 458754, 0, 13893613, 131089, 65536, 21561336, 131074, 65554, 21495801, 65553, 65536, 21889017, 458754, 0, 21889020, 131089, 65536)\nlayer_2/name = \"lvl2-flat\"\nlayer_2/y_sort_enabled = true\nlayer_2/y_sort_origin = 128\nlayer_2/z_index = 11\nlayer_2/tile_data = PackedInt32Array(-4063301, 196623, 131072, -4194371, 196618, 65537, -4522048, 10, 0, -3932224, 131087, 196608, -4653119, 196623, 1, -4915262, 196618, 1, -4784190, 196623, 1, -4259902, 131087, 196608, -4194366, 196623, 131072, -4980795, 196623, 131072, -4128826, 131087, 196608, -4653112, 131087, 196608, -7077833, 15, 0, -6946765, 196623, 1, -6619077, 131072, 1, -6488016, 65536, 0, -5898258, 196623, 1, -5046324, 196623, 1, -5439537, 196623, 0, -4718619, 131087, 0, -4915222, 196623, 1, -5046202, 15, 0, -4915123, 131087, 0, -4980660, 16, 0, -6815682, 65552, 0, -524203, 131087, 0, -458665, 196623, 1, -4915126, 196623, 1, -4652947, 15, 0, -4980603, 15, 0, 10682333, 393224, 0, 10682351, 393224, 1, 10813424, 327693, 0, 10682340, 131087, 1, 10616813, 131087, 1, 10420213, 65553, 2, 10354668, 65558, 0)\nlayer_3/name = \"lvl2-tall\"\nlayer_3/y_sort_enabled = true\nlayer_3/z_index = 20\nlayer_3/tile_data = PackedInt32Array(-6356973, 458754, 65536, 5570634, 2, 65544, 5701708, 2, 65549, 3735642, 196640, 0, 3539035, 131104, 1, 3670108, 65568, 0, 786536, 196628, 0, 917608, 65558, 1, 1376360, 196628, 0, 2621546, 2, 65544, -1048468, 65553, 65536, 2752620, 2, 65549, -982931, 65553, 0, -1507218, 196628, 0, 786542, 65558, 0, -917392, 65553, 2, -1245071, 65553, 65536, -1048463, 65553, 65536, 983153, 17, 0, -917389, 65553, 65536, -851853, 65553, 0, -786317, 65564, 0, -1048459, 65553, 2, -720777, 131096, 1, 1704055, 196632, 2, 1376379, 65564, 0, 1638523, 65564, 0, 1376381, 17, 2, 786559, 327704, 1, 1441919, 393218, 16, 1310848, 17, 2, 1310849, 65553, 2, 1441921, 17, 0, 1376387, 65553, 2, 1441923, 65553, 2, 1507459, 65553, 2, 1572995, 65564, 0, 983172, 65564, 0, 786567, 196632, 2, -2031690, 11, 0, -4587587, 65553, 65536, -4587586, 458763, 65536, -4128834, 65553, 65536, -4259905, 65553, 2, -4194369, 65553, 65536, -4128833, 131074, 18, -4063296, 65553, 2, -4128831, 17, 2, -3997759, 65553, 65536, -4849725, 65553, 2, -4718653, 524290, 20, -4849724, 65553, 0, -4259892, 393224, 65536, 655472, 131100, 0, 1245300, 65553, 2, 917621, 458763, 0, 1310837, 65553, 0, 1310838, 17, 65536, 1179767, 65553, 2, 1310840, 65553, 0, 917625, 65553, 65538, 852090, 65553, 0, 1048698, 65553, 0, 786555, 131100, 0, 1048699, 17, 65538, 1441930, 524290, 65553, -2818121, 131074, 18, -7077835, 458754, 0, -6946761, 131089, 0, -7208907, 14, 0, -5963782, 16, 0, -5701637, 65552, 0, -5701638, 65553, 2, -5832709, 327693, 1, -5767187, 131089, 0, -262179, 458754, 65546, -131107, 65553, 0, -4980627, 262157, 2, -851858, 458763, 0, -5832571, 196622, 0, -5177207, 11, 0, 9699086, 196628, 0, 9830158, 65558, 1, 10288910, 196628, 0, 9699092, 65558, 0, 9568022, 131100, 0, 9895703, 17, 0, 10157850, 65553, 2, 9830171, 458763, 0, 10223387, 65553, 0, 10223388, 17, 65536, 10092317, 65553, 2, 10616605, 196632, 2, 10223390, 65553, 0, 9830175, 65553, 65538, 9764640, 65553, 0, 9961248, 65553, 0, 9699105, 131100, 0, 9961249, 17, 65538, 10288929, 65564, 0, 10551073, 65564, 0, 10288931, 17, 2, 10354469, 393218, 16, 10223398, 17, 2, 10223399, 65553, 2, 10354471, 17, 0, 10288937, 65553, 2, 10354473, 65553, 2, 10420009, 65553, 2, 10485545, 65564, 0, 9895722, 65564, 0, 9699117, 196632, 2, 10354480, 524290, 65553, 15335551, 196622, 0, 15990915, 11, 0, 20250543, 65553, 65536, 20250544, 458763, 65536, 20709296, 65553, 65536, 20578225, 65553, 2, 20643761, 65553, 65536, 20709297, 131074, 18, 20774834, 65553, 2, 20709299, 17, 2, 20840371, 65553, 65536, 19988405, 65553, 2, 20119477, 524290, 20, 19988406, 65553, 0, 20578238, 393224, 65536, 16973786, 393218, 16)\n\n[node name=\"BuildableAreaParent\" type=\"Node2D\" parent=\".\"]\nposition = Vector2(0, -32)\n\n[node name=\"BuildableArea0\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\ntile_map_data = PackedByteArray(\"AADy/97/AAADAAAAAADy/9//AAADAAAAAADy/+D/AAADAAAAAADy/+H/AAADAAAAAADy/+L/AAADAAAAAADy/+P/AAADAAAAAADy/+T/AAADAAAAAADy/+X/AAADAAAAAADy/+b/AAADAAAAAADy/+f/AAADAAAAAADy/+j/AAADAAAAAADy/+n/AAADAAAAAADy/+r/AAADAAAAAADy/+v/AAADAAAAAADy/+z/AAADAAAAAADy/+3/AAADAAAAAADy/+7/AAADAAAAAADy/+//AAADAAAAAADy//D/AAADAAAAAADz/97/AAADAAAAAADz/9//AAADAAAAAADz/+D/AAADAAAAAADz/+H/AAADAAAAAADz/+L/AAADAAAAAADz/+P/AAADAAAAAADz/+T/AAADAAAAAADz/+X/AAADAAAAAADz/+b/AAADAAAAAADz/+f/AAADAAAAAADz/+j/AAADAAAAAADz/+n/AAADAAAAAADz/+r/AAADAAAAAADz/+v/AAADAAAAAADz/+z/AAADAAAAAADz/+3/AAADAAAAAADz/+7/AAADAAAAAADz/+//AAADAAAAAADz//D/AAADAAAAAAD0/97/AAADAAAAAAD0/9//AAADAAAAAAD0/+D/AAADAAAAAAD0/+H/AAADAAAAAAD0/+L/AAADAAAAAAD0/+P/AAADAAAAAAD0/+T/AAADAAAAAAD0/+X/AAADAAAAAAD0/+b/AAADAAAAAAD0/+f/AAADAAAAAAD0/+j/AAADAAAAAAD0/+n/AAADAAAAAAD0/+r/AAADAAAAAAD0/+v/AAADAAAAAAD0/+z/AAADAAAAAAD0/+3/AAADAAAAAAD0/+7/AAADAAAAAAD0/+//AAADAAAAAAD0//D/AAADAAAAAAD1/97/AAADAAAAAAD1/9//AAADAAAAAAD1/+D/AAADAAAAAAD1/+H/AAADAAAAAAD1/+L/AAADAAAAAAD1/+P/AAADAAAAAAD1/+T/AAADAAAAAAD1/+X/AAADAAAAAAD1/+b/AAADAAAAAAD1/+f/AAADAAAAAAD1/+j/AAADAAAAAAD1/+n/AAADAAAAAAD1/+r/AAADAAAAAAD1/+v/AAADAAAAAAD1/+z/AAADAAAAAAD1/+3/AAADAAAAAAD1/+7/AAADAAAAAAD1/+//AAADAAAAAAD1//D/AAADAAAAAAD2/97/AAADAAAAAAD2/9//AAADAAAAAAD2/+D/AAADAAAAAAD2/+H/AAADAAAAAAD2/+L/AAADAAAAAAD2/+P/AAADAAAAAAD2/+T/AAADAAAAAAD2/+X/AAADAAAAAAD2/+b/AAADAAAAAAD2/+f/AAADAAAAAAD2/+j/AAADAAAAAAD2/+n/AAADAAAAAAD2/+r/AAADAAAAAAD2/+v/AAADAAAAAAD2/+z/AAADAAAAAAD2/+3/AAADAAAAAAD2/+7/AAADAAAAAAD2/+//AAADAAAAAAD2//D/AAADAAAAAAD3/97/AAADAAAAAAD3/9//AAADAAAAAAD3/+D/AAADAAAAAAD3/+H/AAADAAAAAAD3/+L/AAADAAAAAAD3/+P/AAADAAAAAAD3/+T/AAADAAAAAAD3/+X/AAADAAAAAAD3/+b/AAADAAAAAAD3/+f/AAADAAAAAAD3/+j/AAADAAAAAAD3/+n/AAADAAAAAAD3/+r/AAADAAAAAAD3/+v/AAADAAAAAAD3/+z/AAADAAAAAAD3/+3/AAADAAAAAAD3/+7/AAADAAAAAAD3/+//AAADAAAAAAD3//D/AAADAAAAAADx//v/AAADAAAAAADx//z/AAADAAAAAADx//3/AAADAAAAAADx//7/AAADAAAAAADx////AAADAAAAAADx/wAAAAADAAAAAADy//v/AAADAAAAAADy//z/AAADAAAAAADy//3/AAADAAAAAADy//7/AAADAAAAAADy////AAADAAAAAADy/wAAAAADAAAAAADz//v/AAADAAAAAADz//z/AAADAAAAAADz//3/AAADAAAAAADz//7/AAADAAAAAADz////AAADAAAAAADz/wAAAAADAAAAAAD0//v/AAADAAAAAAD0//z/AAADAAAAAAD0//3/AAADAAAAAAD0//7/AAADAAAAAAD0////AAADAAAAAAD0/wAAAAADAAAAAAD1//v/AAADAAAAAAD1//z/AAADAAAAAAD1//3/AAADAAAAAAD1//7/AAADAAAAAAD1////AAADAAAAAAD1/wAAAAADAAAAAAD2//v/AAADAAAAAAD2//z/AAADAAAAAAD2//3/AAADAAAAAAD2//7/AAADAAAAAAD2////AAADAAAAAAD2/wAAAAADAAAAAAD3//v/AAADAAAAAAD3//z/AAADAAAAAAD3//3/AAADAAAAAAD3//7/AAADAAAAAAD3////AAADAAAAAAD3/wAAAAADAAAAAAD4//v/AAADAAAAAAD4//z/AAADAAAAAAD4//3/AAADAAAAAAD4//7/AAADAAAAAAD4////AAADAAAAAAD4/wAAAAADAAAAAAD5//v/AAADAAAAAAD5//z/AAADAAAAAAD5//3/AAADAAAAAAD5//7/AAADAAAAAAD5////AAADAAAAAAD5/wAAAAADAAAAAAD6//v/AAADAAAAAAD6//z/AAADAAAAAAD6//3/AAADAAAAAAD6//7/AAADAAAAAAD6////AAADAAAAAAD6/wAAAAADAAAAAAD7//v/AAADAAAAAAD7//z/AAADAAAAAAD7//3/AAADAAAAAAD7//7/AAADAAAAAAD7////AAADAAAAAAD7/wAAAAADAAAAAAD8//v/AAADAAAAAAD8//z/AAADAAAAAAD8//3/AAADAAAAAAD8//7/AAADAAAAAAD8////AAADAAAAAAD8/wAAAAADAAAAAAD9//v/AAADAAAAAAD9//z/AAADAAAAAAD9//3/AAADAAAAAAD9//7/AAADAAAAAAD9////AAADAAAAAAD9/wAAAAADAAAAAAD+//v/AAADAAAAAAD+//z/AAADAAAAAAD+//3/AAADAAAAAAD+//7/AAADAAAAAAD+////AAADAAAAAAD+/wAAAAADAAAAAAD///v/AAADAAAAAAD///z/AAADAAAAAAD///3/AAADAAAAAAD///7/AAADAAAAAAD/////AAADAAAAAAD//wAAAAADAAAAAAAAAPv/AAADAAAAAAAAAPz/AAADAAAAAAAAAP3/AAADAAAAAAAAAP7/AAADAAAAAAAAAP//AAADAAAAAAAAAAAAAAADAAAAAAABAPv/AAADAAAAAAABAPz/AAADAAAAAAABAP3/AAADAAAAAAABAP7/AAADAAAAAAABAP//AAADAAAAAAABAAAAAAADAAAAAAACAPv/AAADAAAAAAACAPz/AAADAAAAAAACAP3/AAADAAAAAAACAP7/AAADAAAAAAACAP//AAADAAAAAAACAAAAAAADAAAAAAADAPv/AAADAAAAAAADAPz/AAADAAAAAAADAP3/AAADAAAAAAADAP7/AAADAAAAAAADAP//AAADAAAAAAADAAAAAAADAAAAAAAEAPv/AAADAAAAAAAEAPz/AAADAAAAAAAEAP3/AAADAAAAAAAEAP7/AAADAAAAAAAEAP//AAADAAAAAAAEAAAAAAADAAAAAAAFAPv/AAADAAAAAAAFAPz/AAADAAAAAAAFAP3/AAADAAAAAAAFAP7/AAADAAAAAAAFAP//AAADAAAAAAAFAAAAAAADAAAAAAAGAPv/AAADAAAAAAAGAPz/AAADAAAAAAAGAP3/AAADAAAAAAAGAP7/AAADAAAAAAAGAP//AAADAAAAAAAGAAAAAAADAAAAAAAHAPv/AAADAAAAAAAHAPz/AAADAAAAAAAHAP3/AAADAAAAAAAHAP7/AAADAAAAAAAHAP//AAADAAAAAAAHAAAAAAADAAAAAAACAOH/AAADAAAAAAACAOL/AAADAAAAAAACAOP/AAADAAAAAAACAOT/AAADAAAAAAACAOX/AAADAAAAAAACAOb/AAADAAAAAAACAOf/AAADAAAAAAACAOj/AAADAAAAAAACAOn/AAADAAAAAAACAOr/AAADAAAAAAACAOv/AAADAAAAAAACAOz/AAADAAAAAAACAO3/AAADAAAAAAACAO7/AAADAAAAAAACAO//AAADAAAAAAACAPD/AAADAAAAAAACAPH/AAADAAAAAAACAPL/AAADAAAAAAACAPP/AAADAAAAAAACAPT/AAADAAAAAAACAPX/AAADAAAAAAACAPb/AAADAAAAAAACAPf/AAADAAAAAAACAPj/AAADAAAAAAACAPn/AAADAAAAAAACAPr/AAADAAAAAAADAOH/AAADAAAAAAADAOL/AAADAAAAAAADAOP/AAADAAAAAAADAOT/AAADAAAAAAADAOX/AAADAAAAAAADAOb/AAADAAAAAAADAOf/AAADAAAAAAADAOj/AAADAAAAAAADAOn/AAADAAAAAAADAOr/AAADAAAAAAADAOv/AAADAAAAAAADAOz/AAADAAAAAAADAO3/AAADAAAAAAADAO7/AAADAAAAAAADAO//AAADAAAAAAADAPD/AAADAAAAAAADAPH/AAADAAAAAAADAPL/AAADAAAAAAADAPP/AAADAAAAAAADAPT/AAADAAAAAAADAPX/AAADAAAAAAADAPb/AAADAAAAAAADAPf/AAADAAAAAAADAPj/AAADAAAAAAADAPn/AAADAAAAAAADAPr/AAADAAAAAAAEAOH/AAADAAAAAAAEAOL/AAADAAAAAAAEAOP/AAADAAAAAAAEAOT/AAADAAAAAAAEAOX/AAADAAAAAAAEAOb/AAADAAAAAAAEAOf/AAADAAAAAAAEAOj/AAADAAAAAAAEAOn/AAADAAAAAAAEAOr/AAADAAAAAAAEAOv/AAADAAAAAAAEAOz/AAADAAAAAAAEAO3/AAADAAAAAAAEAO7/AAADAAAAAAAEAO//AAADAAAAAAAEAPD/AAADAAAAAAAEAPH/AAADAAAAAAAEAPL/AAADAAAAAAAEAPP/AAADAAAAAAAEAPT/AAADAAAAAAAEAPX/AAADAAAAAAAEAPb/AAADAAAAAAAEAPf/AAADAAAAAAAEAPj/AAADAAAAAAAEAPn/AAADAAAAAAAEAPr/AAADAAAAAAAFAOH/AAADAAAAAAAFAOL/AAADAAAAAAAFAOP/AAADAAAAAAAFAOT/AAADAAAAAAAFAOX/AAADAAAAAAAFAOb/AAADAAAAAAAFAOf/AAADAAAAAAAFAOj/AAADAAAAAAAFAOn/AAADAAAAAAAFAOr/AAADAAAAAAAFAOv/AAADAAAAAAAFAOz/AAADAAAAAAAFAO3/AAADAAAAAAAFAO7/AAADAAAAAAAFAO//AAADAAAAAAAFAPD/AAADAAAAAAAFAPH/AAADAAAAAAAFAPL/AAADAAAAAAAFAPP/AAADAAAAAAAFAPT/AAADAAAAAAAFAPX/AAADAAAAAAAFAPb/AAADAAAAAAAFAPf/AAADAAAAAAAFAPj/AAADAAAAAAAFAPn/AAADAAAAAAAFAPr/AAADAAAAAAAGAOH/AAADAAAAAAAGAOL/AAADAAAAAAAGAOP/AAADAAAAAAAGAOT/AAADAAAAAAAGAOX/AAADAAAAAAAGAOb/AAADAAAAAAAGAOf/AAADAAAAAAAGAOj/AAADAAAAAAAGAOn/AAADAAAAAAAGAOr/AAADAAAAAAAGAOv/AAADAAAAAAAGAOz/AAADAAAAAAAGAO3/AAADAAAAAAAGAO7/AAADAAAAAAAGAO//AAADAAAAAAAGAPD/AAADAAAAAAAGAPH/AAADAAAAAAAGAPL/AAADAAAAAAAGAPP/AAADAAAAAAAGAPT/AAADAAAAAAAGAPX/AAADAAAAAAAGAPb/AAADAAAAAAAGAPf/AAADAAAAAAAGAPj/AAADAAAAAAAGAPn/AAADAAAAAAAGAPr/AAADAAAAAAAHAOH/AAADAAAAAAAHAOL/AAADAAAAAAAHAOP/AAADAAAAAAAHAOT/AAADAAAAAAAHAOX/AAADAAAAAAAHAOb/AAADAAAAAAAHAOf/AAADAAAAAAAHAOj/AAADAAAAAAAHAOn/AAADAAAAAAAHAOr/AAADAAAAAAAHAOv/AAADAAAAAAAHAOz/AAADAAAAAAAHAO3/AAADAAAAAAAHAO7/AAADAAAAAAAHAO//AAADAAAAAAAHAPD/AAADAAAAAAAHAPH/AAADAAAAAAAHAPL/AAADAAAAAAAHAPP/AAADAAAAAAAHAPT/AAADAAAAAAAHAPX/AAADAAAAAAAHAPb/AAADAAAAAAAHAPf/AAADAAAAAAAHAPj/AAADAAAAAAAHAPn/AAADAAAAAAAHAPr/AAADAAAAAAD6/wsAAAADAAAAAAD6/wwAAAADAAAAAAD6/w0AAAADAAAAAAD6/w4AAAADAAAAAAD6/w8AAAADAAAAAAD6/xAAAAADAAAAAAD7/wsAAAADAAAAAAD7/wwAAAADAAAAAAD7/w0AAAADAAAAAAD7/w4AAAADAAAAAAD7/w8AAAADAAAAAAD7/xAAAAADAAAAAAD8/wsAAAADAAAAAAD8/wwAAAADAAAAAAD8/w0AAAADAAAAAAD8/w4AAAADAAAAAAD8/w8AAAADAAAAAAD8/xAAAAADAAAAAAD9/wsAAAADAAAAAAD9/wwAAAADAAAAAAD9/w0AAAADAAAAAAD9/w4AAAADAAAAAAD9/w8AAAADAAAAAAD9/xAAAAADAAAAAAD+/wsAAAADAAAAAAD+/wwAAAADAAAAAAD+/w0AAAADAAAAAAD+/w4AAAADAAAAAAD+/w8AAAADAAAAAAD+/xAAAAADAAAAAAD//wsAAAADAAAAAAD//wwAAAADAAAAAAD//w0AAAADAAAAAAD//w4AAAADAAAAAAD//w8AAAADAAAAAAD//xAAAAADAAAAAAAAAAsAAAADAAAAAAAAAAwAAAADAAAAAAAAAA0AAAADAAAAAAAAAA4AAAADAAAAAAAAAA8AAAADAAAAAAAAABAAAAADAAAAAAABAAsAAAADAAAAAAABAAwAAAADAAAAAAABAA0AAAADAAAAAAABAA4AAAADAAAAAAABAA8AAAADAAAAAAABABAAAAADAAAAAAACAAsAAAADAAAAAAACAAwAAAADAAAAAAACAA0AAAADAAAAAAACAA4AAAADAAAAAAACAA8AAAADAAAAAAACABAAAAADAAAAAAADAAsAAAADAAAAAAADAAwAAAADAAAAAAADAA0AAAADAAAAAAADAA4AAAADAAAAAAADAA8AAAADAAAAAAADABAAAAADAAAAAAAEAAsAAAADAAAAAAAEAAwAAAADAAAAAAAEAA0AAAADAAAAAAAEAA4AAAADAAAAAAAEAA8AAAADAAAAAAAEABAAAAADAAAAAAAFAAsAAAADAAAAAAAFAAwAAAADAAAAAAAFAA0AAAADAAAAAAAFAA4AAAADAAAAAAAFAA8AAAADAAAAAAAFABAAAAADAAAAAAAGAAsAAAADAAAAAAAGAAwAAAADAAAAAAAGAA0AAAADAAAAAAAGAA4AAAADAAAAAAAGAA8AAAADAAAAAAAGABAAAAADAAAAAAAHAAsAAAADAAAAAAAHAAwAAAADAAAAAAAHAA0AAAADAAAAAAAHAA4AAAADAAAAAAAHAA8AAAADAAAAAAAHABAAAAADAAAAAAAIAAsAAAADAAAAAAAIAAwAAAADAAAAAAAIAA0AAAADAAAAAAAIAA4AAAADAAAAAAAIAA8AAAADAAAAAAAIABAAAAADAAAAAAAJAAsAAAADAAAAAAAJAAwAAAADAAAAAAAJAA0AAAADAAAAAAAJAA4AAAADAAAAAAAJAA8AAAADAAAAAAAJABAAAAADAAAAAAAKAAsAAAADAAAAAAAKAAwAAAADAAAAAAAKAA0AAAADAAAAAAAKAA4AAAADAAAAAAAKAA8AAAADAAAAAAAKABAAAAADAAAAAAALAAsAAAADAAAAAAALAAwAAAADAAAAAAALAA0AAAADAAAAAAALAA4AAAADAAAAAAALAA8AAAADAAAAAAALABAAAAADAAAAAAAMAAsAAAADAAAAAAAMAAwAAAADAAAAAAAMAA0AAAADAAAAAAAMAA4AAAADAAAAAAAMAA8AAAADAAAAAAAMABAAAAADAAAAAAA=\")\n\n[node name=\"BuildableArea1\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(0, 0.25, 1, 0.211765)\ntile_map_data = PackedByteArray(\"AAASAOH/AAADAAAAAAASAOL/AAADAAAAAAASAOP/AAADAAAAAAASAOT/AAADAAAAAAASAOX/AAADAAAAAAASAOb/AAADAAAAAAASAOf/AAADAAAAAAASAOj/AAADAAAAAAASAOn/AAADAAAAAAASAOr/AAADAAAAAAASAOv/AAADAAAAAAASAOz/AAADAAAAAAASAO3/AAADAAAAAAASAO7/AAADAAAAAAASAO//AAADAAAAAAASAPD/AAADAAAAAAASAPH/AAADAAAAAAASAPL/AAADAAAAAAASAPP/AAADAAAAAAASAPT/AAADAAAAAAASAPX/AAADAAAAAAASAPb/AAADAAAAAAASAPf/AAADAAAAAAASAPj/AAADAAAAAAASAPn/AAADAAAAAAASAPr/AAADAAAAAAASAPv/AAADAAAAAAASAPz/AAADAAAAAAASAP3/AAADAAAAAAASAP7/AAADAAAAAAASAP//AAADAAAAAAASAAAAAAADAAAAAAATAOH/AAADAAAAAAATAOL/AAADAAAAAAATAOP/AAADAAAAAAATAOT/AAADAAAAAAATAOX/AAADAAAAAAATAOb/AAADAAAAAAATAOf/AAADAAAAAAATAOj/AAADAAAAAAATAOn/AAADAAAAAAATAOr/AAADAAAAAAATAOv/AAADAAAAAAATAOz/AAADAAAAAAATAO3/AAADAAAAAAATAO7/AAADAAAAAAATAO//AAADAAAAAAATAPD/AAADAAAAAAATAPH/AAADAAAAAAATAPL/AAADAAAAAAATAPP/AAADAAAAAAATAPT/AAADAAAAAAATAPX/AAADAAAAAAATAPb/AAADAAAAAAATAPf/AAADAAAAAAATAPj/AAADAAAAAAATAPn/AAADAAAAAAATAPr/AAADAAAAAAATAPv/AAADAAAAAAATAPz/AAADAAAAAAATAP3/AAADAAAAAAATAP7/AAADAAAAAAATAP//AAADAAAAAAATAAAAAAADAAAAAAAUAOH/AAADAAAAAAAUAOL/AAADAAAAAAAUAOP/AAADAAAAAAAUAOT/AAADAAAAAAAUAOX/AAADAAAAAAAUAOb/AAADAAAAAAAUAOf/AAADAAAAAAAUAOj/AAADAAAAAAAUAOn/AAADAAAAAAAUAOr/AAADAAAAAAAUAOv/AAADAAAAAAAUAOz/AAADAAAAAAAUAO3/AAADAAAAAAAUAO7/AAADAAAAAAAUAO//AAADAAAAAAAUAPD/AAADAAAAAAAUAPH/AAADAAAAAAAUAPL/AAADAAAAAAAUAPP/AAADAAAAAAAUAPT/AAADAAAAAAAUAPX/AAADAAAAAAAUAPb/AAADAAAAAAAUAPf/AAADAAAAAAAUAPj/AAADAAAAAAAUAPn/AAADAAAAAAAUAPr/AAADAAAAAAAUAPv/AAADAAAAAAAUAPz/AAADAAAAAAAUAP3/AAADAAAAAAAUAP7/AAADAAAAAAAUAP//AAADAAAAAAAUAAAAAAADAAAAAAAVAOH/AAADAAAAAAAVAOL/AAADAAAAAAAVAOP/AAADAAAAAAAVAOT/AAADAAAAAAAVAOX/AAADAAAAAAAVAOb/AAADAAAAAAAVAOf/AAADAAAAAAAVAOj/AAADAAAAAAAVAOn/AAADAAAAAAAVAOr/AAADAAAAAAAVAOv/AAADAAAAAAAVAOz/AAADAAAAAAAVAO3/AAADAAAAAAAVAO7/AAADAAAAAAAVAO//AAADAAAAAAAVAPD/AAADAAAAAAAVAPH/AAADAAAAAAAVAPL/AAADAAAAAAAVAPP/AAADAAAAAAAVAPT/AAADAAAAAAAVAPX/AAADAAAAAAAVAPb/AAADAAAAAAAVAPf/AAADAAAAAAAVAPj/AAADAAAAAAAVAPn/AAADAAAAAAAVAPr/AAADAAAAAAAVAPv/AAADAAAAAAAVAPz/AAADAAAAAAAVAP3/AAADAAAAAAAVAP7/AAADAAAAAAAVAP//AAADAAAAAAAVAAAAAAADAAAAAAAWAOH/AAADAAAAAAAWAOL/AAADAAAAAAAWAOP/AAADAAAAAAAWAOT/AAADAAAAAAAWAOX/AAADAAAAAAAWAOb/AAADAAAAAAAWAOf/AAADAAAAAAAWAOj/AAADAAAAAAAWAOn/AAADAAAAAAAWAOr/AAADAAAAAAAWAOv/AAADAAAAAAAWAOz/AAADAAAAAAAWAO3/AAADAAAAAAAWAO7/AAADAAAAAAAWAO//AAADAAAAAAAWAPD/AAADAAAAAAAWAPH/AAADAAAAAAAWAPL/AAADAAAAAAAWAPP/AAADAAAAAAAWAPT/AAADAAAAAAAWAPX/AAADAAAAAAAWAPb/AAADAAAAAAAWAPf/AAADAAAAAAAWAPj/AAADAAAAAAAWAPn/AAADAAAAAAAWAPr/AAADAAAAAAAWAPv/AAADAAAAAAAWAPz/AAADAAAAAAAWAP3/AAADAAAAAAAWAP7/AAADAAAAAAAWAP//AAADAAAAAAAWAAAAAAADAAAAAAAXAOH/AAADAAAAAAAXAOL/AAADAAAAAAAXAOP/AAADAAAAAAAXAOT/AAADAAAAAAAXAOX/AAADAAAAAAAXAOb/AAADAAAAAAAXAOf/AAADAAAAAAAXAOj/AAADAAAAAAAXAOn/AAADAAAAAAAXAOr/AAADAAAAAAAXAOv/AAADAAAAAAAXAOz/AAADAAAAAAAXAO3/AAADAAAAAAAXAO7/AAADAAAAAAAXAO//AAADAAAAAAAXAPD/AAADAAAAAAAXAPH/AAADAAAAAAAXAPL/AAADAAAAAAAXAPP/AAADAAAAAAAXAPT/AAADAAAAAAAXAPX/AAADAAAAAAAXAPb/AAADAAAAAAAXAPf/AAADAAAAAAAXAPj/AAADAAAAAAAXAPn/AAADAAAAAAAXAPr/AAADAAAAAAAXAPv/AAADAAAAAAAXAPz/AAADAAAAAAAXAP3/AAADAAAAAAAXAP7/AAADAAAAAAAXAP//AAADAAAAAAAXAAAAAAADAAAAAAAiAN7/AAADAAAAAAAiAN//AAADAAAAAAAiAOD/AAADAAAAAAAiAOH/AAADAAAAAAAiAOL/AAADAAAAAAAiAOP/AAADAAAAAAAiAOT/AAADAAAAAAAiAOX/AAADAAAAAAAiAOb/AAADAAAAAAAiAOf/AAADAAAAAAAiAOj/AAADAAAAAAAiAOn/AAADAAAAAAAiAOr/AAADAAAAAAAiAOv/AAADAAAAAAAiAOz/AAADAAAAAAAiAO3/AAADAAAAAAAiAO7/AAADAAAAAAAiAO//AAADAAAAAAAiAPD/AAADAAAAAAAjAN7/AAADAAAAAAAjAN//AAADAAAAAAAjAOD/AAADAAAAAAAjAOH/AAADAAAAAAAjAOL/AAADAAAAAAAjAOP/AAADAAAAAAAjAOT/AAADAAAAAAAjAOX/AAADAAAAAAAjAOb/AAADAAAAAAAjAOf/AAADAAAAAAAjAOj/AAADAAAAAAAjAOn/AAADAAAAAAAjAOr/AAADAAAAAAAjAOv/AAADAAAAAAAjAOz/AAADAAAAAAAjAO3/AAADAAAAAAAjAO7/AAADAAAAAAAjAO//AAADAAAAAAAjAPD/AAADAAAAAAAkAN7/AAADAAAAAAAkAN//AAADAAAAAAAkAOD/AAADAAAAAAAkAOH/AAADAAAAAAAkAOL/AAADAAAAAAAkAOP/AAADAAAAAAAkAOT/AAADAAAAAAAkAOX/AAADAAAAAAAkAOb/AAADAAAAAAAkAOf/AAADAAAAAAAkAOj/AAADAAAAAAAkAOn/AAADAAAAAAAkAOr/AAADAAAAAAAkAOv/AAADAAAAAAAkAOz/AAADAAAAAAAkAO3/AAADAAAAAAAkAO7/AAADAAAAAAAkAO//AAADAAAAAAAkAPD/AAADAAAAAAAlAN7/AAADAAAAAAAlAN//AAADAAAAAAAlAOD/AAADAAAAAAAlAOH/AAADAAAAAAAlAOL/AAADAAAAAAAlAOP/AAADAAAAAAAlAOT/AAADAAAAAAAlAOX/AAADAAAAAAAlAOb/AAADAAAAAAAlAOf/AAADAAAAAAAlAOj/AAADAAAAAAAlAOn/AAADAAAAAAAlAOr/AAADAAAAAAAlAOv/AAADAAAAAAAlAOz/AAADAAAAAAAlAO3/AAADAAAAAAAlAO7/AAADAAAAAAAlAO//AAADAAAAAAAlAPD/AAADAAAAAAAmAN7/AAADAAAAAAAmAN//AAADAAAAAAAmAOD/AAADAAAAAAAmAOH/AAADAAAAAAAmAOL/AAADAAAAAAAmAOP/AAADAAAAAAAmAOT/AAADAAAAAAAmAOX/AAADAAAAAAAmAOb/AAADAAAAAAAmAOf/AAADAAAAAAAmAOj/AAADAAAAAAAmAOn/AAADAAAAAAAmAOr/AAADAAAAAAAmAOv/AAADAAAAAAAmAOz/AAADAAAAAAAmAO3/AAADAAAAAAAmAO7/AAADAAAAAAAmAO//AAADAAAAAAAmAPD/AAADAAAAAAAnAN7/AAADAAAAAAAnAN//AAADAAAAAAAnAOD/AAADAAAAAAAnAOH/AAADAAAAAAAnAOL/AAADAAAAAAAnAOP/AAADAAAAAAAnAOT/AAADAAAAAAAnAOX/AAADAAAAAAAnAOb/AAADAAAAAAAnAOf/AAADAAAAAAAnAOj/AAADAAAAAAAnAOn/AAADAAAAAAAnAOr/AAADAAAAAAAnAOv/AAADAAAAAAAnAOz/AAADAAAAAAAnAO3/AAADAAAAAAAnAO7/AAADAAAAAAAnAO//AAADAAAAAAAnAPD/AAADAAAAAAAYAPv/AAADAAAAAAAYAPz/AAADAAAAAAAYAP3/AAADAAAAAAAYAP7/AAADAAAAAAAYAP//AAADAAAAAAAYAAAAAAADAAAAAAAZAPv/AAADAAAAAAAZAPz/AAADAAAAAAAZAP3/AAADAAAAAAAZAP7/AAADAAAAAAAZAP//AAADAAAAAAAZAAAAAAADAAAAAAAaAPv/AAADAAAAAAAaAPz/AAADAAAAAAAaAP3/AAADAAAAAAAaAP7/AAADAAAAAAAaAP//AAADAAAAAAAaAAAAAAADAAAAAAAbAPv/AAADAAAAAAAbAPz/AAADAAAAAAAbAP3/AAADAAAAAAAbAP7/AAADAAAAAAAbAP//AAADAAAAAAAbAAAAAAADAAAAAAAcAPv/AAADAAAAAAAcAPz/AAADAAAAAAAcAP3/AAADAAAAAAAcAP7/AAADAAAAAAAcAP//AAADAAAAAAAcAAAAAAADAAAAAAAdAPv/AAADAAAAAAAdAPz/AAADAAAAAAAdAP3/AAADAAAAAAAdAP7/AAADAAAAAAAdAP//AAADAAAAAAAdAAAAAAADAAAAAAAeAPv/AAADAAAAAAAeAPz/AAADAAAAAAAeAP3/AAADAAAAAAAeAP7/AAADAAAAAAAeAP//AAADAAAAAAAeAAAAAAADAAAAAAAfAPv/AAADAAAAAAAfAPz/AAADAAAAAAAfAP3/AAADAAAAAAAfAP7/AAADAAAAAAAfAP//AAADAAAAAAAfAAAAAAADAAAAAAAgAPv/AAADAAAAAAAgAPz/AAADAAAAAAAgAP3/AAADAAAAAAAgAP7/AAADAAAAAAAgAP//AAADAAAAAAAgAAAAAAADAAAAAAAhAPv/AAADAAAAAAAhAPz/AAADAAAAAAAhAP3/AAADAAAAAAAhAP7/AAADAAAAAAAhAP//AAADAAAAAAAhAAAAAAADAAAAAAAiAPv/AAADAAAAAAAiAPz/AAADAAAAAAAiAP3/AAADAAAAAAAiAP7/AAADAAAAAAAiAP//AAADAAAAAAAiAAAAAAADAAAAAAAjAPv/AAADAAAAAAAjAPz/AAADAAAAAAAjAP3/AAADAAAAAAAjAP7/AAADAAAAAAAjAP//AAADAAAAAAAjAAAAAAADAAAAAAAkAPv/AAADAAAAAAAkAPz/AAADAAAAAAAkAP3/AAADAAAAAAAkAP7/AAADAAAAAAAkAP//AAADAAAAAAAkAAAAAAADAAAAAAAlAPv/AAADAAAAAAAlAPz/AAADAAAAAAAlAP3/AAADAAAAAAAlAP7/AAADAAAAAAAlAP//AAADAAAAAAAlAAAAAAADAAAAAAAmAPv/AAADAAAAAAAmAPz/AAADAAAAAAAmAP3/AAADAAAAAAAmAP7/AAADAAAAAAAmAP//AAADAAAAAAAmAAAAAAADAAAAAAAnAPv/AAADAAAAAAAnAPz/AAADAAAAAAAnAP3/AAADAAAAAAAnAP7/AAADAAAAAAAnAP//AAADAAAAAAAnAAAAAAADAAAAAAAoAPv/AAADAAAAAAAoAPz/AAADAAAAAAAoAP3/AAADAAAAAAAoAP7/AAADAAAAAAAoAP//AAADAAAAAAAoAAAAAAADAAAAAAANAAsAAAADAAAAAAANAAwAAAADAAAAAAANAA0AAAADAAAAAAANAA4AAAADAAAAAAANAA8AAAADAAAAAAANABAAAAADAAAAAAAOAAsAAAADAAAAAAAOAAwAAAADAAAAAAAOAA0AAAADAAAAAAAOAA4AAAADAAAAAAAOAA8AAAADAAAAAAAOABAAAAADAAAAAAAPAAsAAAADAAAAAAAPAAwAAAADAAAAAAAPAA0AAAADAAAAAAAPAA4AAAADAAAAAAAPAA8AAAADAAAAAAAPABAAAAADAAAAAAAQAAsAAAADAAAAAAAQAAwAAAADAAAAAAAQAA0AAAADAAAAAAAQAA4AAAADAAAAAAAQAA8AAAADAAAAAAAQABAAAAADAAAAAAARAAsAAAADAAAAAAARAAwAAAADAAAAAAARAA0AAAADAAAAAAARAA4AAAADAAAAAAARAA8AAAADAAAAAAARABAAAAADAAAAAAASAAsAAAADAAAAAAASAAwAAAADAAAAAAASAA0AAAADAAAAAAASAA4AAAADAAAAAAASAA8AAAADAAAAAAASABAAAAADAAAAAAATAAsAAAADAAAAAAATAAwAAAADAAAAAAATAA0AAAADAAAAAAATAA4AAAADAAAAAAATAA8AAAADAAAAAAATABAAAAADAAAAAAAUAAsAAAADAAAAAAAUAAwAAAADAAAAAAAUAA0AAAADAAAAAAAUAA4AAAADAAAAAAAUAA8AAAADAAAAAAAUABAAAAADAAAAAAAVAAsAAAADAAAAAAAVAAwAAAADAAAAAAAVAA0AAAADAAAAAAAVAA4AAAADAAAAAAAVAA8AAAADAAAAAAAVABAAAAADAAAAAAAWAAsAAAADAAAAAAAWAAwAAAADAAAAAAAWAA0AAAADAAAAAAAWAA4AAAADAAAAAAAWAA8AAAADAAAAAAAWABAAAAADAAAAAAAXAAsAAAADAAAAAAAXAAwAAAADAAAAAAAXAA0AAAADAAAAAAAXAA4AAAADAAAAAAAXAA8AAAADAAAAAAAXABAAAAADAAAAAAAYAAsAAAADAAAAAAAYAAwAAAADAAAAAAAYAA0AAAADAAAAAAAYAA4AAAADAAAAAAAYAA8AAAADAAAAAAAYABAAAAADAAAAAAAZAAsAAAADAAAAAAAZAAwAAAADAAAAAAAZAA0AAAADAAAAAAAZAA4AAAADAAAAAAAZAA8AAAADAAAAAAAZABAAAAADAAAAAAAaAAsAAAADAAAAAAAaAAwAAAADAAAAAAAaAA0AAAADAAAAAAAaAA4AAAADAAAAAAAaAA8AAAADAAAAAAAaABAAAAADAAAAAAAbAAsAAAADAAAAAAAbAAwAAAADAAAAAAAbAA0AAAADAAAAAAAbAA4AAAADAAAAAAAbAA8AAAADAAAAAAAbABAAAAADAAAAAAAcAAsAAAADAAAAAAAcAAwAAAADAAAAAAAcAA0AAAADAAAAAAAcAA4AAAADAAAAAAAcAA8AAAADAAAAAAAcABAAAAADAAAAAAAdAAsAAAADAAAAAAAdAAwAAAADAAAAAAAdAA0AAAADAAAAAAAdAA4AAAADAAAAAAAdAA8AAAADAAAAAAAdABAAAAADAAAAAAAeAAsAAAADAAAAAAAeAAwAAAADAAAAAAAeAA0AAAADAAAAAAAeAA4AAAADAAAAAAAeAA8AAAADAAAAAAAeABAAAAADAAAAAAAfAAsAAAADAAAAAAAfAAwAAAADAAAAAAAfAA0AAAADAAAAAAAfAA4AAAADAAAAAAAfAA8AAAADAAAAAAAfABAAAAADAAAAAAA=\")\nplayer_id = 1\n\n[node name=\"BuildableArea2\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(0.916667, 0, 1, 0.211765)\ntile_map_data = PackedByteArray(\"AABcADUAAAADAAAAAABcADYAAAADAAAAAABcADcAAAADAAAAAABcADgAAAADAAAAAABcADkAAAADAAAAAABcADoAAAADAAAAAABdADUAAAADAAAAAABdADYAAAADAAAAAABdADcAAAADAAAAAABdADgAAAADAAAAAABdADkAAAADAAAAAABdADoAAAADAAAAAABeADUAAAADAAAAAABeADYAAAADAAAAAABeADcAAAADAAAAAABeADgAAAADAAAAAABeADkAAAADAAAAAABeADoAAAADAAAAAABfADUAAAADAAAAAABfADYAAAADAAAAAABfADcAAAADAAAAAABfADgAAAADAAAAAABfADkAAAADAAAAAABfADoAAAADAAAAAABgADUAAAADAAAAAABgADYAAAADAAAAAABgADcAAAADAAAAAABgADgAAAADAAAAAABgADkAAAADAAAAAABgADoAAAADAAAAAABhADUAAAADAAAAAABhADYAAAADAAAAAABhADcAAAADAAAAAABhADgAAAADAAAAAABhADkAAAADAAAAAABhADoAAAADAAAAAABiADUAAAADAAAAAABiADYAAAADAAAAAABiADcAAAADAAAAAABiADgAAAADAAAAAABiADkAAAADAAAAAABiADoAAAADAAAAAABjADUAAAADAAAAAABjADYAAAADAAAAAABjADcAAAADAAAAAABjADgAAAADAAAAAABjADkAAAADAAAAAABjADoAAAADAAAAAABkADUAAAADAAAAAABkADYAAAADAAAAAABkADcAAAADAAAAAABkADgAAAADAAAAAABkADkAAAADAAAAAABkADoAAAADAAAAAABlADUAAAADAAAAAABlADYAAAADAAAAAABlADcAAAADAAAAAABlADgAAAADAAAAAABlADkAAAADAAAAAABlADoAAAADAAAAAABmADUAAAADAAAAAABmADYAAAADAAAAAABmADcAAAADAAAAAABmADgAAAADAAAAAABmADkAAAADAAAAAABmADoAAAADAAAAAABnADUAAAADAAAAAABnADYAAAADAAAAAABnADcAAAADAAAAAABnADgAAAADAAAAAABnADkAAAADAAAAAABnADoAAAADAAAAAABoADUAAAADAAAAAABoADYAAAADAAAAAABoADcAAAADAAAAAABoADgAAAADAAAAAABoADkAAAADAAAAAABoADoAAAADAAAAAABpADUAAAADAAAAAABpADYAAAADAAAAAABpADcAAAADAAAAAABpADgAAAADAAAAAABpADkAAAADAAAAAABpADoAAAADAAAAAABMADUAAAADAAAAAABMADYAAAADAAAAAABMADcAAAADAAAAAABMADgAAAADAAAAAABMADkAAAADAAAAAABMADoAAAADAAAAAABNADUAAAADAAAAAABNADYAAAADAAAAAABNADcAAAADAAAAAABNADgAAAADAAAAAABNADkAAAADAAAAAABNADoAAAADAAAAAABOADUAAAADAAAAAABOADYAAAADAAAAAABOADcAAAADAAAAAABOADgAAAADAAAAAABOADkAAAADAAAAAABOADoAAAADAAAAAABPADUAAAADAAAAAABPADYAAAADAAAAAABPADcAAAADAAAAAABPADgAAAADAAAAAABPADkAAAADAAAAAABPADoAAAADAAAAAABQADUAAAADAAAAAABQADYAAAADAAAAAABQADcAAAADAAAAAABQADgAAAADAAAAAABQADkAAAADAAAAAABQADoAAAADAAAAAABRADUAAAADAAAAAABRADYAAAADAAAAAABRADcAAAADAAAAAABRADgAAAADAAAAAABRADkAAAADAAAAAABRADoAAAADAAAAAABSADUAAAADAAAAAABSADYAAAADAAAAAABSADcAAAADAAAAAABSADgAAAADAAAAAABSADkAAAADAAAAAABSADoAAAADAAAAAABTADUAAAADAAAAAABTADYAAAADAAAAAABTADcAAAADAAAAAABTADgAAAADAAAAAABTADkAAAADAAAAAABTADoAAAADAAAAAABUADUAAAADAAAAAABUADYAAAADAAAAAABUADcAAAADAAAAAABUADgAAAADAAAAAABUADkAAAADAAAAAABUADoAAAADAAAAAABVADUAAAADAAAAAABVADYAAAADAAAAAABVADcAAAADAAAAAABVADgAAAADAAAAAABVADkAAAADAAAAAABVADoAAAADAAAAAABWADUAAAADAAAAAABWADYAAAADAAAAAABWADcAAAADAAAAAABWADgAAAADAAAAAABWADkAAAADAAAAAABWADoAAAADAAAAAABXADUAAAADAAAAAABXADYAAAADAAAAAABXADcAAAADAAAAAABXADgAAAADAAAAAABXADkAAAADAAAAAABXADoAAAADAAAAAABYADUAAAADAAAAAABYADYAAAADAAAAAABYADcAAAADAAAAAABYADgAAAADAAAAAABYADkAAAADAAAAAABYADoAAAADAAAAAABZADUAAAADAAAAAABZADYAAAADAAAAAABZADcAAAADAAAAAABZADgAAAADAAAAAABZADkAAAADAAAAAABZADoAAAADAAAAAABaADUAAAADAAAAAABaADYAAAADAAAAAABaADcAAAADAAAAAABaADgAAAADAAAAAABaADkAAAADAAAAAABaADoAAAADAAAAAABbADUAAAADAAAAAABbADYAAAADAAAAAABbADcAAAADAAAAAABbADgAAAADAAAAAABbADkAAAADAAAAAABbADoAAAADAAAAAABMACQAAAADAAAAAABMACUAAAADAAAAAABMACYAAAADAAAAAABMACcAAAADAAAAAABMACgAAAADAAAAAABMACkAAAADAAAAAABMACoAAAADAAAAAABMACsAAAADAAAAAABMACwAAAADAAAAAABMAC0AAAADAAAAAABMAC4AAAADAAAAAABMAC8AAAADAAAAAABMADAAAAADAAAAAABMADEAAAADAAAAAABMADIAAAADAAAAAABMADMAAAADAAAAAABMADQAAAADAAAAAABNACQAAAADAAAAAABNACUAAAADAAAAAABNACYAAAADAAAAAABNACcAAAADAAAAAABNACgAAAADAAAAAABNACkAAAADAAAAAABNACoAAAADAAAAAABNACsAAAADAAAAAABNACwAAAADAAAAAABNAC0AAAADAAAAAABNAC4AAAADAAAAAABNAC8AAAADAAAAAABNADAAAAADAAAAAABNADEAAAADAAAAAABNADIAAAADAAAAAABNADMAAAADAAAAAABNADQAAAADAAAAAABOACQAAAADAAAAAABOACUAAAADAAAAAABOACYAAAADAAAAAABOACcAAAADAAAAAABOACgAAAADAAAAAABOACkAAAADAAAAAABOACoAAAADAAAAAABOACsAAAADAAAAAABOACwAAAADAAAAAABOAC0AAAADAAAAAABOAC4AAAADAAAAAABOAC8AAAADAAAAAABOADAAAAADAAAAAABOADEAAAADAAAAAABOADIAAAADAAAAAABOADMAAAADAAAAAABOADQAAAADAAAAAABPACQAAAADAAAAAABPACUAAAADAAAAAABPACYAAAADAAAAAABPACcAAAADAAAAAABPACgAAAADAAAAAABPACkAAAADAAAAAABPACoAAAADAAAAAABPACsAAAADAAAAAABPACwAAAADAAAAAABPAC0AAAADAAAAAABPAC4AAAADAAAAAABPAC8AAAADAAAAAABPADAAAAADAAAAAABPADEAAAADAAAAAABPADIAAAADAAAAAABPADMAAAADAAAAAABPADQAAAADAAAAAABQACQAAAADAAAAAABQACUAAAADAAAAAABQACYAAAADAAAAAABQACcAAAADAAAAAABQACgAAAADAAAAAABQACkAAAADAAAAAABQACoAAAADAAAAAABQACsAAAADAAAAAABQACwAAAADAAAAAABQAC0AAAADAAAAAABQAC4AAAADAAAAAABQAC8AAAADAAAAAABQADAAAAADAAAAAABQADEAAAADAAAAAABQADIAAAADAAAAAABQADMAAAADAAAAAABQADQAAAADAAAAAABRACQAAAADAAAAAABRACUAAAADAAAAAABRACYAAAADAAAAAABRACcAAAADAAAAAABRACgAAAADAAAAAABRACkAAAADAAAAAABRACoAAAADAAAAAABRACsAAAADAAAAAABRACwAAAADAAAAAABRAC0AAAADAAAAAABRAC4AAAADAAAAAABRAC8AAAADAAAAAABRADAAAAADAAAAAABRADEAAAADAAAAAABRADIAAAADAAAAAABRADMAAAADAAAAAABRADQAAAADAAAAAAA8AC0AAAADAAAAAAA8AC4AAAADAAAAAAA8AC8AAAADAAAAAAA8ADAAAAADAAAAAAA8ADEAAAADAAAAAAA8ADIAAAADAAAAAAA8ADMAAAADAAAAAAA8ADQAAAADAAAAAAA8ADUAAAADAAAAAAA8ADYAAAADAAAAAAA8ADcAAAADAAAAAAA8ADgAAAADAAAAAAA8ADkAAAADAAAAAAA8ADoAAAADAAAAAAA8ADsAAAADAAAAAAA8ADwAAAADAAAAAAA8AD0AAAADAAAAAAA8AD4AAAADAAAAAAA8AD8AAAADAAAAAAA9AC0AAAADAAAAAAA9AC4AAAADAAAAAAA9AC8AAAADAAAAAAA9ADAAAAADAAAAAAA9ADEAAAADAAAAAAA9ADIAAAADAAAAAAA9ADMAAAADAAAAAAA9ADQAAAADAAAAAAA9ADUAAAADAAAAAAA9ADYAAAADAAAAAAA9ADcAAAADAAAAAAA9ADgAAAADAAAAAAA9ADkAAAADAAAAAAA9ADoAAAADAAAAAAA9ADsAAAADAAAAAAA9ADwAAAADAAAAAAA9AD0AAAADAAAAAAA9AD4AAAADAAAAAAA9AD8AAAADAAAAAAA+AC0AAAADAAAAAAA+AC4AAAADAAAAAAA+AC8AAAADAAAAAAA+ADAAAAADAAAAAAA+ADEAAAADAAAAAAA+ADIAAAADAAAAAAA+ADMAAAADAAAAAAA+ADQAAAADAAAAAAA+ADUAAAADAAAAAAA+ADYAAAADAAAAAAA+ADcAAAADAAAAAAA+ADgAAAADAAAAAAA+ADkAAAADAAAAAAA+ADoAAAADAAAAAAA+ADsAAAADAAAAAAA+ADwAAAADAAAAAAA+AD0AAAADAAAAAAA+AD4AAAADAAAAAAA+AD8AAAADAAAAAAA/AC0AAAADAAAAAAA/AC4AAAADAAAAAAA/AC8AAAADAAAAAAA/ADAAAAADAAAAAAA/ADEAAAADAAAAAAA/ADIAAAADAAAAAAA/ADMAAAADAAAAAAA/ADQAAAADAAAAAAA/ADUAAAADAAAAAAA/ADYAAAADAAAAAAA/ADcAAAADAAAAAAA/ADgAAAADAAAAAAA/ADkAAAADAAAAAAA/ADoAAAADAAAAAAA/ADsAAAADAAAAAAA/ADwAAAADAAAAAAA/AD0AAAADAAAAAAA/AD4AAAADAAAAAAA/AD8AAAADAAAAAABAAC0AAAADAAAAAABAAC4AAAADAAAAAABAAC8AAAADAAAAAABAADAAAAADAAAAAABAADEAAAADAAAAAABAADIAAAADAAAAAABAADMAAAADAAAAAABAADQAAAADAAAAAABAADUAAAADAAAAAABAADYAAAADAAAAAABAADcAAAADAAAAAABAADgAAAADAAAAAABAADkAAAADAAAAAABAADoAAAADAAAAAABAADsAAAADAAAAAABAADwAAAADAAAAAABAAD0AAAADAAAAAABAAD4AAAADAAAAAABAAD8AAAADAAAAAABBAC0AAAADAAAAAABBAC4AAAADAAAAAABBAC8AAAADAAAAAABBADAAAAADAAAAAABBADEAAAADAAAAAABBADIAAAADAAAAAABBADMAAAADAAAAAABBADQAAAADAAAAAABBADUAAAADAAAAAABBADYAAAADAAAAAABBADcAAAADAAAAAABBADgAAAADAAAAAABBADkAAAADAAAAAABBADoAAAADAAAAAABBADsAAAADAAAAAABBADwAAAADAAAAAABBAD0AAAADAAAAAABBAD4AAAADAAAAAABBAD8AAAADAAAAAABcACUAAAADAAAAAABcACYAAAADAAAAAABcACcAAAADAAAAAABcACgAAAADAAAAAABcACkAAAADAAAAAABcACoAAAADAAAAAABdACUAAAADAAAAAABdACYAAAADAAAAAABdACcAAAADAAAAAABdACgAAAADAAAAAABdACkAAAADAAAAAABdACoAAAADAAAAAABeACUAAAADAAAAAABeACYAAAADAAAAAABeACcAAAADAAAAAABeACgAAAADAAAAAABeACkAAAADAAAAAABeACoAAAADAAAAAABfACUAAAADAAAAAABfACYAAAADAAAAAABfACcAAAADAAAAAABfACgAAAADAAAAAABfACkAAAADAAAAAABfACoAAAADAAAAAABgACUAAAADAAAAAABgACYAAAADAAAAAABgACcAAAADAAAAAABgACgAAAADAAAAAABgACkAAAADAAAAAABgACoAAAADAAAAAABhACUAAAADAAAAAABhACYAAAADAAAAAABhACcAAAADAAAAAABhACgAAAADAAAAAABhACkAAAADAAAAAABhACoAAAADAAAAAABiACUAAAADAAAAAABiACYAAAADAAAAAABiACcAAAADAAAAAABiACgAAAADAAAAAABiACkAAAADAAAAAABiACoAAAADAAAAAABjACUAAAADAAAAAABjACYAAAADAAAAAABjACcAAAADAAAAAABjACgAAAADAAAAAABjACkAAAADAAAAAABjACoAAAADAAAAAABkACUAAAADAAAAAABkACYAAAADAAAAAABkACcAAAADAAAAAABkACgAAAADAAAAAABkACkAAAADAAAAAABkACoAAAADAAAAAABlACUAAAADAAAAAABlACYAAAADAAAAAABlACcAAAADAAAAAABlACgAAAADAAAAAABlACkAAAADAAAAAABlACoAAAADAAAAAABmACUAAAADAAAAAABmACYAAAADAAAAAABmACcAAAADAAAAAABmACgAAAADAAAAAABmACkAAAADAAAAAABmACoAAAADAAAAAABnACUAAAADAAAAAABnACYAAAADAAAAAABnACcAAAADAAAAAABnACgAAAADAAAAAABnACkAAAADAAAAAABnACoAAAADAAAAAABoACUAAAADAAAAAABoACYAAAADAAAAAABoACcAAAADAAAAAABoACgAAAADAAAAAABoACkAAAADAAAAAABoACoAAAADAAAAAABpACUAAAADAAAAAABpACYAAAADAAAAAABpACcAAAADAAAAAABpACgAAAADAAAAAABpACkAAAADAAAAAABpACoAAAADAAAAAABqACUAAAADAAAAAABqACYAAAADAAAAAABqACcAAAADAAAAAABqACgAAAADAAAAAABqACkAAAADAAAAAABqACoAAAADAAAAAABrACUAAAADAAAAAABrACYAAAADAAAAAABrACcAAAADAAAAAABrACgAAAADAAAAAABrACkAAAADAAAAAABrACoAAAADAAAAAABsACUAAAADAAAAAABsACYAAAADAAAAAABsACcAAAADAAAAAABsACgAAAADAAAAAABsACkAAAADAAAAAABsACoAAAADAAAAAABtACUAAAADAAAAAABtACYAAAADAAAAAABtACcAAAADAAAAAABtACgAAAADAAAAAABtACkAAAADAAAAAABtACoAAAADAAAAAABuACUAAAADAAAAAABuACYAAAADAAAAAABuACcAAAADAAAAAABuACgAAAADAAAAAABuACkAAAADAAAAAABuACoAAAADAAAAAAA=\")\nplayer_id = 2\n\n[node name=\"BuildableArea3\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(1, 0, 0.216667, 0.211765)\ntile_map_data = PackedByteArray(\"AAA8AEAAAAADAAAAAAA8AEEAAAADAAAAAAA8AEIAAAADAAAAAAA8AEMAAAADAAAAAAA8AEQAAAADAAAAAAA8AEUAAAADAAAAAAA8AEYAAAADAAAAAAA8AEcAAAADAAAAAAA8AEgAAAADAAAAAAA8AEkAAAADAAAAAAA8AEoAAAADAAAAAAA8AEsAAAADAAAAAAA8AEwAAAADAAAAAAA8AE0AAAADAAAAAAA8AE4AAAADAAAAAAA8AE8AAAADAAAAAAA8AFAAAAADAAAAAAA8AFEAAAADAAAAAAA8AFIAAAADAAAAAAA9AEAAAAADAAAAAAA9AEEAAAADAAAAAAA9AEIAAAADAAAAAAA9AEMAAAADAAAAAAA9AEQAAAADAAAAAAA9AEUAAAADAAAAAAA9AEYAAAADAAAAAAA9AEcAAAADAAAAAAA9AEgAAAADAAAAAAA9AEkAAAADAAAAAAA9AEoAAAADAAAAAAA9AEsAAAADAAAAAAA9AEwAAAADAAAAAAA9AE0AAAADAAAAAAA9AE4AAAADAAAAAAA9AE8AAAADAAAAAAA9AFAAAAADAAAAAAA9AFEAAAADAAAAAAA9AFIAAAADAAAAAAA+AEAAAAADAAAAAAA+AEEAAAADAAAAAAA+AEIAAAADAAAAAAA+AEMAAAADAAAAAAA+AEQAAAADAAAAAAA+AEUAAAADAAAAAAA+AEYAAAADAAAAAAA+AEcAAAADAAAAAAA+AEgAAAADAAAAAAA+AEkAAAADAAAAAAA+AEoAAAADAAAAAAA+AEsAAAADAAAAAAA+AEwAAAADAAAAAAA+AE0AAAADAAAAAAA+AE4AAAADAAAAAAA+AE8AAAADAAAAAAA+AFAAAAADAAAAAAA+AFEAAAADAAAAAAA+AFIAAAADAAAAAAA/AEAAAAADAAAAAAA/AEEAAAADAAAAAAA/AEIAAAADAAAAAAA/AEMAAAADAAAAAAA/AEQAAAADAAAAAAA/AEUAAAADAAAAAAA/AEYAAAADAAAAAAA/AEcAAAADAAAAAAA/AEgAAAADAAAAAAA/AEkAAAADAAAAAAA/AEoAAAADAAAAAAA/AEsAAAADAAAAAAA/AEwAAAADAAAAAAA/AE0AAAADAAAAAAA/AE4AAAADAAAAAAA/AE8AAAADAAAAAAA/AFAAAAADAAAAAAA/AFEAAAADAAAAAAA/AFIAAAADAAAAAABAAEAAAAADAAAAAABAAEEAAAADAAAAAABAAEIAAAADAAAAAABAAEMAAAADAAAAAABAAEQAAAADAAAAAABAAEUAAAADAAAAAABAAEYAAAADAAAAAABAAEcAAAADAAAAAABAAEgAAAADAAAAAABAAEkAAAADAAAAAABAAEoAAAADAAAAAABAAEsAAAADAAAAAABAAEwAAAADAAAAAABAAE0AAAADAAAAAABAAE4AAAADAAAAAABAAE8AAAADAAAAAABAAFAAAAADAAAAAABAAFEAAAADAAAAAABAAFIAAAADAAAAAABBAEAAAAADAAAAAABBAEEAAAADAAAAAABBAEIAAAADAAAAAABBAEMAAAADAAAAAABBAEQAAAADAAAAAABBAEUAAAADAAAAAABBAEYAAAADAAAAAABBAEcAAAADAAAAAABBAEgAAAADAAAAAABBAEkAAAADAAAAAABBAEoAAAADAAAAAABBAEsAAAADAAAAAABBAEwAAAADAAAAAABBAE0AAAADAAAAAABBAE4AAAADAAAAAABBAE8AAAADAAAAAABBAFAAAAADAAAAAABBAFEAAAADAAAAAABBAFIAAAADAAAAAABMAEUAAAADAAAAAABMAEYAAAADAAAAAABMAEcAAAADAAAAAABMAEgAAAADAAAAAABMAEkAAAADAAAAAABMAEoAAAADAAAAAABNAEUAAAADAAAAAABNAEYAAAADAAAAAABNAEcAAAADAAAAAABNAEgAAAADAAAAAABNAEkAAAADAAAAAABNAEoAAAADAAAAAABOAEUAAAADAAAAAABOAEYAAAADAAAAAABOAEcAAAADAAAAAABOAEgAAAADAAAAAABOAEkAAAADAAAAAABOAEoAAAADAAAAAABPAEUAAAADAAAAAABPAEYAAAADAAAAAABPAEcAAAADAAAAAABPAEgAAAADAAAAAABPAEkAAAADAAAAAABPAEoAAAADAAAAAABQAEUAAAADAAAAAABQAEYAAAADAAAAAABQAEcAAAADAAAAAABQAEgAAAADAAAAAABQAEkAAAADAAAAAABQAEoAAAADAAAAAABRAEUAAAADAAAAAABRAEYAAAADAAAAAABRAEcAAAADAAAAAABRAEgAAAADAAAAAABRAEkAAAADAAAAAABRAEoAAAADAAAAAABSAEUAAAADAAAAAABSAEYAAAADAAAAAABSAEcAAAADAAAAAABSAEgAAAADAAAAAABSAEkAAAADAAAAAABSAEoAAAADAAAAAABTAEUAAAADAAAAAABTAEYAAAADAAAAAABTAEcAAAADAAAAAABTAEgAAAADAAAAAABTAEkAAAADAAAAAABTAEoAAAADAAAAAABUAEUAAAADAAAAAABUAEYAAAADAAAAAABUAEcAAAADAAAAAABUAEgAAAADAAAAAABUAEkAAAADAAAAAABUAEoAAAADAAAAAABVAEUAAAADAAAAAABVAEYAAAADAAAAAABVAEcAAAADAAAAAABVAEgAAAADAAAAAABVAEkAAAADAAAAAABVAEoAAAADAAAAAABWAEUAAAADAAAAAABWAEYAAAADAAAAAABWAEcAAAADAAAAAABWAEgAAAADAAAAAABWAEkAAAADAAAAAABWAEoAAAADAAAAAABXAEUAAAADAAAAAABXAEYAAAADAAAAAABXAEcAAAADAAAAAABXAEgAAAADAAAAAABXAEkAAAADAAAAAABXAEoAAAADAAAAAABYAEUAAAADAAAAAABYAEYAAAADAAAAAABYAEcAAAADAAAAAABYAEgAAAADAAAAAABYAEkAAAADAAAAAABYAEoAAAADAAAAAABZAEUAAAADAAAAAABZAEYAAAADAAAAAABZAEcAAAADAAAAAABZAEgAAAADAAAAAABZAEkAAAADAAAAAABZAEoAAAADAAAAAABaAEUAAAADAAAAAABaAEYAAAADAAAAAABaAEcAAAADAAAAAABaAEgAAAADAAAAAABaAEkAAAADAAAAAABaAEoAAAADAAAAAABbAEUAAAADAAAAAABbAEYAAAADAAAAAABbAEcAAAADAAAAAABbAEgAAAADAAAAAABbAEkAAAADAAAAAABbAEoAAAADAAAAAABcAEUAAAADAAAAAABcAEYAAAADAAAAAABcAEcAAAADAAAAAABcAEgAAAADAAAAAABcAEkAAAADAAAAAABcAEoAAAADAAAAAABdAEUAAAADAAAAAABdAEYAAAADAAAAAABdAEcAAAADAAAAAABdAEgAAAADAAAAAABdAEkAAAADAAAAAABdAEoAAAADAAAAAABeAEUAAAADAAAAAABeAEYAAAADAAAAAABeAEcAAAADAAAAAABeAEgAAAADAAAAAABeAEkAAAADAAAAAABeAEoAAAADAAAAAABfAEUAAAADAAAAAABfAEYAAAADAAAAAABfAEcAAAADAAAAAABfAEgAAAADAAAAAABfAEkAAAADAAAAAABfAEoAAAADAAAAAABgAEUAAAADAAAAAABgAEYAAAADAAAAAABgAEcAAAADAAAAAABgAEgAAAADAAAAAABgAEkAAAADAAAAAABgAEoAAAADAAAAAABhAEUAAAADAAAAAABhAEYAAAADAAAAAABhAEcAAAADAAAAAABhAEgAAAADAAAAAABhAEkAAAADAAAAAABhAEoAAAADAAAAAABiAEUAAAADAAAAAABiAEYAAAADAAAAAABiAEcAAAADAAAAAABiAEgAAAADAAAAAABiAEkAAAADAAAAAABiAEoAAAADAAAAAABjAEUAAAADAAAAAABjAEYAAAADAAAAAABjAEcAAAADAAAAAABjAEgAAAADAAAAAABjAEkAAAADAAAAAABjAEoAAAADAAAAAABkAEUAAAADAAAAAABkAEYAAAADAAAAAABkAEcAAAADAAAAAABkAEgAAAADAAAAAABkAEkAAAADAAAAAABkAEoAAAADAAAAAABlAEUAAAADAAAAAABlAEYAAAADAAAAAABlAEcAAAADAAAAAABlAEgAAAADAAAAAABlAEkAAAADAAAAAABlAEoAAAADAAAAAABmAEUAAAADAAAAAABmAEYAAAADAAAAAABmAEcAAAADAAAAAABmAEgAAAADAAAAAABmAEkAAAADAAAAAABmAEoAAAADAAAAAABnAEUAAAADAAAAAABnAEYAAAADAAAAAABnAEcAAAADAAAAAABnAEgAAAADAAAAAABnAEkAAAADAAAAAABnAEoAAAADAAAAAABoAEUAAAADAAAAAABoAEYAAAADAAAAAABoAEcAAAADAAAAAABoAEgAAAADAAAAAABoAEkAAAADAAAAAABoAEoAAAADAAAAAABpAEUAAAADAAAAAABpAEYAAAADAAAAAABpAEcAAAADAAAAAABpAEgAAAADAAAAAABpAEkAAAADAAAAAABpAEoAAAADAAAAAABMAEsAAAADAAAAAABMAEwAAAADAAAAAABMAE0AAAADAAAAAABMAE4AAAADAAAAAABMAE8AAAADAAAAAABMAFAAAAADAAAAAABMAFEAAAADAAAAAABMAFIAAAADAAAAAABMAFMAAAADAAAAAABMAFQAAAADAAAAAABMAFUAAAADAAAAAABMAFYAAAADAAAAAABMAFcAAAADAAAAAABMAFgAAAADAAAAAABMAFkAAAADAAAAAABMAFoAAAADAAAAAABMAFsAAAADAAAAAABNAEsAAAADAAAAAABNAEwAAAADAAAAAABNAE0AAAADAAAAAABNAE4AAAADAAAAAABNAE8AAAADAAAAAABNAFAAAAADAAAAAABNAFEAAAADAAAAAABNAFIAAAADAAAAAABNAFMAAAADAAAAAABNAFQAAAADAAAAAABNAFUAAAADAAAAAABNAFYAAAADAAAAAABNAFcAAAADAAAAAABNAFgAAAADAAAAAABNAFkAAAADAAAAAABNAFoAAAADAAAAAABNAFsAAAADAAAAAABOAEsAAAADAAAAAABOAEwAAAADAAAAAABOAE0AAAADAAAAAABOAE4AAAADAAAAAABOAE8AAAADAAAAAABOAFAAAAADAAAAAABOAFEAAAADAAAAAABOAFIAAAADAAAAAABOAFMAAAADAAAAAABOAFQAAAADAAAAAABOAFUAAAADAAAAAABOAFYAAAADAAAAAABOAFcAAAADAAAAAABOAFgAAAADAAAAAABOAFkAAAADAAAAAABOAFoAAAADAAAAAABOAFsAAAADAAAAAABPAEsAAAADAAAAAABPAEwAAAADAAAAAABPAE0AAAADAAAAAABPAE4AAAADAAAAAABPAE8AAAADAAAAAABPAFAAAAADAAAAAABPAFEAAAADAAAAAABPAFIAAAADAAAAAABPAFMAAAADAAAAAABPAFQAAAADAAAAAABPAFUAAAADAAAAAABPAFYAAAADAAAAAABPAFcAAAADAAAAAABPAFgAAAADAAAAAABPAFkAAAADAAAAAABPAFoAAAADAAAAAABPAFsAAAADAAAAAABQAEsAAAADAAAAAABQAEwAAAADAAAAAABQAE0AAAADAAAAAABQAE4AAAADAAAAAABQAE8AAAADAAAAAABQAFAAAAADAAAAAABQAFEAAAADAAAAAABQAFIAAAADAAAAAABQAFMAAAADAAAAAABQAFQAAAADAAAAAABQAFUAAAADAAAAAABQAFYAAAADAAAAAABQAFcAAAADAAAAAABQAFgAAAADAAAAAABQAFkAAAADAAAAAABQAFoAAAADAAAAAABQAFsAAAADAAAAAABRAEsAAAADAAAAAABRAEwAAAADAAAAAABRAE0AAAADAAAAAABRAE4AAAADAAAAAABRAE8AAAADAAAAAABRAFAAAAADAAAAAABRAFEAAAADAAAAAABRAFIAAAADAAAAAABRAFMAAAADAAAAAABRAFQAAAADAAAAAABRAFUAAAADAAAAAABRAFYAAAADAAAAAABRAFcAAAADAAAAAABRAFgAAAADAAAAAABRAFkAAAADAAAAAABRAFoAAAADAAAAAABRAFsAAAADAAAAAABcAFUAAAADAAAAAABcAFYAAAADAAAAAABcAFcAAAADAAAAAABcAFgAAAADAAAAAABcAFkAAAADAAAAAABcAFoAAAADAAAAAABdAFUAAAADAAAAAABdAFYAAAADAAAAAABdAFcAAAADAAAAAABdAFgAAAADAAAAAABdAFkAAAADAAAAAABdAFoAAAADAAAAAABeAFUAAAADAAAAAABeAFYAAAADAAAAAABeAFcAAAADAAAAAABeAFgAAAADAAAAAABeAFkAAAADAAAAAABeAFoAAAADAAAAAABfAFUAAAADAAAAAABfAFYAAAADAAAAAABfAFcAAAADAAAAAABfAFgAAAADAAAAAABfAFkAAAADAAAAAABfAFoAAAADAAAAAABgAFUAAAADAAAAAABgAFYAAAADAAAAAABgAFcAAAADAAAAAABgAFgAAAADAAAAAABgAFkAAAADAAAAAABgAFoAAAADAAAAAABhAFUAAAADAAAAAABhAFYAAAADAAAAAABhAFcAAAADAAAAAABhAFgAAAADAAAAAABhAFkAAAADAAAAAABhAFoAAAADAAAAAABiAFUAAAADAAAAAABiAFYAAAADAAAAAABiAFcAAAADAAAAAABiAFgAAAADAAAAAABiAFkAAAADAAAAAABiAFoAAAADAAAAAABjAFUAAAADAAAAAABjAFYAAAADAAAAAABjAFcAAAADAAAAAABjAFgAAAADAAAAAABjAFkAAAADAAAAAABjAFoAAAADAAAAAABkAFUAAAADAAAAAABkAFYAAAADAAAAAABkAFcAAAADAAAAAABkAFgAAAADAAAAAABkAFkAAAADAAAAAABkAFoAAAADAAAAAABlAFUAAAADAAAAAABlAFYAAAADAAAAAABlAFcAAAADAAAAAABlAFgAAAADAAAAAABlAFkAAAADAAAAAABlAFoAAAADAAAAAABmAFUAAAADAAAAAABmAFYAAAADAAAAAABmAFcAAAADAAAAAABmAFgAAAADAAAAAABmAFkAAAADAAAAAABmAFoAAAADAAAAAABnAFUAAAADAAAAAABnAFYAAAADAAAAAABnAFcAAAADAAAAAABnAFgAAAADAAAAAABnAFkAAAADAAAAAABnAFoAAAADAAAAAABoAFUAAAADAAAAAABoAFYAAAADAAAAAABoAFcAAAADAAAAAABoAFgAAAADAAAAAABoAFkAAAADAAAAAABoAFoAAAADAAAAAABpAFUAAAADAAAAAABpAFYAAAADAAAAAABpAFcAAAADAAAAAABpAFgAAAADAAAAAABpAFkAAAADAAAAAABpAFoAAAADAAAAAABqAFUAAAADAAAAAABqAFYAAAADAAAAAABqAFcAAAADAAAAAABqAFgAAAADAAAAAABqAFkAAAADAAAAAABqAFoAAAADAAAAAABrAFUAAAADAAAAAABrAFYAAAADAAAAAABrAFcAAAADAAAAAABrAFgAAAADAAAAAABrAFkAAAADAAAAAABrAFoAAAADAAAAAABsAFUAAAADAAAAAABsAFYAAAADAAAAAABsAFcAAAADAAAAAABsAFgAAAADAAAAAABsAFkAAAADAAAAAABsAFoAAAADAAAAAABtAFUAAAADAAAAAABtAFYAAAADAAAAAABtAFcAAAADAAAAAABtAFgAAAADAAAAAABtAFkAAAADAAAAAABtAFoAAAADAAAAAABuAFUAAAADAAAAAABuAFYAAAADAAAAAABuAFcAAAADAAAAAABuAFgAAAADAAAAAABuAFkAAAADAAAAAABuAFoAAAADAAAAAAA=\")\nplayer_id = 3\n\n[node name=\"BuildableArea4\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(1, 0.483333, 0, 0.211765)\ntile_map_data = PackedByteArray(\"AAAiAI8AAAADAAAAAAAiAJAAAAADAAAAAAAiAJEAAAADAAAAAAAiAJIAAAADAAAAAAAiAJMAAAADAAAAAAAiAJQAAAADAAAAAAAiAJUAAAADAAAAAAAiAJYAAAADAAAAAAAiAJcAAAADAAAAAAAiAJgAAAADAAAAAAAiAJkAAAADAAAAAAAiAJoAAAADAAAAAAAiAJsAAAADAAAAAAAiAJwAAAADAAAAAAAiAJ0AAAADAAAAAAAiAJ4AAAADAAAAAAAiAJ8AAAADAAAAAAAiAKAAAAADAAAAAAAiAKEAAAADAAAAAAAjAI8AAAADAAAAAAAjAJAAAAADAAAAAAAjAJEAAAADAAAAAAAjAJIAAAADAAAAAAAjAJMAAAADAAAAAAAjAJQAAAADAAAAAAAjAJUAAAADAAAAAAAjAJYAAAADAAAAAAAjAJcAAAADAAAAAAAjAJgAAAADAAAAAAAjAJkAAAADAAAAAAAjAJoAAAADAAAAAAAjAJsAAAADAAAAAAAjAJwAAAADAAAAAAAjAJ0AAAADAAAAAAAjAJ4AAAADAAAAAAAjAJ8AAAADAAAAAAAjAKAAAAADAAAAAAAjAKEAAAADAAAAAAAkAI8AAAADAAAAAAAkAJAAAAADAAAAAAAkAJEAAAADAAAAAAAkAJIAAAADAAAAAAAkAJMAAAADAAAAAAAkAJQAAAADAAAAAAAkAJUAAAADAAAAAAAkAJYAAAADAAAAAAAkAJcAAAADAAAAAAAkAJgAAAADAAAAAAAkAJkAAAADAAAAAAAkAJoAAAADAAAAAAAkAJsAAAADAAAAAAAkAJwAAAADAAAAAAAkAJ0AAAADAAAAAAAkAJ4AAAADAAAAAAAkAJ8AAAADAAAAAAAkAKAAAAADAAAAAAAkAKEAAAADAAAAAAAlAI8AAAADAAAAAAAlAJAAAAADAAAAAAAlAJEAAAADAAAAAAAlAJIAAAADAAAAAAAlAJMAAAADAAAAAAAlAJQAAAADAAAAAAAlAJUAAAADAAAAAAAlAJYAAAADAAAAAAAlAJcAAAADAAAAAAAlAJgAAAADAAAAAAAlAJkAAAADAAAAAAAlAJoAAAADAAAAAAAlAJsAAAADAAAAAAAlAJwAAAADAAAAAAAlAJ0AAAADAAAAAAAlAJ4AAAADAAAAAAAlAJ8AAAADAAAAAAAlAKAAAAADAAAAAAAlAKEAAAADAAAAAAAmAI8AAAADAAAAAAAmAJAAAAADAAAAAAAmAJEAAAADAAAAAAAmAJIAAAADAAAAAAAmAJMAAAADAAAAAAAmAJQAAAADAAAAAAAmAJUAAAADAAAAAAAmAJYAAAADAAAAAAAmAJcAAAADAAAAAAAmAJgAAAADAAAAAAAmAJkAAAADAAAAAAAmAJoAAAADAAAAAAAmAJsAAAADAAAAAAAmAJwAAAADAAAAAAAmAJ0AAAADAAAAAAAmAJ4AAAADAAAAAAAmAJ8AAAADAAAAAAAmAKAAAAADAAAAAAAmAKEAAAADAAAAAAAnAI8AAAADAAAAAAAnAJAAAAADAAAAAAAnAJEAAAADAAAAAAAnAJIAAAADAAAAAAAnAJMAAAADAAAAAAAnAJQAAAADAAAAAAAnAJUAAAADAAAAAAAnAJYAAAADAAAAAAAnAJcAAAADAAAAAAAnAJgAAAADAAAAAAAnAJkAAAADAAAAAAAnAJoAAAADAAAAAAAnAJsAAAADAAAAAAAnAJwAAAADAAAAAAAnAJ0AAAADAAAAAAAnAJ4AAAADAAAAAAAnAJ8AAAADAAAAAAAnAKAAAAADAAAAAAAnAKEAAAADAAAAAAASAH8AAAADAAAAAAASAIAAAAADAAAAAAASAIEAAAADAAAAAAASAIIAAAADAAAAAAASAIMAAAADAAAAAAASAIQAAAADAAAAAAASAIUAAAADAAAAAAASAIYAAAADAAAAAAASAIcAAAADAAAAAAASAIgAAAADAAAAAAASAIkAAAADAAAAAAASAIoAAAADAAAAAAASAIsAAAADAAAAAAASAIwAAAADAAAAAAASAI0AAAADAAAAAAASAI4AAAADAAAAAAASAI8AAAADAAAAAAASAJAAAAADAAAAAAASAJEAAAADAAAAAAASAJIAAAADAAAAAAASAJMAAAADAAAAAAASAJQAAAADAAAAAAASAJUAAAADAAAAAAASAJYAAAADAAAAAAASAJcAAAADAAAAAAASAJgAAAADAAAAAAASAJkAAAADAAAAAAASAJoAAAADAAAAAAASAJsAAAADAAAAAAASAJwAAAADAAAAAAASAJ0AAAADAAAAAAASAJ4AAAADAAAAAAATAH8AAAADAAAAAAATAIAAAAADAAAAAAATAIEAAAADAAAAAAATAIIAAAADAAAAAAATAIMAAAADAAAAAAATAIQAAAADAAAAAAATAIUAAAADAAAAAAATAIYAAAADAAAAAAATAIcAAAADAAAAAAATAIgAAAADAAAAAAATAIkAAAADAAAAAAATAIoAAAADAAAAAAATAIsAAAADAAAAAAATAIwAAAADAAAAAAATAI0AAAADAAAAAAATAI4AAAADAAAAAAATAI8AAAADAAAAAAATAJAAAAADAAAAAAATAJEAAAADAAAAAAATAJIAAAADAAAAAAATAJMAAAADAAAAAAATAJQAAAADAAAAAAATAJUAAAADAAAAAAATAJYAAAADAAAAAAATAJcAAAADAAAAAAATAJgAAAADAAAAAAATAJkAAAADAAAAAAATAJoAAAADAAAAAAATAJsAAAADAAAAAAATAJwAAAADAAAAAAATAJ0AAAADAAAAAAATAJ4AAAADAAAAAAAUAH8AAAADAAAAAAAUAIAAAAADAAAAAAAUAIEAAAADAAAAAAAUAIIAAAADAAAAAAAUAIMAAAADAAAAAAAUAIQAAAADAAAAAAAUAIUAAAADAAAAAAAUAIYAAAADAAAAAAAUAIcAAAADAAAAAAAUAIgAAAADAAAAAAAUAIkAAAADAAAAAAAUAIoAAAADAAAAAAAUAIsAAAADAAAAAAAUAIwAAAADAAAAAAAUAI0AAAADAAAAAAAUAI4AAAADAAAAAAAUAI8AAAADAAAAAAAUAJAAAAADAAAAAAAUAJEAAAADAAAAAAAUAJIAAAADAAAAAAAUAJMAAAADAAAAAAAUAJQAAAADAAAAAAAUAJUAAAADAAAAAAAUAJYAAAADAAAAAAAUAJcAAAADAAAAAAAUAJgAAAADAAAAAAAUAJkAAAADAAAAAAAUAJoAAAADAAAAAAAUAJsAAAADAAAAAAAUAJwAAAADAAAAAAAUAJ0AAAADAAAAAAAUAJ4AAAADAAAAAAAVAH8AAAADAAAAAAAVAIAAAAADAAAAAAAVAIEAAAADAAAAAAAVAIIAAAADAAAAAAAVAIMAAAADAAAAAAAVAIQAAAADAAAAAAAVAIUAAAADAAAAAAAVAIYAAAADAAAAAAAVAIcAAAADAAAAAAAVAIgAAAADAAAAAAAVAIkAAAADAAAAAAAVAIoAAAADAAAAAAAVAIsAAAADAAAAAAAVAIwAAAADAAAAAAAVAI0AAAADAAAAAAAVAI4AAAADAAAAAAAVAI8AAAADAAAAAAAVAJAAAAADAAAAAAAVAJEAAAADAAAAAAAVAJIAAAADAAAAAAAVAJMAAAADAAAAAAAVAJQAAAADAAAAAAAVAJUAAAADAAAAAAAVAJYAAAADAAAAAAAVAJcAAAADAAAAAAAVAJgAAAADAAAAAAAVAJkAAAADAAAAAAAVAJoAAAADAAAAAAAVAJsAAAADAAAAAAAVAJwAAAADAAAAAAAVAJ0AAAADAAAAAAAVAJ4AAAADAAAAAAAWAH8AAAADAAAAAAAWAIAAAAADAAAAAAAWAIEAAAADAAAAAAAWAIIAAAADAAAAAAAWAIMAAAADAAAAAAAWAIQAAAADAAAAAAAWAIUAAAADAAAAAAAWAIYAAAADAAAAAAAWAIcAAAADAAAAAAAWAIgAAAADAAAAAAAWAIkAAAADAAAAAAAWAIoAAAADAAAAAAAWAIsAAAADAAAAAAAWAIwAAAADAAAAAAAWAI0AAAADAAAAAAAWAI4AAAADAAAAAAAWAI8AAAADAAAAAAAWAJAAAAADAAAAAAAWAJEAAAADAAAAAAAWAJIAAAADAAAAAAAWAJMAAAADAAAAAAAWAJQAAAADAAAAAAAWAJUAAAADAAAAAAAWAJYAAAADAAAAAAAWAJcAAAADAAAAAAAWAJgAAAADAAAAAAAWAJkAAAADAAAAAAAWAJoAAAADAAAAAAAWAJsAAAADAAAAAAAWAJwAAAADAAAAAAAWAJ0AAAADAAAAAAAWAJ4AAAADAAAAAAAXAH8AAAADAAAAAAAXAIAAAAADAAAAAAAXAIEAAAADAAAAAAAXAIIAAAADAAAAAAAXAIMAAAADAAAAAAAXAIQAAAADAAAAAAAXAIUAAAADAAAAAAAXAIYAAAADAAAAAAAXAIcAAAADAAAAAAAXAIgAAAADAAAAAAAXAIkAAAADAAAAAAAXAIoAAAADAAAAAAAXAIsAAAADAAAAAAAXAIwAAAADAAAAAAAXAI0AAAADAAAAAAAXAI4AAAADAAAAAAAXAI8AAAADAAAAAAAXAJAAAAADAAAAAAAXAJEAAAADAAAAAAAXAJIAAAADAAAAAAAXAJMAAAADAAAAAAAXAJQAAAADAAAAAAAXAJUAAAADAAAAAAAXAJYAAAADAAAAAAAXAJcAAAADAAAAAAAXAJgAAAADAAAAAAAXAJkAAAADAAAAAAAXAJoAAAADAAAAAAAXAJsAAAADAAAAAAAXAJwAAAADAAAAAAAXAJ0AAAADAAAAAAAXAJ4AAAADAAAAAAAYAH8AAAADAAAAAAAYAIAAAAADAAAAAAAYAIEAAAADAAAAAAAYAIIAAAADAAAAAAAYAIMAAAADAAAAAAAYAIQAAAADAAAAAAAZAH8AAAADAAAAAAAZAIAAAAADAAAAAAAZAIEAAAADAAAAAAAZAIIAAAADAAAAAAAZAIMAAAADAAAAAAAZAIQAAAADAAAAAAAaAH8AAAADAAAAAAAaAIAAAAADAAAAAAAaAIEAAAADAAAAAAAaAIIAAAADAAAAAAAaAIMAAAADAAAAAAAaAIQAAAADAAAAAAAbAH8AAAADAAAAAAAbAIAAAAADAAAAAAAbAIEAAAADAAAAAAAbAIIAAAADAAAAAAAbAIMAAAADAAAAAAAbAIQAAAADAAAAAAAcAH8AAAADAAAAAAAcAIAAAAADAAAAAAAcAIEAAAADAAAAAAAcAIIAAAADAAAAAAAcAIMAAAADAAAAAAAcAIQAAAADAAAAAAAdAH8AAAADAAAAAAAdAIAAAAADAAAAAAAdAIEAAAADAAAAAAAdAIIAAAADAAAAAAAdAIMAAAADAAAAAAAdAIQAAAADAAAAAAAeAH8AAAADAAAAAAAeAIAAAAADAAAAAAAeAIEAAAADAAAAAAAeAIIAAAADAAAAAAAeAIMAAAADAAAAAAAeAIQAAAADAAAAAAAfAH8AAAADAAAAAAAfAIAAAAADAAAAAAAfAIEAAAADAAAAAAAfAIIAAAADAAAAAAAfAIMAAAADAAAAAAAfAIQAAAADAAAAAAAgAH8AAAADAAAAAAAgAIAAAAADAAAAAAAgAIEAAAADAAAAAAAgAIIAAAADAAAAAAAgAIMAAAADAAAAAAAgAIQAAAADAAAAAAAhAH8AAAADAAAAAAAhAIAAAAADAAAAAAAhAIEAAAADAAAAAAAhAIIAAAADAAAAAAAhAIMAAAADAAAAAAAhAIQAAAADAAAAAAAiAH8AAAADAAAAAAAiAIAAAAADAAAAAAAiAIEAAAADAAAAAAAiAIIAAAADAAAAAAAiAIMAAAADAAAAAAAiAIQAAAADAAAAAAAjAH8AAAADAAAAAAAjAIAAAAADAAAAAAAjAIEAAAADAAAAAAAjAIIAAAADAAAAAAAjAIMAAAADAAAAAAAjAIQAAAADAAAAAAAkAH8AAAADAAAAAAAkAIAAAAADAAAAAAAkAIEAAAADAAAAAAAkAIIAAAADAAAAAAAkAIMAAAADAAAAAAAkAIQAAAADAAAAAAAlAH8AAAADAAAAAAAlAIAAAAADAAAAAAAlAIEAAAADAAAAAAAlAIIAAAADAAAAAAAlAIMAAAADAAAAAAAlAIQAAAADAAAAAAAmAH8AAAADAAAAAAAmAIAAAAADAAAAAAAmAIEAAAADAAAAAAAmAIIAAAADAAAAAAAmAIMAAAADAAAAAAAmAIQAAAADAAAAAAAnAH8AAAADAAAAAAAnAIAAAAADAAAAAAAnAIEAAAADAAAAAAAnAIIAAAADAAAAAAAnAIMAAAADAAAAAAAnAIQAAAADAAAAAAAoAH8AAAADAAAAAAAoAIAAAAADAAAAAAAoAIEAAAADAAAAAAAoAIIAAAADAAAAAAAoAIMAAAADAAAAAAAoAIQAAAADAAAAAAApAH8AAAADAAAAAAApAIAAAAADAAAAAAApAIEAAAADAAAAAAApAIIAAAADAAAAAAApAIMAAAADAAAAAAApAIQAAAADAAAAAAANAG8AAAADAAAAAAANAHAAAAADAAAAAAANAHEAAAADAAAAAAANAHIAAAADAAAAAAANAHMAAAADAAAAAAANAHQAAAADAAAAAAAOAG8AAAADAAAAAAAOAHAAAAADAAAAAAAOAHEAAAADAAAAAAAOAHIAAAADAAAAAAAOAHMAAAADAAAAAAAOAHQAAAADAAAAAAAPAG8AAAADAAAAAAAPAHAAAAADAAAAAAAPAHEAAAADAAAAAAAPAHIAAAADAAAAAAAPAHMAAAADAAAAAAAPAHQAAAADAAAAAAAQAG8AAAADAAAAAAAQAHAAAAADAAAAAAAQAHEAAAADAAAAAAAQAHIAAAADAAAAAAAQAHMAAAADAAAAAAAQAHQAAAADAAAAAAARAG8AAAADAAAAAAARAHAAAAADAAAAAAARAHEAAAADAAAAAAARAHIAAAADAAAAAAARAHMAAAADAAAAAAARAHQAAAADAAAAAAASAG8AAAADAAAAAAASAHAAAAADAAAAAAASAHEAAAADAAAAAAASAHIAAAADAAAAAAASAHMAAAADAAAAAAASAHQAAAADAAAAAAATAG8AAAADAAAAAAATAHAAAAADAAAAAAATAHEAAAADAAAAAAATAHIAAAADAAAAAAATAHMAAAADAAAAAAATAHQAAAADAAAAAAAUAG8AAAADAAAAAAAUAHAAAAADAAAAAAAUAHEAAAADAAAAAAAUAHIAAAADAAAAAAAUAHMAAAADAAAAAAAUAHQAAAADAAAAAAAVAG8AAAADAAAAAAAVAHAAAAADAAAAAAAVAHEAAAADAAAAAAAVAHIAAAADAAAAAAAVAHMAAAADAAAAAAAVAHQAAAADAAAAAAAWAG8AAAADAAAAAAAWAHAAAAADAAAAAAAWAHEAAAADAAAAAAAWAHIAAAADAAAAAAAWAHMAAAADAAAAAAAWAHQAAAADAAAAAAAXAG8AAAADAAAAAAAXAHAAAAADAAAAAAAXAHEAAAADAAAAAAAXAHIAAAADAAAAAAAXAHMAAAADAAAAAAAXAHQAAAADAAAAAAAYAG8AAAADAAAAAAAYAHAAAAADAAAAAAAYAHEAAAADAAAAAAAYAHIAAAADAAAAAAAYAHMAAAADAAAAAAAYAHQAAAADAAAAAAAZAG8AAAADAAAAAAAZAHAAAAADAAAAAAAZAHEAAAADAAAAAAAZAHIAAAADAAAAAAAZAHMAAAADAAAAAAAZAHQAAAADAAAAAAAaAG8AAAADAAAAAAAaAHAAAAADAAAAAAAaAHEAAAADAAAAAAAaAHIAAAADAAAAAAAaAHMAAAADAAAAAAAaAHQAAAADAAAAAAAbAG8AAAADAAAAAAAbAHAAAAADAAAAAAAbAHEAAAADAAAAAAAbAHIAAAADAAAAAAAbAHMAAAADAAAAAAAbAHQAAAADAAAAAAAcAG8AAAADAAAAAAAcAHAAAAADAAAAAAAcAHEAAAADAAAAAAAcAHIAAAADAAAAAAAcAHMAAAADAAAAAAAcAHQAAAADAAAAAAAdAG8AAAADAAAAAAAdAHAAAAADAAAAAAAdAHEAAAADAAAAAAAdAHIAAAADAAAAAAAdAHMAAAADAAAAAAAdAHQAAAADAAAAAAAeAG8AAAADAAAAAAAeAHAAAAADAAAAAAAeAHEAAAADAAAAAAAeAHIAAAADAAAAAAAeAHMAAAADAAAAAAAeAHQAAAADAAAAAAAfAG8AAAADAAAAAAAfAHAAAAADAAAAAAAfAHEAAAADAAAAAAAfAHIAAAADAAAAAAAfAHMAAAADAAAAAAAfAHQAAAADAAAAAAA=\")\nplayer_id = 4\n\n[node name=\"BuildableArea5\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(0.933333, 1, 0, 0.211765)\ntile_map_data = PackedByteArray(\"AAD9/3EAAAADAAAAAAD9/3IAAAADAAAAAAD9/3MAAAADAAAAAAD9/3QAAAADAAAAAAD+/3EAAAADAAAAAAD+/3IAAAADAAAAAAD+/3MAAAADAAAAAAD+/3QAAAADAAAAAAD//3EAAAADAAAAAAD//3IAAAADAAAAAAD//3MAAAADAAAAAAD//3QAAAADAAAAAAAAAHEAAAADAAAAAAAAAHIAAAADAAAAAAAAAHMAAAADAAAAAAAAAHQAAAADAAAAAAABAHEAAAADAAAAAAABAHIAAAADAAAAAAABAHMAAAADAAAAAAABAHQAAAADAAAAAAACAHEAAAADAAAAAAACAHIAAAADAAAAAAACAHMAAAADAAAAAAACAHQAAAADAAAAAAADAHEAAAADAAAAAAADAHIAAAADAAAAAAADAHMAAAADAAAAAAADAHQAAAADAAAAAAAEAHEAAAADAAAAAAAEAHIAAAADAAAAAAAEAHMAAAADAAAAAAAEAHQAAAADAAAAAAAFAHEAAAADAAAAAAAFAHIAAAADAAAAAAAFAHMAAAADAAAAAAAFAHQAAAADAAAAAAAGAHEAAAADAAAAAAAGAHIAAAADAAAAAAAGAHMAAAADAAAAAAAGAHQAAAADAAAAAAAHAHEAAAADAAAAAAAHAHIAAAADAAAAAAAHAHMAAAADAAAAAAAHAHQAAAADAAAAAAAIAHEAAAADAAAAAAAIAHIAAAADAAAAAAAIAHMAAAADAAAAAAAIAHQAAAADAAAAAAAJAHEAAAADAAAAAAAJAHIAAAADAAAAAAAJAHMAAAADAAAAAAAJAHQAAAADAAAAAAAKAHEAAAADAAAAAAAKAHIAAAADAAAAAAAKAHMAAAADAAAAAAAKAHQAAAADAAAAAAALAHEAAAADAAAAAAALAHIAAAADAAAAAAALAHMAAAADAAAAAAALAHQAAAADAAAAAAAMAHEAAAADAAAAAAAMAHIAAAADAAAAAAAMAHMAAAADAAAAAAAMAHQAAAADAAAAAAD6/28AAAADAAAAAAD6/3AAAAADAAAAAAD6/3EAAAADAAAAAAD6/3IAAAADAAAAAAD6/3MAAAADAAAAAAD6/3QAAAADAAAAAAD7/28AAAADAAAAAAD7/3AAAAADAAAAAAD7/3EAAAADAAAAAAD7/3IAAAADAAAAAAD7/3MAAAADAAAAAAD7/3QAAAADAAAAAAD8/28AAAADAAAAAAD8/3AAAAADAAAAAAD8/3EAAAADAAAAAAD8/3IAAAADAAAAAAD8/3MAAAADAAAAAAD8/3QAAAADAAAAAAD9/28AAAADAAAAAAD9/3AAAAADAAAAAAD+/28AAAADAAAAAAD+/3AAAAADAAAAAAD//28AAAADAAAAAAD//3AAAAADAAAAAAAAAG8AAAADAAAAAAAAAHAAAAADAAAAAAABAG8AAAADAAAAAAABAHAAAAADAAAAAAACAG8AAAADAAAAAAACAHAAAAADAAAAAAADAG8AAAADAAAAAAADAHAAAAADAAAAAAAEAG8AAAADAAAAAAAEAHAAAAADAAAAAAAFAG8AAAADAAAAAAAFAHAAAAADAAAAAAAGAG8AAAADAAAAAAAGAHAAAAADAAAAAAAHAG8AAAADAAAAAAAHAHAAAAADAAAAAAAIAG8AAAADAAAAAAAIAHAAAAADAAAAAAAJAG8AAAADAAAAAAAJAHAAAAADAAAAAAAKAG8AAAADAAAAAAAKAHAAAAADAAAAAAALAG8AAAADAAAAAAALAHAAAAADAAAAAAAMAG8AAAADAAAAAAAMAHAAAAADAAAAAAACAH8AAAADAAAAAAACAIAAAAADAAAAAAACAIEAAAADAAAAAAACAIIAAAADAAAAAAACAIMAAAADAAAAAAACAIQAAAADAAAAAAACAIUAAAADAAAAAAACAIYAAAADAAAAAAACAIcAAAADAAAAAAACAIgAAAADAAAAAAACAIkAAAADAAAAAAACAIoAAAADAAAAAAACAIsAAAADAAAAAAACAIwAAAADAAAAAAACAI0AAAADAAAAAAACAI4AAAADAAAAAAACAI8AAAADAAAAAAACAJAAAAADAAAAAAACAJEAAAADAAAAAAACAJIAAAADAAAAAAACAJMAAAADAAAAAAACAJQAAAADAAAAAAACAJUAAAADAAAAAAACAJYAAAADAAAAAAACAJcAAAADAAAAAAACAJgAAAADAAAAAAACAJkAAAADAAAAAAACAJoAAAADAAAAAAACAJsAAAADAAAAAAACAJwAAAADAAAAAAACAJ0AAAADAAAAAAACAJ4AAAADAAAAAAADAH8AAAADAAAAAAADAIAAAAADAAAAAAADAIEAAAADAAAAAAADAIIAAAADAAAAAAADAIMAAAADAAAAAAADAIQAAAADAAAAAAADAIUAAAADAAAAAAADAIYAAAADAAAAAAADAIcAAAADAAAAAAADAIgAAAADAAAAAAADAIkAAAADAAAAAAADAIoAAAADAAAAAAADAIsAAAADAAAAAAADAIwAAAADAAAAAAADAI0AAAADAAAAAAADAI4AAAADAAAAAAADAI8AAAADAAAAAAADAJAAAAADAAAAAAADAJEAAAADAAAAAAADAJIAAAADAAAAAAADAJMAAAADAAAAAAADAJQAAAADAAAAAAADAJUAAAADAAAAAAADAJYAAAADAAAAAAADAJcAAAADAAAAAAADAJgAAAADAAAAAAADAJkAAAADAAAAAAADAJoAAAADAAAAAAADAJsAAAADAAAAAAADAJwAAAADAAAAAAADAJ0AAAADAAAAAAADAJ4AAAADAAAAAAAEAH8AAAADAAAAAAAEAIAAAAADAAAAAAAEAIEAAAADAAAAAAAEAIIAAAADAAAAAAAEAIMAAAADAAAAAAAEAIQAAAADAAAAAAAEAIUAAAADAAAAAAAEAIYAAAADAAAAAAAEAIcAAAADAAAAAAAEAIgAAAADAAAAAAAEAIkAAAADAAAAAAAEAIoAAAADAAAAAAAEAIsAAAADAAAAAAAEAIwAAAADAAAAAAAEAI0AAAADAAAAAAAEAI4AAAADAAAAAAAEAI8AAAADAAAAAAAEAJAAAAADAAAAAAAEAJEAAAADAAAAAAAEAJIAAAADAAAAAAAEAJMAAAADAAAAAAAEAJQAAAADAAAAAAAEAJUAAAADAAAAAAAEAJYAAAADAAAAAAAEAJcAAAADAAAAAAAEAJgAAAADAAAAAAAEAJkAAAADAAAAAAAEAJoAAAADAAAAAAAEAJsAAAADAAAAAAAEAJwAAAADAAAAAAAEAJ0AAAADAAAAAAAEAJ4AAAADAAAAAAAFAH8AAAADAAAAAAAFAIAAAAADAAAAAAAFAIEAAAADAAAAAAAFAIIAAAADAAAAAAAFAIMAAAADAAAAAAAFAIQAAAADAAAAAAAFAIUAAAADAAAAAAAFAIYAAAADAAAAAAAFAIcAAAADAAAAAAAFAIgAAAADAAAAAAAFAIkAAAADAAAAAAAFAIoAAAADAAAAAAAFAIsAAAADAAAAAAAFAIwAAAADAAAAAAAFAI0AAAADAAAAAAAFAI4AAAADAAAAAAAFAI8AAAADAAAAAAAFAJAAAAADAAAAAAAFAJEAAAADAAAAAAAFAJIAAAADAAAAAAAFAJMAAAADAAAAAAAFAJQAAAADAAAAAAAFAJUAAAADAAAAAAAFAJYAAAADAAAAAAAFAJcAAAADAAAAAAAFAJgAAAADAAAAAAAFAJkAAAADAAAAAAAFAJoAAAADAAAAAAAFAJsAAAADAAAAAAAFAJwAAAADAAAAAAAFAJ0AAAADAAAAAAAFAJ4AAAADAAAAAAAGAH8AAAADAAAAAAAGAIAAAAADAAAAAAAGAIEAAAADAAAAAAAGAIIAAAADAAAAAAAGAIMAAAADAAAAAAAGAIQAAAADAAAAAAAGAIUAAAADAAAAAAAGAIYAAAADAAAAAAAGAIcAAAADAAAAAAAGAIgAAAADAAAAAAAGAIkAAAADAAAAAAAGAIoAAAADAAAAAAAGAIsAAAADAAAAAAAGAIwAAAADAAAAAAAGAI0AAAADAAAAAAAGAI4AAAADAAAAAAAGAI8AAAADAAAAAAAGAJAAAAADAAAAAAAGAJEAAAADAAAAAAAGAJIAAAADAAAAAAAGAJMAAAADAAAAAAAGAJQAAAADAAAAAAAGAJUAAAADAAAAAAAGAJYAAAADAAAAAAAGAJcAAAADAAAAAAAGAJgAAAADAAAAAAAGAJkAAAADAAAAAAAGAJoAAAADAAAAAAAGAJsAAAADAAAAAAAGAJwAAAADAAAAAAAGAJ0AAAADAAAAAAAGAJ4AAAADAAAAAAAHAH8AAAADAAAAAAAHAIAAAAADAAAAAAAHAIEAAAADAAAAAAAHAIIAAAADAAAAAAAHAIMAAAADAAAAAAAHAIQAAAADAAAAAAAHAIUAAAADAAAAAAAHAIYAAAADAAAAAAAHAIcAAAADAAAAAAAHAIgAAAADAAAAAAAHAIkAAAADAAAAAAAHAIoAAAADAAAAAAAHAIsAAAADAAAAAAAHAIwAAAADAAAAAAAHAI0AAAADAAAAAAAHAI4AAAADAAAAAAAHAI8AAAADAAAAAAAHAJAAAAADAAAAAAAHAJEAAAADAAAAAAAHAJIAAAADAAAAAAAHAJMAAAADAAAAAAAHAJQAAAADAAAAAAAHAJUAAAADAAAAAAAHAJYAAAADAAAAAAAHAJcAAAADAAAAAAAHAJgAAAADAAAAAAAHAJkAAAADAAAAAAAHAJoAAAADAAAAAAAHAJsAAAADAAAAAAAHAJwAAAADAAAAAAAHAJ0AAAADAAAAAAAHAJ4AAAADAAAAAADx/38AAAADAAAAAADx/4AAAAADAAAAAADx/4EAAAADAAAAAADx/4IAAAADAAAAAADx/4MAAAADAAAAAADx/4QAAAADAAAAAADy/38AAAADAAAAAADy/4AAAAADAAAAAADy/4EAAAADAAAAAADy/4IAAAADAAAAAADy/4MAAAADAAAAAADy/4QAAAADAAAAAADz/38AAAADAAAAAADz/4AAAAADAAAAAADz/4EAAAADAAAAAADz/4IAAAADAAAAAADz/4MAAAADAAAAAADz/4QAAAADAAAAAAD0/38AAAADAAAAAAD0/4AAAAADAAAAAAD0/4EAAAADAAAAAAD0/4IAAAADAAAAAAD0/4MAAAADAAAAAAD0/4QAAAADAAAAAAD1/38AAAADAAAAAAD1/4AAAAADAAAAAAD1/4EAAAADAAAAAAD1/4IAAAADAAAAAAD1/4MAAAADAAAAAAD1/4QAAAADAAAAAAD2/38AAAADAAAAAAD2/4AAAAADAAAAAAD2/4EAAAADAAAAAAD2/4IAAAADAAAAAAD2/4MAAAADAAAAAAD2/4QAAAADAAAAAAD3/38AAAADAAAAAAD3/4AAAAADAAAAAAD3/4EAAAADAAAAAAD3/4IAAAADAAAAAAD3/4MAAAADAAAAAAD3/4QAAAADAAAAAAD4/38AAAADAAAAAAD4/4AAAAADAAAAAAD4/4EAAAADAAAAAAD4/4IAAAADAAAAAAD4/4MAAAADAAAAAAD4/4QAAAADAAAAAAD5/38AAAADAAAAAAD5/4AAAAADAAAAAAD5/4EAAAADAAAAAAD5/4IAAAADAAAAAAD5/4MAAAADAAAAAAD5/4QAAAADAAAAAAD6/38AAAADAAAAAAD6/4AAAAADAAAAAAD6/4EAAAADAAAAAAD6/4IAAAADAAAAAAD6/4MAAAADAAAAAAD6/4QAAAADAAAAAAD7/38AAAADAAAAAAD7/4AAAAADAAAAAAD7/4EAAAADAAAAAAD7/4IAAAADAAAAAAD7/4MAAAADAAAAAAD7/4QAAAADAAAAAAD8/38AAAADAAAAAAD8/4AAAAADAAAAAAD8/4EAAAADAAAAAAD8/4IAAAADAAAAAAD8/4MAAAADAAAAAAD8/4QAAAADAAAAAAD9/38AAAADAAAAAAD9/4AAAAADAAAAAAD9/4EAAAADAAAAAAD9/4IAAAADAAAAAAD9/4MAAAADAAAAAAD9/4QAAAADAAAAAAD+/38AAAADAAAAAAD+/4AAAAADAAAAAAD+/4EAAAADAAAAAAD+/4IAAAADAAAAAAD+/4MAAAADAAAAAAD+/4QAAAADAAAAAAD//38AAAADAAAAAAD//4AAAAADAAAAAAD//4EAAAADAAAAAAD//4IAAAADAAAAAAD//4MAAAADAAAAAAD//4QAAAADAAAAAAAAAH8AAAADAAAAAAAAAIAAAAADAAAAAAAAAIEAAAADAAAAAAAAAIIAAAADAAAAAAAAAIMAAAADAAAAAAAAAIQAAAADAAAAAAABAH8AAAADAAAAAAABAIAAAAADAAAAAAABAIEAAAADAAAAAAABAIIAAAADAAAAAAABAIMAAAADAAAAAAABAIQAAAADAAAAAADy/48AAAADAAAAAADy/5AAAAADAAAAAADy/5EAAAADAAAAAADy/5IAAAADAAAAAADy/5MAAAADAAAAAADy/5QAAAADAAAAAADy/5UAAAADAAAAAADy/5YAAAADAAAAAADy/5cAAAADAAAAAADy/5gAAAADAAAAAADy/5kAAAADAAAAAADy/5oAAAADAAAAAADy/5sAAAADAAAAAADy/5wAAAADAAAAAADy/50AAAADAAAAAADy/54AAAADAAAAAADy/58AAAADAAAAAADy/6AAAAADAAAAAADy/6EAAAADAAAAAADz/48AAAADAAAAAADz/5AAAAADAAAAAADz/5EAAAADAAAAAADz/5IAAAADAAAAAADz/5MAAAADAAAAAADz/5QAAAADAAAAAADz/5UAAAADAAAAAADz/5YAAAADAAAAAADz/5cAAAADAAAAAADz/5gAAAADAAAAAADz/5kAAAADAAAAAADz/5oAAAADAAAAAADz/5sAAAADAAAAAADz/5wAAAADAAAAAADz/50AAAADAAAAAADz/54AAAADAAAAAADz/58AAAADAAAAAADz/6AAAAADAAAAAADz/6EAAAADAAAAAAD0/48AAAADAAAAAAD0/5AAAAADAAAAAAD0/5EAAAADAAAAAAD0/5IAAAADAAAAAAD0/5MAAAADAAAAAAD0/5QAAAADAAAAAAD0/5UAAAADAAAAAAD0/5YAAAADAAAAAAD0/5cAAAADAAAAAAD0/5gAAAADAAAAAAD0/5kAAAADAAAAAAD0/5oAAAADAAAAAAD0/5sAAAADAAAAAAD0/5wAAAADAAAAAAD0/50AAAADAAAAAAD0/54AAAADAAAAAAD0/58AAAADAAAAAAD0/6AAAAADAAAAAAD0/6EAAAADAAAAAAD1/48AAAADAAAAAAD1/5AAAAADAAAAAAD1/5EAAAADAAAAAAD1/5IAAAADAAAAAAD1/5MAAAADAAAAAAD1/5QAAAADAAAAAAD1/5UAAAADAAAAAAD1/5YAAAADAAAAAAD1/5cAAAADAAAAAAD1/5gAAAADAAAAAAD1/5kAAAADAAAAAAD1/5oAAAADAAAAAAD1/5sAAAADAAAAAAD1/5wAAAADAAAAAAD1/50AAAADAAAAAAD1/54AAAADAAAAAAD1/58AAAADAAAAAAD1/6AAAAADAAAAAAD1/6EAAAADAAAAAAD2/48AAAADAAAAAAD2/5AAAAADAAAAAAD2/5EAAAADAAAAAAD2/5IAAAADAAAAAAD2/5MAAAADAAAAAAD2/5QAAAADAAAAAAD2/5UAAAADAAAAAAD2/5YAAAADAAAAAAD2/5cAAAADAAAAAAD2/5gAAAADAAAAAAD2/5kAAAADAAAAAAD2/5oAAAADAAAAAAD2/5sAAAADAAAAAAD2/5wAAAADAAAAAAD2/50AAAADAAAAAAD2/54AAAADAAAAAAD2/58AAAADAAAAAAD2/6AAAAADAAAAAAD2/6EAAAADAAAAAAD3/48AAAADAAAAAAD3/5AAAAADAAAAAAD3/5EAAAADAAAAAAD3/5IAAAADAAAAAAD3/5MAAAADAAAAAAD3/5QAAAADAAAAAAD3/5UAAAADAAAAAAD3/5YAAAADAAAAAAD3/5cAAAADAAAAAAD3/5gAAAADAAAAAAD3/5kAAAADAAAAAAD3/5oAAAADAAAAAAD3/5sAAAADAAAAAAD3/5wAAAADAAAAAAD3/50AAAADAAAAAAD3/54AAAADAAAAAAD3/58AAAADAAAAAAD3/6AAAAADAAAAAAD3/6EAAAADAAAAAAA=\")\nplayer_id = 5\n\n[node name=\"BuildableArea6\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(0.35, 1, 0, 0.211765)\ntile_map_data = PackedByteArray(\"AACr/1UAAAADAAAAAACr/1YAAAADAAAAAACr/1cAAAADAAAAAACr/1gAAAADAAAAAACr/1kAAAADAAAAAACr/1oAAAADAAAAAACs/1UAAAADAAAAAACs/1YAAAADAAAAAACs/1cAAAADAAAAAACs/1gAAAADAAAAAACs/1kAAAADAAAAAACs/1oAAAADAAAAAACt/1UAAAADAAAAAACt/1YAAAADAAAAAACt/1cAAAADAAAAAACt/1gAAAADAAAAAACt/1kAAAADAAAAAACt/1oAAAADAAAAAACu/1UAAAADAAAAAACu/1YAAAADAAAAAACu/1cAAAADAAAAAACu/1gAAAADAAAAAACu/1kAAAADAAAAAACu/1oAAAADAAAAAACv/1UAAAADAAAAAACv/1YAAAADAAAAAACv/1cAAAADAAAAAACv/1gAAAADAAAAAACv/1kAAAADAAAAAACv/1oAAAADAAAAAACw/1UAAAADAAAAAACw/1YAAAADAAAAAACw/1cAAAADAAAAAACw/1gAAAADAAAAAACw/1kAAAADAAAAAACw/1oAAAADAAAAAACx/1UAAAADAAAAAACx/1YAAAADAAAAAACx/1cAAAADAAAAAACx/1gAAAADAAAAAACx/1kAAAADAAAAAACx/1oAAAADAAAAAACy/1UAAAADAAAAAACy/1YAAAADAAAAAACy/1cAAAADAAAAAACy/1gAAAADAAAAAACy/1kAAAADAAAAAACy/1oAAAADAAAAAACz/1UAAAADAAAAAACz/1YAAAADAAAAAACz/1cAAAADAAAAAACz/1gAAAADAAAAAACz/1kAAAADAAAAAACz/1oAAAADAAAAAAC0/1UAAAADAAAAAAC0/1YAAAADAAAAAAC0/1cAAAADAAAAAAC0/1gAAAADAAAAAAC0/1kAAAADAAAAAAC0/1oAAAADAAAAAAC1/1UAAAADAAAAAAC1/1YAAAADAAAAAAC1/1cAAAADAAAAAAC1/1gAAAADAAAAAAC1/1kAAAADAAAAAAC1/1oAAAADAAAAAAC2/1UAAAADAAAAAAC2/1YAAAADAAAAAAC2/1cAAAADAAAAAAC2/1gAAAADAAAAAAC2/1kAAAADAAAAAAC2/1oAAAADAAAAAAC3/1UAAAADAAAAAAC3/1YAAAADAAAAAAC3/1cAAAADAAAAAAC3/1gAAAADAAAAAAC3/1kAAAADAAAAAAC3/1oAAAADAAAAAAC4/1UAAAADAAAAAAC4/1YAAAADAAAAAAC4/1cAAAADAAAAAAC4/1gAAAADAAAAAAC4/1kAAAADAAAAAAC4/1oAAAADAAAAAAC5/1UAAAADAAAAAAC5/1YAAAADAAAAAAC5/1cAAAADAAAAAAC5/1gAAAADAAAAAAC5/1kAAAADAAAAAAC5/1oAAAADAAAAAAC6/1UAAAADAAAAAAC6/1YAAAADAAAAAAC6/1cAAAADAAAAAAC6/1gAAAADAAAAAAC6/1kAAAADAAAAAAC6/1oAAAADAAAAAAC7/1UAAAADAAAAAAC7/1YAAAADAAAAAAC7/1cAAAADAAAAAAC7/1gAAAADAAAAAAC7/1kAAAADAAAAAAC7/1oAAAADAAAAAAC8/1UAAAADAAAAAAC8/1YAAAADAAAAAAC8/1cAAAADAAAAAAC8/1gAAAADAAAAAAC8/1kAAAADAAAAAAC8/1oAAAADAAAAAAC9/1UAAAADAAAAAAC9/1YAAAADAAAAAAC9/1cAAAADAAAAAAC9/1gAAAADAAAAAAC9/1kAAAADAAAAAAC9/1oAAAADAAAAAACw/0UAAAADAAAAAACw/0YAAAADAAAAAACw/0cAAAADAAAAAACw/0gAAAADAAAAAACw/0kAAAADAAAAAACw/0oAAAADAAAAAACx/0UAAAADAAAAAACx/0YAAAADAAAAAACx/0cAAAADAAAAAACx/0gAAAADAAAAAACx/0kAAAADAAAAAACx/0oAAAADAAAAAACy/0UAAAADAAAAAACy/0YAAAADAAAAAACy/0cAAAADAAAAAACy/0gAAAADAAAAAACy/0kAAAADAAAAAACy/0oAAAADAAAAAACz/0UAAAADAAAAAACz/0YAAAADAAAAAACz/0cAAAADAAAAAACz/0gAAAADAAAAAACz/0kAAAADAAAAAACz/0oAAAADAAAAAAC0/0UAAAADAAAAAAC0/0YAAAADAAAAAAC0/0cAAAADAAAAAAC0/0gAAAADAAAAAAC0/0kAAAADAAAAAAC0/0oAAAADAAAAAAC1/0UAAAADAAAAAAC1/0YAAAADAAAAAAC1/0cAAAADAAAAAAC1/0gAAAADAAAAAAC1/0kAAAADAAAAAAC1/0oAAAADAAAAAAC2/0UAAAADAAAAAAC2/0YAAAADAAAAAAC2/0cAAAADAAAAAAC2/0gAAAADAAAAAAC2/0kAAAADAAAAAAC2/0oAAAADAAAAAAC3/0UAAAADAAAAAAC3/0YAAAADAAAAAAC3/0cAAAADAAAAAAC3/0gAAAADAAAAAAC3/0kAAAADAAAAAAC3/0oAAAADAAAAAAC4/0UAAAADAAAAAAC4/0YAAAADAAAAAAC4/0cAAAADAAAAAAC4/0gAAAADAAAAAAC4/0kAAAADAAAAAAC4/0oAAAADAAAAAAC5/0UAAAADAAAAAAC5/0YAAAADAAAAAAC5/0cAAAADAAAAAAC5/0gAAAADAAAAAAC5/0kAAAADAAAAAAC5/0oAAAADAAAAAAC6/0UAAAADAAAAAAC6/0YAAAADAAAAAAC6/0cAAAADAAAAAAC6/0gAAAADAAAAAAC6/0kAAAADAAAAAAC6/0oAAAADAAAAAAC7/0UAAAADAAAAAAC7/0YAAAADAAAAAAC7/0cAAAADAAAAAAC7/0gAAAADAAAAAAC7/0kAAAADAAAAAAC7/0oAAAADAAAAAAC8/0UAAAADAAAAAAC8/0YAAAADAAAAAAC8/0cAAAADAAAAAAC8/0gAAAADAAAAAAC8/0kAAAADAAAAAAC8/0oAAAADAAAAAAC9/0UAAAADAAAAAAC9/0YAAAADAAAAAAC9/0cAAAADAAAAAAC9/0gAAAADAAAAAAC9/0kAAAADAAAAAAC9/0oAAAADAAAAAAC+/0UAAAADAAAAAAC+/0YAAAADAAAAAAC+/0cAAAADAAAAAAC+/0gAAAADAAAAAAC+/0kAAAADAAAAAAC+/0oAAAADAAAAAAC//0UAAAADAAAAAAC//0YAAAADAAAAAAC//0cAAAADAAAAAAC//0gAAAADAAAAAAC//0kAAAADAAAAAAC//0oAAAADAAAAAADA/0UAAAADAAAAAADA/0YAAAADAAAAAADA/0cAAAADAAAAAADA/0gAAAADAAAAAADA/0kAAAADAAAAAADA/0oAAAADAAAAAADB/0UAAAADAAAAAADB/0YAAAADAAAAAADB/0cAAAADAAAAAADB/0gAAAADAAAAAADB/0kAAAADAAAAAADB/0oAAAADAAAAAADC/0UAAAADAAAAAADC/0YAAAADAAAAAADC/0cAAAADAAAAAADC/0gAAAADAAAAAADC/0kAAAADAAAAAADC/0oAAAADAAAAAADD/0UAAAADAAAAAADD/0YAAAADAAAAAADD/0cAAAADAAAAAADD/0gAAAADAAAAAADD/0kAAAADAAAAAADD/0oAAAADAAAAAADE/0UAAAADAAAAAADE/0YAAAADAAAAAADE/0cAAAADAAAAAADE/0gAAAADAAAAAADE/0kAAAADAAAAAADE/0oAAAADAAAAAADF/0UAAAADAAAAAADF/0YAAAADAAAAAADF/0cAAAADAAAAAADF/0gAAAADAAAAAADF/0kAAAADAAAAAADF/0oAAAADAAAAAADG/0UAAAADAAAAAADG/0YAAAADAAAAAADG/0cAAAADAAAAAADG/0gAAAADAAAAAADG/0kAAAADAAAAAADG/0oAAAADAAAAAADH/0UAAAADAAAAAADH/0YAAAADAAAAAADH/0cAAAADAAAAAADH/0gAAAADAAAAAADH/0kAAAADAAAAAADH/0oAAAADAAAAAADI/0UAAAADAAAAAADI/0YAAAADAAAAAADI/0cAAAADAAAAAADI/0gAAAADAAAAAADI/0kAAAADAAAAAADI/0oAAAADAAAAAADJ/0UAAAADAAAAAADJ/0YAAAADAAAAAADJ/0cAAAADAAAAAADJ/0gAAAADAAAAAADJ/0kAAAADAAAAAADJ/0oAAAADAAAAAADK/0UAAAADAAAAAADK/0YAAAADAAAAAADK/0cAAAADAAAAAADK/0gAAAADAAAAAADK/0kAAAADAAAAAADK/0oAAAADAAAAAADL/0UAAAADAAAAAADL/0YAAAADAAAAAADL/0cAAAADAAAAAADL/0gAAAADAAAAAADL/0kAAAADAAAAAADL/0oAAAADAAAAAADM/0UAAAADAAAAAADM/0YAAAADAAAAAADM/0cAAAADAAAAAADM/0gAAAADAAAAAADM/0kAAAADAAAAAADM/0oAAAADAAAAAADN/0UAAAADAAAAAADN/0YAAAADAAAAAADN/0cAAAADAAAAAADN/0gAAAADAAAAAADN/0kAAAADAAAAAADN/0oAAAADAAAAAADI/0sAAAADAAAAAADI/0wAAAADAAAAAADI/00AAAADAAAAAADI/04AAAADAAAAAADI/08AAAADAAAAAADI/1AAAAADAAAAAADI/1EAAAADAAAAAADI/1IAAAADAAAAAADI/1MAAAADAAAAAADI/1QAAAADAAAAAADI/1UAAAADAAAAAADI/1YAAAADAAAAAADI/1cAAAADAAAAAADI/1gAAAADAAAAAADI/1kAAAADAAAAAADI/1oAAAADAAAAAADI/1sAAAADAAAAAADJ/0sAAAADAAAAAADJ/0wAAAADAAAAAADJ/00AAAADAAAAAADJ/04AAAADAAAAAADJ/08AAAADAAAAAADJ/1AAAAADAAAAAADJ/1EAAAADAAAAAADJ/1IAAAADAAAAAADJ/1MAAAADAAAAAADJ/1QAAAADAAAAAADJ/1UAAAADAAAAAADJ/1YAAAADAAAAAADJ/1cAAAADAAAAAADJ/1gAAAADAAAAAADJ/1kAAAADAAAAAADJ/1oAAAADAAAAAADJ/1sAAAADAAAAAADK/0sAAAADAAAAAADK/0wAAAADAAAAAADK/00AAAADAAAAAADK/04AAAADAAAAAADK/08AAAADAAAAAADK/1AAAAADAAAAAADK/1EAAAADAAAAAADK/1IAAAADAAAAAADK/1MAAAADAAAAAADK/1QAAAADAAAAAADK/1UAAAADAAAAAADK/1YAAAADAAAAAADK/1cAAAADAAAAAADK/1gAAAADAAAAAADK/1kAAAADAAAAAADK/1oAAAADAAAAAADK/1sAAAADAAAAAADL/0sAAAADAAAAAADL/0wAAAADAAAAAADL/00AAAADAAAAAADL/04AAAADAAAAAADL/08AAAADAAAAAADL/1AAAAADAAAAAADL/1EAAAADAAAAAADL/1IAAAADAAAAAADL/1MAAAADAAAAAADL/1QAAAADAAAAAADL/1UAAAADAAAAAADL/1YAAAADAAAAAADL/1cAAAADAAAAAADL/1gAAAADAAAAAADL/1kAAAADAAAAAADL/1oAAAADAAAAAADL/1sAAAADAAAAAADM/0sAAAADAAAAAADM/0wAAAADAAAAAADM/00AAAADAAAAAADM/04AAAADAAAAAADM/08AAAADAAAAAADM/1AAAAADAAAAAADM/1EAAAADAAAAAADM/1IAAAADAAAAAADM/1MAAAADAAAAAADM/1QAAAADAAAAAADM/1UAAAADAAAAAADM/1YAAAADAAAAAADM/1cAAAADAAAAAADM/1gAAAADAAAAAADM/1kAAAADAAAAAADM/1oAAAADAAAAAADM/1sAAAADAAAAAADN/0sAAAADAAAAAADN/0wAAAADAAAAAADN/00AAAADAAAAAADN/04AAAADAAAAAADN/08AAAADAAAAAADN/1AAAAADAAAAAADN/1EAAAADAAAAAADN/1IAAAADAAAAAADN/1MAAAADAAAAAADN/1QAAAADAAAAAADN/1UAAAADAAAAAADN/1YAAAADAAAAAADN/1cAAAADAAAAAADN/1gAAAADAAAAAADN/1kAAAADAAAAAADN/1oAAAADAAAAAADN/1sAAAADAAAAAADY/0AAAAADAAAAAADY/0EAAAADAAAAAADY/0IAAAADAAAAAADY/0MAAAADAAAAAADY/0QAAAADAAAAAADY/0UAAAADAAAAAADY/0YAAAADAAAAAADY/0cAAAADAAAAAADY/0gAAAADAAAAAADY/0kAAAADAAAAAADY/0oAAAADAAAAAADY/0sAAAADAAAAAADY/0wAAAADAAAAAADY/00AAAADAAAAAADY/04AAAADAAAAAADY/08AAAADAAAAAADY/1AAAAADAAAAAADY/1EAAAADAAAAAADY/1IAAAADAAAAAADZ/0AAAAADAAAAAADZ/0EAAAADAAAAAADZ/0IAAAADAAAAAADZ/0MAAAADAAAAAADZ/0QAAAADAAAAAADZ/0UAAAADAAAAAADZ/0YAAAADAAAAAADZ/0cAAAADAAAAAADZ/0gAAAADAAAAAADZ/0kAAAADAAAAAADZ/0oAAAADAAAAAADZ/0sAAAADAAAAAADZ/0wAAAADAAAAAADZ/00AAAADAAAAAADZ/04AAAADAAAAAADZ/08AAAADAAAAAADZ/1AAAAADAAAAAADZ/1EAAAADAAAAAADZ/1IAAAADAAAAAADa/0AAAAADAAAAAADa/0EAAAADAAAAAADa/0IAAAADAAAAAADa/0MAAAADAAAAAADa/0QAAAADAAAAAADa/0UAAAADAAAAAADa/0YAAAADAAAAAADa/0cAAAADAAAAAADa/0gAAAADAAAAAADa/0kAAAADAAAAAADa/0oAAAADAAAAAADa/0sAAAADAAAAAADa/0wAAAADAAAAAADa/00AAAADAAAAAADa/04AAAADAAAAAADa/08AAAADAAAAAADa/1AAAAADAAAAAADa/1EAAAADAAAAAADa/1IAAAADAAAAAADb/0AAAAADAAAAAADb/0EAAAADAAAAAADb/0IAAAADAAAAAADb/0MAAAADAAAAAADb/0QAAAADAAAAAADb/0UAAAADAAAAAADb/0YAAAADAAAAAADb/0cAAAADAAAAAADb/0gAAAADAAAAAADb/0kAAAADAAAAAADb/0oAAAADAAAAAADb/0sAAAADAAAAAADb/0wAAAADAAAAAADb/00AAAADAAAAAADb/04AAAADAAAAAADb/08AAAADAAAAAADb/1AAAAADAAAAAADb/1EAAAADAAAAAADb/1IAAAADAAAAAADc/0AAAAADAAAAAADc/0EAAAADAAAAAADc/0IAAAADAAAAAADc/0MAAAADAAAAAADc/0QAAAADAAAAAADc/0UAAAADAAAAAADc/0YAAAADAAAAAADc/0cAAAADAAAAAADc/0gAAAADAAAAAADc/0kAAAADAAAAAADc/0oAAAADAAAAAADc/0sAAAADAAAAAADc/0wAAAADAAAAAADc/00AAAADAAAAAADc/04AAAADAAAAAADc/08AAAADAAAAAADc/1AAAAADAAAAAADc/1EAAAADAAAAAADc/1IAAAADAAAAAADd/0AAAAADAAAAAADd/0EAAAADAAAAAADd/0IAAAADAAAAAADd/0MAAAADAAAAAADd/0QAAAADAAAAAADd/0UAAAADAAAAAADd/0YAAAADAAAAAADd/0cAAAADAAAAAADd/0gAAAADAAAAAADd/0kAAAADAAAAAADd/0oAAAADAAAAAADd/0sAAAADAAAAAADd/0wAAAADAAAAAADd/00AAAADAAAAAADd/04AAAADAAAAAADd/08AAAADAAAAAADd/1AAAAADAAAAAADd/1EAAAADAAAAAADd/1IAAAADAAAAAAA=\")\nplayer_id = 6\n\n[node name=\"BuildableArea7\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_vfex0\")]\nvisible = false\nmodulate = Color(0, 1, 0.366667, 0.211765)\ntile_map_data = PackedByteArray(\"AADY/y0AAAADAAAAAADY/y4AAAADAAAAAADY/y8AAAADAAAAAADY/zAAAAADAAAAAADY/zEAAAADAAAAAADY/zIAAAADAAAAAADY/zMAAAADAAAAAADY/zQAAAADAAAAAADY/zUAAAADAAAAAADY/zYAAAADAAAAAADY/zcAAAADAAAAAADY/zgAAAADAAAAAADY/zkAAAADAAAAAADY/zoAAAADAAAAAADY/zsAAAADAAAAAADY/zwAAAADAAAAAADY/z0AAAADAAAAAADY/z4AAAADAAAAAADY/z8AAAADAAAAAADZ/y0AAAADAAAAAADZ/y4AAAADAAAAAADZ/y8AAAADAAAAAADZ/zAAAAADAAAAAADZ/zEAAAADAAAAAADZ/zIAAAADAAAAAADZ/zMAAAADAAAAAADZ/zQAAAADAAAAAADZ/zUAAAADAAAAAADZ/zYAAAADAAAAAADZ/zcAAAADAAAAAADZ/zgAAAADAAAAAADZ/zkAAAADAAAAAADZ/zoAAAADAAAAAADZ/zsAAAADAAAAAADZ/zwAAAADAAAAAADZ/z0AAAADAAAAAADZ/z4AAAADAAAAAADZ/z8AAAADAAAAAADa/y0AAAADAAAAAADa/y4AAAADAAAAAADa/y8AAAADAAAAAADa/zAAAAADAAAAAADa/zEAAAADAAAAAADa/zIAAAADAAAAAADa/zMAAAADAAAAAADa/zQAAAADAAAAAADa/zUAAAADAAAAAADa/zYAAAADAAAAAADa/zcAAAADAAAAAADa/zgAAAADAAAAAADa/zkAAAADAAAAAADa/zoAAAADAAAAAADa/zsAAAADAAAAAADa/zwAAAADAAAAAADa/z0AAAADAAAAAADa/z4AAAADAAAAAADa/z8AAAADAAAAAADb/y0AAAADAAAAAADb/y4AAAADAAAAAADb/y8AAAADAAAAAADb/zAAAAADAAAAAADb/zEAAAADAAAAAADb/zIAAAADAAAAAADb/zMAAAADAAAAAADb/zQAAAADAAAAAADb/zUAAAADAAAAAADb/zYAAAADAAAAAADb/zcAAAADAAAAAADb/zgAAAADAAAAAADb/zkAAAADAAAAAADb/zoAAAADAAAAAADb/zsAAAADAAAAAADb/zwAAAADAAAAAADb/z0AAAADAAAAAADb/z4AAAADAAAAAADb/z8AAAADAAAAAADc/y0AAAADAAAAAADc/y4AAAADAAAAAADc/y8AAAADAAAAAADc/zAAAAADAAAAAADc/zEAAAADAAAAAADc/zIAAAADAAAAAADc/zMAAAADAAAAAADc/zQAAAADAAAAAADc/zUAAAADAAAAAADc/zYAAAADAAAAAADc/zcAAAADAAAAAADc/zgAAAADAAAAAADc/zkAAAADAAAAAADc/zoAAAADAAAAAADc/zsAAAADAAAAAADc/zwAAAADAAAAAADc/z0AAAADAAAAAADc/z4AAAADAAAAAADc/z8AAAADAAAAAADd/y0AAAADAAAAAADd/y4AAAADAAAAAADd/y8AAAADAAAAAADd/zAAAAADAAAAAADd/zEAAAADAAAAAADd/zIAAAADAAAAAADd/zMAAAADAAAAAADd/zQAAAADAAAAAADd/zUAAAADAAAAAADd/zYAAAADAAAAAADd/zcAAAADAAAAAADd/zgAAAADAAAAAADd/zkAAAADAAAAAADd/zoAAAADAAAAAADd/zsAAAADAAAAAADd/zwAAAADAAAAAADd/z0AAAADAAAAAADd/z4AAAADAAAAAADd/z8AAAADAAAAAACw/zUAAAADAAAAAACw/zYAAAADAAAAAACw/zcAAAADAAAAAACw/zgAAAADAAAAAACw/zkAAAADAAAAAACw/zoAAAADAAAAAACx/zUAAAADAAAAAACx/zYAAAADAAAAAACx/zcAAAADAAAAAACx/zgAAAADAAAAAACx/zkAAAADAAAAAACx/zoAAAADAAAAAACy/zUAAAADAAAAAACy/zYAAAADAAAAAACy/zcAAAADAAAAAACy/zgAAAADAAAAAACy/zkAAAADAAAAAACy/zoAAAADAAAAAACz/zUAAAADAAAAAACz/zYAAAADAAAAAACz/zcAAAADAAAAAACz/zgAAAADAAAAAACz/zkAAAADAAAAAACz/zoAAAADAAAAAAC0/zUAAAADAAAAAAC0/zYAAAADAAAAAAC0/zcAAAADAAAAAAC0/zgAAAADAAAAAAC0/zkAAAADAAAAAAC0/zoAAAADAAAAAAC1/zUAAAADAAAAAAC1/zYAAAADAAAAAAC1/zcAAAADAAAAAAC1/zgAAAADAAAAAAC1/zkAAAADAAAAAAC1/zoAAAADAAAAAAC2/zUAAAADAAAAAAC2/zYAAAADAAAAAAC2/zcAAAADAAAAAAC2/zgAAAADAAAAAAC2/zkAAAADAAAAAAC2/zoAAAADAAAAAAC3/zUAAAADAAAAAAC3/zYAAAADAAAAAAC3/zcAAAADAAAAAAC3/zgAAAADAAAAAAC3/zkAAAADAAAAAAC3/zoAAAADAAAAAAC4/zUAAAADAAAAAAC4/zYAAAADAAAAAAC4/zcAAAADAAAAAAC4/zgAAAADAAAAAAC4/zkAAAADAAAAAAC4/zoAAAADAAAAAAC5/zUAAAADAAAAAAC5/zYAAAADAAAAAAC5/zcAAAADAAAAAAC5/zgAAAADAAAAAAC5/zkAAAADAAAAAAC5/zoAAAADAAAAAAC6/zUAAAADAAAAAAC6/zYAAAADAAAAAAC6/zcAAAADAAAAAAC6/zgAAAADAAAAAAC6/zkAAAADAAAAAAC6/zoAAAADAAAAAAC7/zUAAAADAAAAAAC7/zYAAAADAAAAAAC7/zcAAAADAAAAAAC7/zgAAAADAAAAAAC7/zkAAAADAAAAAAC7/zoAAAADAAAAAAC8/zUAAAADAAAAAAC8/zYAAAADAAAAAAC8/zcAAAADAAAAAAC8/zgAAAADAAAAAAC8/zkAAAADAAAAAAC8/zoAAAADAAAAAAC9/zUAAAADAAAAAAC9/zYAAAADAAAAAAC9/zcAAAADAAAAAAC9/zgAAAADAAAAAAC9/zkAAAADAAAAAAC9/zoAAAADAAAAAAC+/zUAAAADAAAAAAC+/zYAAAADAAAAAAC+/zcAAAADAAAAAAC+/zgAAAADAAAAAAC+/zkAAAADAAAAAAC+/zoAAAADAAAAAAC//zUAAAADAAAAAAC//zYAAAADAAAAAAC//zcAAAADAAAAAAC//zgAAAADAAAAAAC//zkAAAADAAAAAAC//zoAAAADAAAAAADA/zUAAAADAAAAAADA/zYAAAADAAAAAADA/zcAAAADAAAAAADA/zgAAAADAAAAAADA/zkAAAADAAAAAADA/zoAAAADAAAAAADB/zUAAAADAAAAAADB/zYAAAADAAAAAADB/zcAAAADAAAAAADB/zgAAAADAAAAAADB/zkAAAADAAAAAADB/zoAAAADAAAAAADC/zUAAAADAAAAAADC/zYAAAADAAAAAADC/zcAAAADAAAAAADC/zgAAAADAAAAAADC/zkAAAADAAAAAADC/zoAAAADAAAAAADD/zUAAAADAAAAAADD/zYAAAADAAAAAADD/zcAAAADAAAAAADD/zgAAAADAAAAAADD/zkAAAADAAAAAADD/zoAAAADAAAAAADE/zUAAAADAAAAAADE/zYAAAADAAAAAADE/zcAAAADAAAAAADE/zgAAAADAAAAAADE/zkAAAADAAAAAADE/zoAAAADAAAAAADF/zUAAAADAAAAAADF/zYAAAADAAAAAADF/zcAAAADAAAAAADF/zgAAAADAAAAAADF/zkAAAADAAAAAADF/zoAAAADAAAAAADG/zUAAAADAAAAAADG/zYAAAADAAAAAADG/zcAAAADAAAAAADG/zgAAAADAAAAAADG/zkAAAADAAAAAADG/zoAAAADAAAAAADH/zUAAAADAAAAAADH/zYAAAADAAAAAADH/zcAAAADAAAAAADH/zgAAAADAAAAAADH/zkAAAADAAAAAADH/zoAAAADAAAAAADI/zUAAAADAAAAAADI/zYAAAADAAAAAADI/zcAAAADAAAAAADI/zgAAAADAAAAAADI/zkAAAADAAAAAADI/zoAAAADAAAAAADJ/zUAAAADAAAAAADJ/zYAAAADAAAAAADJ/zcAAAADAAAAAADJ/zgAAAADAAAAAADJ/zkAAAADAAAAAADJ/zoAAAADAAAAAADK/zUAAAADAAAAAADK/zYAAAADAAAAAADK/zcAAAADAAAAAADK/zgAAAADAAAAAADK/zkAAAADAAAAAADK/zoAAAADAAAAAADL/zUAAAADAAAAAADL/zYAAAADAAAAAADL/zcAAAADAAAAAADL/zgAAAADAAAAAADL/zkAAAADAAAAAADL/zoAAAADAAAAAADM/zUAAAADAAAAAADM/zYAAAADAAAAAADM/zcAAAADAAAAAADM/zgAAAADAAAAAADM/zkAAAADAAAAAADM/zoAAAADAAAAAADN/zUAAAADAAAAAADN/zYAAAADAAAAAADN/zcAAAADAAAAAADN/zgAAAADAAAAAADN/zkAAAADAAAAAADN/zoAAAADAAAAAADI/yQAAAADAAAAAADI/yUAAAADAAAAAADI/yYAAAADAAAAAADI/ycAAAADAAAAAADI/ygAAAADAAAAAADI/ykAAAADAAAAAADI/yoAAAADAAAAAADI/ysAAAADAAAAAADI/ywAAAADAAAAAADI/y0AAAADAAAAAADI/y4AAAADAAAAAADI/y8AAAADAAAAAADI/zAAAAADAAAAAADI/zEAAAADAAAAAADI/zIAAAADAAAAAADI/zMAAAADAAAAAADI/zQAAAADAAAAAADJ/yQAAAADAAAAAADJ/yUAAAADAAAAAADJ/yYAAAADAAAAAADJ/ycAAAADAAAAAADJ/ygAAAADAAAAAADJ/ykAAAADAAAAAADJ/yoAAAADAAAAAADJ/ysAAAADAAAAAADJ/ywAAAADAAAAAADJ/y0AAAADAAAAAADJ/y4AAAADAAAAAADJ/y8AAAADAAAAAADJ/zAAAAADAAAAAADJ/zEAAAADAAAAAADJ/zIAAAADAAAAAADJ/zMAAAADAAAAAADJ/zQAAAADAAAAAADK/yQAAAADAAAAAADK/yUAAAADAAAAAADK/yYAAAADAAAAAADK/ycAAAADAAAAAADK/ygAAAADAAAAAADK/ykAAAADAAAAAADK/yoAAAADAAAAAADK/ysAAAADAAAAAADK/ywAAAADAAAAAADK/y0AAAADAAAAAADK/y4AAAADAAAAAADK/y8AAAADAAAAAADK/zAAAAADAAAAAADK/zEAAAADAAAAAADK/zIAAAADAAAAAADK/zMAAAADAAAAAADK/zQAAAADAAAAAADL/yQAAAADAAAAAADL/yUAAAADAAAAAADL/yYAAAADAAAAAADL/ycAAAADAAAAAADL/ygAAAADAAAAAADL/ykAAAADAAAAAADL/yoAAAADAAAAAADL/ysAAAADAAAAAADL/ywAAAADAAAAAADL/y0AAAADAAAAAADL/y4AAAADAAAAAADL/y8AAAADAAAAAADL/zAAAAADAAAAAADL/zEAAAADAAAAAADL/zIAAAADAAAAAADL/zMAAAADAAAAAADL/zQAAAADAAAAAADM/yQAAAADAAAAAADM/yUAAAADAAAAAADM/yYAAAADAAAAAADM/ycAAAADAAAAAADM/ygAAAADAAAAAADM/ykAAAADAAAAAADM/yoAAAADAAAAAADM/ysAAAADAAAAAADM/ywAAAADAAAAAADM/y0AAAADAAAAAADM/y4AAAADAAAAAADM/y8AAAADAAAAAADM/zAAAAADAAAAAADM/zEAAAADAAAAAADM/zIAAAADAAAAAADM/zMAAAADAAAAAADM/zQAAAADAAAAAADN/yQAAAADAAAAAADN/yUAAAADAAAAAADN/yYAAAADAAAAAADN/ycAAAADAAAAAADN/ygAAAADAAAAAADN/ykAAAADAAAAAADN/yoAAAADAAAAAADN/ysAAAADAAAAAADN/ywAAAADAAAAAADN/y0AAAADAAAAAADN/y4AAAADAAAAAADN/y8AAAADAAAAAADN/zAAAAADAAAAAADN/zEAAAADAAAAAADN/zIAAAADAAAAAADN/zMAAAADAAAAAADN/zQAAAADAAAAAACr/yUAAAADAAAAAACr/yYAAAADAAAAAACr/ycAAAADAAAAAACr/ygAAAADAAAAAACr/ykAAAADAAAAAACr/yoAAAADAAAAAACs/yUAAAADAAAAAACs/yYAAAADAAAAAACs/ycAAAADAAAAAACs/ygAAAADAAAAAACs/ykAAAADAAAAAACs/yoAAAADAAAAAACt/yUAAAADAAAAAACt/yYAAAADAAAAAACt/ycAAAADAAAAAACt/ygAAAADAAAAAACt/ykAAAADAAAAAACt/yoAAAADAAAAAACu/yUAAAADAAAAAACu/yYAAAADAAAAAACu/ycAAAADAAAAAACu/ygAAAADAAAAAACu/ykAAAADAAAAAACu/yoAAAADAAAAAACv/yUAAAADAAAAAACv/yYAAAADAAAAAACv/ycAAAADAAAAAACv/ygAAAADAAAAAACv/ykAAAADAAAAAACv/yoAAAADAAAAAACw/yUAAAADAAAAAACw/yYAAAADAAAAAACw/ycAAAADAAAAAACw/ygAAAADAAAAAACw/ykAAAADAAAAAACw/yoAAAADAAAAAACx/yUAAAADAAAAAACx/yYAAAADAAAAAACx/ycAAAADAAAAAACx/ygAAAADAAAAAACx/ykAAAADAAAAAACx/yoAAAADAAAAAACy/yUAAAADAAAAAACy/yYAAAADAAAAAACy/ycAAAADAAAAAACy/ygAAAADAAAAAACy/ykAAAADAAAAAACy/yoAAAADAAAAAACz/yUAAAADAAAAAACz/yYAAAADAAAAAACz/ycAAAADAAAAAACz/ygAAAADAAAAAACz/ykAAAADAAAAAACz/yoAAAADAAAAAAC0/yUAAAADAAAAAAC0/yYAAAADAAAAAAC0/ycAAAADAAAAAAC0/ygAAAADAAAAAAC0/ykAAAADAAAAAAC0/yoAAAADAAAAAAC1/yUAAAADAAAAAAC1/yYAAAADAAAAAAC1/ycAAAADAAAAAAC1/ygAAAADAAAAAAC1/ykAAAADAAAAAAC1/yoAAAADAAAAAAC2/yUAAAADAAAAAAC2/yYAAAADAAAAAAC2/ycAAAADAAAAAAC2/ygAAAADAAAAAAC2/ykAAAADAAAAAAC2/yoAAAADAAAAAAC3/yUAAAADAAAAAAC3/yYAAAADAAAAAAC3/ycAAAADAAAAAAC3/ygAAAADAAAAAAC3/ykAAAADAAAAAAC3/yoAAAADAAAAAAC4/yUAAAADAAAAAAC4/yYAAAADAAAAAAC4/ycAAAADAAAAAAC4/ygAAAADAAAAAAC4/ykAAAADAAAAAAC4/yoAAAADAAAAAAC5/yUAAAADAAAAAAC5/yYAAAADAAAAAAC5/ycAAAADAAAAAAC5/ygAAAADAAAAAAC5/ykAAAADAAAAAAC5/yoAAAADAAAAAAC6/yUAAAADAAAAAAC6/yYAAAADAAAAAAC6/ycAAAADAAAAAAC6/ygAAAADAAAAAAC6/ykAAAADAAAAAAC6/yoAAAADAAAAAAC7/yUAAAADAAAAAAC7/yYAAAADAAAAAAC7/ycAAAADAAAAAAC7/ygAAAADAAAAAAC7/ykAAAADAAAAAAC7/yoAAAADAAAAAAC8/yUAAAADAAAAAAC8/yYAAAADAAAAAAC8/ycAAAADAAAAAAC8/ygAAAADAAAAAAC8/ykAAAADAAAAAAC8/yoAAAADAAAAAAC9/yUAAAADAAAAAAC9/yYAAAADAAAAAAC9/ycAAAADAAAAAAC9/ygAAAADAAAAAAC9/ykAAAADAAAAAAC9/yoAAAADAAAAAAA=\")\nplayer_id = 7\n\n[node name=\"GroundIndicatorMap\" type=\"TileMap\" parent=\".\"]\nvisible = false\ny_sort_enabled = true\ntile_set = SubResource(\"TileSet_dc62b\")\nformat = 2\nlayer_0/modulate = Color(1, 0, 1, 0.392157)\nlayer_0/y_sort_enabled = true\nlayer_0/z_index = 100\nlayer_0/tile_data = PackedInt32Array(-2359305, 1, 0, -2293769, 1, 0, -2228233, 1, 0, -2162697, 1, 0, -2097161, 1, 0, -2031625, 1, 0, -1966089, 1, 0, -2293770, 1, 0, -2228234, 1, 0, -2228235, 1, 0, -2162699, 1, 0, -2097163, 1, 0, -2031627, 1, 0, -1966091, 1, 0, -1900555, 1, 0, -1835019, 1, 0, -1769483, 1, 0, -1703947, 1, 0, -1638411, 1, 0, -1572875, 1, 0, -1507339, 1, 0, -1441803, 1, 0, -1376267, 1, 0, -1310731, 1, 0, -1245195, 1, 0, -1179659, 1, 0, -1114123, 1, 0, -1048587, 1, 0, -983051, 1, 0, -917515, 1, 0, -851979, 1, 0, -786443, 1, 0, -720907, 1, 0, -655371, 1, 0, -589835, 1, 0, -524299, 1, 0, -458763, 1, 0, -393227, 1, 0, -327691, 1, 0, -262155, 1, 0, -196619, 1, 0, -2162698, 1, 0, -2097162, 1, 0, -2031626, 1, 0, -1966090, 1, 0, -1900554, 1, 0, -1835018, 1, 0, -1769482, 1, 0, -1703946, 1, 0, -1638410, 1, 0, -1572874, 1, 0, -1507338, 1, 0, -1441802, 1, 0, -1376266, 1, 0, -1310730, 1, 0, -1245194, 1, 0, -1179658, 1, 0, -1114122, 1, 0, -1048586, 1, 0, -983050, 1, 0, -917514, 1, 0, -851978, 1, 0, -786442, 1, 0, -720906, 1, 0, -655370, 1, 0, -589834, 1, 0, -524298, 1, 0, -458762, 1, 0, -393226, 1, 0, -327690, 1, 0, -262154, 1, 0, -196618, 1, 0, -1900553, 1, 0, -1835017, 1, 0, -1769481, 1, 0, -1703945, 1, 0, -1638409, 1, 0, -1572873, 1, 0, -1507337, 1, 0, -1441801, 1, 0, -1376265, 1, 0, -1310729, 1, 0, -1245193, 1, 0, -1179657, 1, 0, -1114121, 1, 0, -1048585, 1, 0, -983049, 1, 0, -917513, 1, 0, -851977, 1, 0, -786441, 1, 0, -720905, 1, 0, -655369, 1, 0, -589833, 1, 0, -524297, 1, 0, -458761, 1, 0, -393225, 1, 0, -327689, 1, 0, -262153, 1, 0, -196617, 1, 0, -327688, 1, 0, -262152, 1, 0, -196616, 1, 0, -327687, 1, 0, -262151, 1, 0, -196615, 1, 0, -327686, 1, 0, -262150, 1, 0, -196614, 1, 0, -327685, 1, 0, -262149, 1, 0, -196613, 1, 0, -327684, 1, 0, -262148, 1, 0, -196612, 1, 0, -327683, 1, 0, -262147, 1, 0, -196611, 1, 0, -327682, 1, 0, -262146, 1, 0, -196610, 1, 0, -327681, 1, 0, -262145, 1, 0, -196609, 1, 0, -1179651, 1, 0, -1114115, 1, 0, -1048579, 1, 0, -983043, 1, 0, -917507, 1, 0, -851971, 1, 0, -786435, 1, 0, -720899, 1, 0, -655363, 1, 0, -589827, 1, 0, -524291, 1, 0, -458755, 1, 0, -393219, 1, 0, -1179650, 1, 0, -1114114, 1, 0, -1048578, 1, 0, -983042, 1, 0, -917506, 1, 0, -851970, 1, 0, -786434, 1, 0, -720898, 1, 0, -655362, 1, 0, -589826, 1, 0, -524290, 1, 0, -458754, 1, 0, -393218, 1, 0, -1179649, 1, 0, -1114113, 1, 0, -1048577, 1, 0, -983041, 1, 0, -917505, 1, 0, -851969, 1, 0, -786433, 1, 0, -720897, 1, 0, -655361, 1, 0, -589825, 1, 0, -524289, 1, 0, -458753, 1, 0, -393217, 1, 0, -1245184, 1, 0, -1179648, 1, 0, -1114112, 1, 0, -1245183, 1, 0, -1179647, 1, 0, -1114111, 1, 0, -1245182, 1, 0, -1179646, 1, 0, -1114110, 1, 0, -1245181, 1, 0, -1179645, 1, 0, -1114109, 1, 0, -1245180, 1, 0, -1179644, 1, 0, -1114108, 1, 0, -1245179, 1, 0, -1179643, 1, 0, -1114107, 1, 0, -1245178, 1, 0, -1179642, 1, 0, -1114106, 1, 0, -1245177, 1, 0, -1179641, 1, 0, -1114105, 1, 0, -1048571, 1, 0, -983035, 1, 0, -917499, 1, 0, -851963, 1, 0, -786427, 1, 0, -720891, 1, 0, -655355, 1, 0, -589819, 1, 0, -524283, 1, 0, -458747, 1, 0, -393211, 1, 0, -327675, 1, 0, -262139, 1, 0, -196603, 1, 0, -131067, 1, 0, -65531, 1, 0, -1048570, 1, 0, -983034, 1, 0, -917498, 1, 0, -851962, 1, 0, -786426, 1, 0, -720890, 1, 0, -655354, 1, 0, -589818, 1, 0, -524282, 1, 0, -458746, 1, 0, -393210, 1, 0, -327674, 1, 0, -262138, 1, 0, -196602, 1, 0, -131066, 1, 0, -65530, 1, 0, -1048569, 1, 0, -983033, 1, 0, -917497, 1, 0, -851961, 1, 0, -786425, 1, 0, -720889, 1, 0, -655353, 1, 0, -589817, 1, 0, -524281, 1, 0, -458745, 1, 0, -393209, 1, 0, -327673, 1, 0, -262137, 1, 0, -196601, 1, 0, -131065, 1, 0, -65529, 1, 0, 5, 1, 0, 65541, 1, 0, 131077, 1, 0, 196613, 1, 0, 262149, 1, 0, 6, 1, 0, 65542, 1, 0, 131078, 1, 0, 196614, 1, 0, 262150, 1, 0, 7, 1, 0, 65543, 1, 0, 131079, 1, 0, 196615, 1, 0, 262151, 1, 0, 262137, 1, 0, 327673, 1, 0, 262138, 1, 0, 327674, 1, 0, 262139, 1, 0, 327675, 1, 0, 262140, 1, 0, 327676, 1, 0, 262141, 1, 0, 327677, 1, 0, 262142, 1, 0, 327678, 1, 0, 262143, 1, 0, 327679, 1, 0, 196608, 1, 0, 262144, 1, 0, 196609, 1, 0, 262145, 1, 0, 196610, 1, 0, 262146, 1, 0, 196611, 1, 0, 262147, 1, 0, 196612, 1, 0, 262148, 1, 0, 196601, 1, 0, 196602, 1, 0, 196603, 1, 0, 196604, 1, 0, 196605, 1, 0, 196606, 1, 0, 196607, 1, 0, 131072, 1, 0, 131073, 1, 0, 131074, 1, 0, 131075, 1, 0, 131076, 1, 0, 393209, 1, 0, 458745, 1, 0, 524281, 1, 0, 589817, 1, 0, 655353, 1, 0, 720889, 1, 0, 786425, 1, 0, 851961, 1, 0, 393210, 1, 0, 458746, 1, 0, 524282, 1, 0, 589818, 1, 0, 655354, 1, 0, 720890, 1, 0, 786426, 1, 0, 851962, 1, 0, 393211, 1, 0, 458747, 1, 0, 524283, 1, 0, 589819, 1, 0, 655355, 1, 0, 720891, 1, 0, 786427, 1, 0, 851963, 1, 0, 720892, 1, 0, 786428, 1, 0, 851964, 1, 0, 720893, 1, 0, 786429, 1, 0, 851965, 1, 0, 720894, 1, 0, 786430, 1, 0, 851966, 1, 0, 720895, 1, 0, 786431, 1, 0, 851967, 1, 0, 655360, 1, 0, 720896, 1, 0, 786432, 1, 0, 655361, 1, 0, 720897, 1, 0, 786433, 1, 0, 655362, 1, 0, 720898, 1, 0, 786434, 1, 0, 655363, 1, 0, 720899, 1, 0, 786435, 1, 0, 655364, 1, 0, 720900, 1, 0, 786436, 1, 0, 655365, 1, 0, 720901, 1, 0, 786437, 1, 0, 655366, 1, 0, 720902, 1, 0, 786438, 1, 0, 655367, 1, 0, 720903, 1, 0, 786439, 1, 0, 851973, 1, 0, 917509, 1, 0, 983045, 1, 0, 1048581, 1, 0, 1114117, 1, 0, 1179653, 1, 0, 1245189, 1, 0, 1310725, 1, 0, 1376261, 1, 0, 1441797, 1, 0, 1507333, 1, 0, 1572869, 1, 0, 1638405, 1, 0, 1703941, 1, 0, 1769477, 1, 0, 1835013, 1, 0, 1900549, 1, 0, 1966085, 1, 0, 2031621, 1, 0, 2097157, 1, 0, 2162693, 1, 0, 2228229, 1, 0, 2293765, 1, 0, 2359301, 1, 0, 2424837, 1, 0, 851974, 1, 0, 917510, 1, 0, 983046, 1, 0, 1048582, 1, 0, 1114118, 1, 0, 1179654, 1, 0, 1245190, 1, 0, 1310726, 1, 0, 1376262, 1, 0, 1441798, 1, 0, 1507334, 1, 0, 1572870, 1, 0, 1638406, 1, 0, 1703942, 1, 0, 1769478, 1, 0, 1835014, 1, 0, 1900550, 1, 0, 1966086, 1, 0, 2031622, 1, 0, 2097158, 1, 0, 2162694, 1, 0, 2228230, 1, 0, 2293766, 1, 0, 2359302, 1, 0, 2424838, 1, 0, 851975, 1, 0, 917511, 1, 0, 983047, 1, 0, 1048583, 1, 0, 1114119, 1, 0, 1179655, 1, 0, 1245191, 1, 0, 1310727, 1, 0, 1376263, 1, 0, 1441799, 1, 0, 1507335, 1, 0, 1572871, 1, 0, 1638407, 1, 0, 1703943, 1, 0, 1769479, 1, 0, 1835015, 1, 0, 1900551, 1, 0, 1966087, 1, 0, 2031623, 1, 0, 2097159, 1, 0, 2162695, 1, 0, 2228231, 1, 0, 2293767, 1, 0, 2359303, 1, 0, 2424839, 1, 0, -1245176, 1, 0, -1179640, 1, 0, -1114104, 1, 0, -1245175, 1, 0, -1179639, 1, 0, -1114103, 1, 0, -1245174, 1, 0, -1179638, 1, 0, -1114102, 1, 0, -1245173, 1, 0, -1179637, 1, 0, -1114101, 1, 0, -1245172, 1, 0, -1179636, 1, 0, -1114100, 1, 0, -1245171, 1, 0, -1179635, 1, 0, -1114099, 1, 0, -1245170, 1, 0, -1179634, 1, 0, -1114098, 1, 0, -1245169, 1, 0, -1179633, 1, 0, -1114097, 1, 0, -1048563, 1, 0, -983027, 1, 0, -917491, 1, 0, -851955, 1, 0, -786419, 1, 0, -720883, 1, 0, -655347, 1, 0, -589811, 1, 0, -524275, 1, 0, -458739, 1, 0, -393203, 1, 0, -327667, 1, 0, -262131, 1, 0, -1048562, 1, 0, -983026, 1, 0, -917490, 1, 0, -851954, 1, 0, -786418, 1, 0, -720882, 1, 0, -655346, 1, 0, -589810, 1, 0, -524274, 1, 0, -458738, 1, 0, -393202, 1, 0, -327666, 1, 0, -262130, 1, 0, -1048561, 1, 0, -983025, 1, 0, -917489, 1, 0, -851953, 1, 0, -786417, 1, 0, -720881, 1, 0, -655345, 1, 0, -589809, 1, 0, -524273, 1, 0, -458737, 1, 0, -393201, 1, 0, -327665, 1, 0, -262129, 1, 0, -393200, 1, 0, -327664, 1, 0, -262128, 1, 0, -393199, 1, 0, -327663, 1, 0, -262127, 1, 0, -393198, 1, 0, -327662, 1, 0, -262126, 1, 0, -393197, 1, 0, -327661, 1, 0, -262125, 1, 0, -393196, 1, 0, -327660, 1, 0, -262124, 1, 0, -458731, 1, 0, -393195, 1, 0, -327659, 1, 0, -262123, 1, 0, -458730, 1, 0, -393194, 1, 0, -327658, 1, 0, -262122, 1, 0, -458729, 1, 0, -393193, 1, 0, -327657, 1, 0, -262121, 1, 0, -1638379, 1, 0, -1572843, 1, 0, -1507307, 1, 0, -1441771, 1, 0, -1376235, 1, 0, -1310699, 1, 0, -1245163, 1, 0, -1179627, 1, 0, -1114091, 1, 0, -1048555, 1, 0, -983019, 1, 0, -917483, 1, 0, -851947, 1, 0, -786411, 1, 0, -720875, 1, 0, -655339, 1, 0, -589803, 1, 0, -524267, 1, 0, -1638378, 1, 0, -1572842, 1, 0, -1507306, 1, 0, -1441770, 1, 0, -1376234, 1, 0, -1310698, 1, 0, -1245162, 1, 0, -1179626, 1, 0, -1114090, 1, 0, -1048554, 1, 0, -983018, 1, 0, -917482, 1, 0, -851946, 1, 0, -786410, 1, 0, -720874, 1, 0, -655338, 1, 0, -589802, 1, 0, -524266, 1, 0, -1638377, 1, 0, -1572841, 1, 0, -1507305, 1, 0, -1441769, 1, 0, -1376233, 1, 0, -1310697, 1, 0, -1245161, 1, 0, -1179625, 1, 0, -1114089, 1, 0, -1048553, 1, 0, -983017, 1, 0, -917481, 1, 0, -851945, 1, 0, -786409, 1, 0, -720873, 1, 0, -655337, 1, 0, -589801, 1, 0, -524265, 1, 0, -2424811, 1, 0, -2359275, 1, 0, -2293739, 1, 0, -2228203, 1, 0, -2162667, 1, 0, -2097131, 1, 0, -2031595, 1, 0, -1966059, 1, 0, -1900523, 1, 0, -1834987, 1, 0, -1769451, 1, 0, -1703915, 1, 0, -2424810, 1, 0, -2359274, 1, 0, -2293738, 1, 0, -2228202, 1, 0, -2162666, 1, 0, -2097130, 1, 0, -2031594, 1, 0, -1966058, 1, 0, -1900522, 1, 0, -1834986, 1, 0, -1769450, 1, 0, -1703914, 1, 0, -2424809, 1, 0, -2359273, 1, 0, -2293737, 1, 0, -2228201, 1, 0, -2162665, 1, 0, -2097129, 1, 0, -2031593, 1, 0, -1966057, 1, 0, -1900521, 1, 0, -1834985, 1, 0, -1769449, 1, 0, -1703913, 1, 0, -2490347, 1, 0, -2490346, 1, 0, -2490345, 1, 0, 131080, 1, 0, 196616, 1, 0, 262152, 1, 0, 131081, 1, 0, 196617, 1, 0, 262153, 1, 0, 131082, 1, 0, 196618, 1, 0, 262154, 1, 0, 131083, 1, 0, 196619, 1, 0, 262155, 1, 0, 131084, 1, 0, 196620, 1, 0, 262156, 1, 0, 131085, 1, 0, 196621, 1, 0, 262157, 1, 0, 131086, 1, 0, 196622, 1, 0, 262158, 1, 0, 131087, 1, 0, 196623, 1, 0, 262159, 1, 0, 131088, 1, 0, 196624, 1, 0, 262160, 1, 0, 131089, 1, 0, 196625, 1, 0, 262161, 1, 0, 131090, 1, 0, 196626, 1, 0, 262162, 1, 0, 131091, 1, 0, 196627, 1, 0, 262163, 1, 0, 655376, 1, 0, 720912, 1, 0, 786448, 1, 0, 327697, 1, 0, 393233, 1, 0, 458769, 1, 0, 524305, 1, 0, 589841, 1, 0, 655377, 1, 0, 720913, 1, 0, 786449, 1, 0, 327698, 1, 0, 393234, 1, 0, 458770, 1, 0, 524306, 1, 0, 589842, 1, 0, 655378, 1, 0, 720914, 1, 0, 786450, 1, 0, 327699, 1, 0, 393235, 1, 0, 458771, 1, 0, 524307, 1, 0, 589843, 1, 0, 655379, 1, 0, 720915, 1, 0, 786451, 1, 0, 655368, 1, 0, 720904, 1, 0, 786440, 1, 0, 655369, 1, 0, 720905, 1, 0, 786441, 1, 0, 655370, 1, 0, 720906, 1, 0, 786442, 1, 0, 655371, 1, 0, 720907, 1, 0, 786443, 1, 0, 655372, 1, 0, 720908, 1, 0, 786444, 1, 0, 655373, 1, 0, 720909, 1, 0, 786445, 1, 0, 655374, 1, 0, 720910, 1, 0, 786446, 1, 0, 655375, 1, 0, 720911, 1, 0, 786447, 1, 0, 2031624, 1, 0, 2097160, 1, 0, 2162696, 1, 0, 2031625, 1, 0, 2097161, 1, 0, 2162697, 1, 0, 2031626, 1, 0, 2097162, 1, 0, 2162698, 1, 0, 2031627, 1, 0, 2097163, 1, 0, 2162699, 1, 0, 2031628, 1, 0, 2097164, 1, 0, 2162700, 1, 0, 2031629, 1, 0, 2097165, 1, 0, 2162701, 1, 0, 2031630, 1, 0, 2097166, 1, 0, 2162702, 1, 0, 2031631, 1, 0, 2097167, 1, 0, 2162703, 1, 0, 2031632, 1, 0, 2097168, 1, 0, 2162704, 1, 0, 2031633, 1, 0, 2097169, 1, 0, 2162705, 1, 0, 2031634, 1, 0, 2097170, 1, 0, 2162706, 1, 0, 2031635, 1, 0, 2097171, 1, 0, 2162707, 1, 0, 2031636, 1, 0, 2097172, 1, 0, 2162708, 1, 0, 2031637, 1, 0, 2097173, 1, 0, 2162709, 1, 0, 2031638, 1, 0, 2097174, 1, 0, 2162710, 1, 0, 2031639, 1, 0, 2097175, 1, 0, 2162711, 1, 0, 2031640, 1, 0, 2097176, 1, 0, 2162712, 1, 0, 2031641, 1, 0, 2097177, 1, 0, 2162713, 1, 0, 2031642, 1, 0, 2097178, 1, 0, 2162714, 1, 0, 2031643, 1, 0, 2097179, 1, 0, 2162715, 1, 0, 2031644, 1, 0, 2097180, 1, 0, 2162716, 1, 0, 1245210, 1, 0, 1310746, 1, 0, 1376282, 1, 0, 1441818, 1, 0, 1507354, 1, 0, 1572890, 1, 0, 1638426, 1, 0, 1703962, 1, 0, 1769498, 1, 0, 1835034, 1, 0, 1900570, 1, 0, 1966106, 1, 0, 1245211, 1, 0, 1310747, 1, 0, 1376283, 1, 0, 1441819, 1, 0, 1507355, 1, 0, 1572891, 1, 0, 1638427, 1, 0, 1703963, 1, 0, 1769499, 1, 0, 1835035, 1, 0, 1900571, 1, 0, 1966107, 1, 0, 1245212, 1, 0, 1310748, 1, 0, 1376284, 1, 0, 1441820, 1, 0, 1507356, 1, 0, 1572892, 1, 0, 1638428, 1, 0, 1703964, 1, 0, 1769500, 1, 0, 1835036, 1, 0, 1900572, 1, 0, 1966108, 1, 0, 1245213, 1, 0, 1310749, 1, 0, 1376285, 1, 0, 1245214, 1, 0, 1310750, 1, 0, 1376286, 1, 0, 1245215, 1, 0, 1310751, 1, 0, 1376287, 1, 0, 1245216, 1, 0, 1310752, 1, 0, 1376288, 1, 0, 1245217, 1, 0, 1310753, 1, 0, 1376289, 1, 0, 1245218, 1, 0, 1310754, 1, 0, 1376290, 1, 0, 1245219, 1, 0, 1310755, 1, 0, 1376291, 1, 0, 1245220, 1, 0, 1310756, 1, 0, 1376292, 1, 0, 2228250, 1, 0, 2293786, 1, 0, 2359322, 1, 0, 2424858, 1, 0, 2490394, 1, 0, 2555930, 1, 0, 2621466, 1, 0, 2687002, 1, 0, 2752538, 1, 0, 2818074, 1, 0, 2883610, 1, 0, 2949146, 1, 0, 2228251, 1, 0, 2293787, 1, 0, 2359323, 1, 0, 2424859, 1, 0, 2490395, 1, 0, 2555931, 1, 0, 2621467, 1, 0, 2687003, 1, 0, 2752539, 1, 0, 2818075, 1, 0, 2883611, 1, 0, 2949147, 1, 0, 2228252, 1, 0, 2293788, 1, 0, 2359324, 1, 0, 2424860, 1, 0, 2490396, 1, 0, 2555932, 1, 0, 2621468, 1, 0, 2687004, 1, 0, 2752540, 1, 0, 2818076, 1, 0, 2883612, 1, 0, 2949148, 1, 0, 2818077, 1, 0, 2883613, 1, 0, 2949149, 1, 0, 2818078, 1, 0, 2883614, 1, 0, 2949150, 1, 0, 2818079, 1, 0, 2883615, 1, 0, 2949151, 1, 0, 2818080, 1, 0, 2883616, 1, 0, 2949152, 1, 0, 2818081, 1, 0, 2883617, 1, 0, 2949153, 1, 0, 2818082, 1, 0, 2883618, 1, 0, 2949154, 1, 0, 2818083, 1, 0, 2883619, 1, 0, 2949155, 1, 0, 2818084, 1, 0, 2883620, 1, 0, 2949156, 1, 0, 1441826, 1, 0, 1507362, 1, 0, 1572898, 1, 0, 1638434, 1, 0, 1703970, 1, 0, 1769506, 1, 0, 1835042, 1, 0, 1900578, 1, 0, 1966114, 1, 0, 2031650, 1, 0, 2097186, 1, 0, 2162722, 1, 0, 2228258, 1, 0, 2293794, 1, 0, 2359330, 1, 0, 2424866, 1, 0, 2490402, 1, 0, 2555938, 1, 0, 2621474, 1, 0, 2687010, 1, 0, 2752546, 1, 0, 1441827, 1, 0, 1507363, 1, 0, 1572899, 1, 0, 1638435, 1, 0, 1703971, 1, 0, 1769507, 1, 0, 1835043, 1, 0, 1900579, 1, 0, 1966115, 1, 0, 2031651, 1, 0, 2097187, 1, 0, 2162723, 1, 0, 2228259, 1, 0, 2293795, 1, 0, 2359331, 1, 0, 2424867, 1, 0, 2490403, 1, 0, 2555939, 1, 0, 2621475, 1, 0, 2687011, 1, 0, 2752547, 1, 0, 1441828, 1, 0, 1507364, 1, 0, 1572900, 1, 0, 1638436, 1, 0, 1703972, 1, 0, 1769508, 1, 0, 1835044, 1, 0, 1900580, 1, 0, 1966116, 1, 0, 2031652, 1, 0, 2097188, 1, 0, 2162724, 1, 0, 2228260, 1, 0, 2293796, 1, 0, 2359332, 1, 0, 2424868, 1, 0, 2490404, 1, 0, 2555940, 1, 0, 2621476, 1, 0, 2687012, 1, 0, 2752548, 1, 0, 2031653, 1, 0, 2097189, 1, 0, 2162725, 1, 0, 2031654, 1, 0, 2097190, 1, 0, 2162726, 1, 0, 2031655, 1, 0, 2097191, 1, 0, 2162727, 1, 0, 2031656, 1, 0, 2097192, 1, 0, 2162728, 1, 0, 2031657, 1, 0, 2097193, 1, 0, 2162729, 1, 0, 2031658, 1, 0, 2097194, 1, 0, 2162730, 1, 0, 2031659, 1, 0, 2097195, 1, 0, 2162731, 1, 0, 2031660, 1, 0, 2097196, 1, 0, 2162732, 1, 0, 2031661, 1, 0, 2097197, 1, 0, 2162733, 1, 0, 2031662, 1, 0, 2097198, 1, 0, 2162734, 1, 0, 2031663, 1, 0, 2097199, 1, 0, 2162735, 1, 0, 2031664, 1, 0, 2097200, 1, 0, 2162736, 1, 0, 2031665, 1, 0, 2097201, 1, 0, 2162737, 1, 0, 2031666, 1, 0, 2097202, 1, 0, 2162738, 1, 0, 2031667, 1, 0, 2097203, 1, 0, 2162739, 1, 0, 2031668, 1, 0, 2097204, 1, 0, 2162740, 1, 0, 2031669, 1, 0, 2097205, 1, 0, 2162741, 1, 0, 2031670, 1, 0, 2097206, 1, 0, 2162742, 1, 0, 2031671, 1, 0, 2097207, 1, 0, 2162743, 1, 0, 2031672, 1, 0, 2097208, 1, 0, 2162744, 1, 0, 1507382, 1, 0, 1572918, 1, 0, 1638454, 1, 0, 1703990, 1, 0, 1769526, 1, 0, 1835062, 1, 0, 1900598, 1, 0, 1966134, 1, 0, 1507383, 1, 0, 1572919, 1, 0, 1638455, 1, 0, 1703991, 1, 0, 1769527, 1, 0, 1835063, 1, 0, 1900599, 1, 0, 1966135, 1, 0, 1507384, 1, 0, 1572920, 1, 0, 1638456, 1, 0, 1703992, 1, 0, 1769528, 1, 0, 1835064, 1, 0, 1900600, 1, 0, 1966136, 1, 0, 1507370, 1, 0, 1572906, 1, 0, 1638442, 1, 0, 1507371, 1, 0, 1572907, 1, 0, 1638443, 1, 0, 1507372, 1, 0, 1572908, 1, 0, 1638444, 1, 0, 1507373, 1, 0, 1572909, 1, 0, 1638445, 1, 0, 1507374, 1, 0, 1572910, 1, 0, 1638446, 1, 0, 1507375, 1, 0, 1572911, 1, 0, 1638447, 1, 0, 1507376, 1, 0, 1572912, 1, 0, 1638448, 1, 0, 1507377, 1, 0, 1572913, 1, 0, 1638449, 1, 0, 1507378, 1, 0, 1572914, 1, 0, 1638450, 1, 0, 1507379, 1, 0, 1572915, 1, 0, 1638451, 1, 0, 1507380, 1, 0, 1572916, 1, 0, 1638452, 1, 0, 1507381, 1, 0, 1572917, 1, 0, 1638453, 1, 0, 983082, 1, 0, 1048618, 1, 0, 1114154, 1, 0, 1179690, 1, 0, 1245226, 1, 0, 1310762, 1, 0, 1376298, 1, 0, 1441834, 1, 0, 983083, 1, 0, 1048619, 1, 0, 1114155, 1, 0, 1179691, 1, 0, 1245227, 1, 0, 1310763, 1, 0, 1376299, 1, 0, 1441835, 1, 0, 983084, 1, 0, 1048620, 1, 0, 1114156, 1, 0, 1179692, 1, 0, 1245228, 1, 0, 1310764, 1, 0, 1376300, 1, 0, 1441836, 1, 0, 983085, 1, 0, 1048621, 1, 0, 1114157, 1, 0, 983086, 1, 0, 1048622, 1, 0, 1114158, 1, 0, 983087, 1, 0, 1048623, 1, 0, 1114159, 1, 0, 983088, 1, 0, 1048624, 1, 0, 1114160, 1, 0, 983089, 1, 0, 1048625, 1, 0, 1114161, 1, 0, 983090, 1, 0, 1048626, 1, 0, 1114162, 1, 0, 983091, 1, 0, 1048627, 1, 0, 1114163, 1, 0, 983092, 1, 0, 1048628, 1, 0, 1114164, 1, 0, 983093, 1, 0, 1048629, 1, 0, 1114165, 1, 0, 983094, 1, 0, 1048630, 1, 0, 1114166, 1, 0, 983095, 1, 0, 1048631, 1, 0, 1114167, 1, 0, 983096, 1, 0, 1048632, 1, 0, 1114168, 1, 0, 983097, 1, 0, 1048633, 1, 0, 1114169, 1, 0, 983098, 1, 0, 1048634, 1, 0, 1114170, 1, 0, 983099, 1, 0, 1048635, 1, 0, 1114171, 1, 0, 983100, 1, 0, 1048636, 1, 0, 1114172, 1, 0, 983101, 1, 0, 1048637, 1, 0, 1114173, 1, 0, 983102, 1, 0, 1048638, 1, 0, 1114174, 1, 0, 983103, 1, 0, 1048639, 1, 0, 1114175, 1, 0, 983104, 1, 0, 1048640, 1, 0, 1114176, 1, 0, 983105, 1, 0, 1048641, 1, 0, 1114177, 1, 0, 983106, 1, 0, 1048642, 1, 0, 1114178, 1, 0, 983107, 1, 0, 1048643, 1, 0, 1114179, 1, 0, 983108, 1, 0, 1048644, 1, 0, 1114180, 1, 0, 983109, 1, 0, 1048645, 1, 0, 1114181, 1, 0, 983110, 1, 0, 1048646, 1, 0, 1114182, 1, 0, 983111, 1, 0, 1048647, 1, 0, 1114183, 1, 0, 2228278, 1, 0, 2293814, 1, 0, 2359350, 1, 0, 2424886, 1, 0, 2490422, 1, 0, 2555958, 1, 0, 2621494, 1, 0, 2687030, 1, 0, 2228279, 1, 0, 2293815, 1, 0, 2359351, 1, 0, 2424887, 1, 0, 2490423, 1, 0, 2555959, 1, 0, 2621495, 1, 0, 2687031, 1, 0, 2228280, 1, 0, 2293816, 1, 0, 2359352, 1, 0, 2424888, 1, 0, 2490424, 1, 0, 2555960, 1, 0, 2621496, 1, 0, 2687032, 1, 0, 2555946, 1, 0, 2621482, 1, 0, 2687018, 1, 0, 2555947, 1, 0, 2621483, 1, 0, 2687019, 1, 0, 2555948, 1, 0, 2621484, 1, 0, 2687020, 1, 0, 2555949, 1, 0, 2621485, 1, 0, 2687021, 1, 0, 2555950, 1, 0, 2621486, 1, 0, 2687022, 1, 0, 2555951, 1, 0, 2621487, 1, 0, 2687023, 1, 0, 2555952, 1, 0, 2621488, 1, 0, 2687024, 1, 0, 2555953, 1, 0, 2621489, 1, 0, 2687025, 1, 0, 2555954, 1, 0, 2621490, 1, 0, 2687026, 1, 0, 2555955, 1, 0, 2621491, 1, 0, 2687027, 1, 0, 2555956, 1, 0, 2621492, 1, 0, 2687028, 1, 0, 2555957, 1, 0, 2621493, 1, 0, 2687029, 1, 0, 2752554, 1, 0, 2818090, 1, 0, 2883626, 1, 0, 2949162, 1, 0, 3014698, 1, 0, 3080234, 1, 0, 3145770, 1, 0, 3211306, 1, 0, 2752555, 1, 0, 2818091, 1, 0, 2883627, 1, 0, 2949163, 1, 0, 3014699, 1, 0, 3080235, 1, 0, 3145771, 1, 0, 3211307, 1, 0, 2752556, 1, 0, 2818092, 1, 0, 2883628, 1, 0, 2949164, 1, 0, 3014700, 1, 0, 3080236, 1, 0, 3145772, 1, 0, 3211308, 1, 0, 3080237, 1, 0, 3145773, 1, 0, 3211309, 1, 0, 3080238, 1, 0, 3145774, 1, 0, 3211310, 1, 0, 3080239, 1, 0, 3145775, 1, 0, 3211311, 1, 0, 3080240, 1, 0, 3145776, 1, 0, 3211312, 1, 0, 3080241, 1, 0, 3145777, 1, 0, 3211313, 1, 0, 3080242, 1, 0, 3145778, 1, 0, 3211314, 1, 0, 3080243, 1, 0, 3145779, 1, 0, 3211315, 1, 0, 3080244, 1, 0, 3145780, 1, 0, 3211316, 1, 0, 3080245, 1, 0, 3145781, 1, 0, 3211317, 1, 0, 3080246, 1, 0, 3145782, 1, 0, 3211318, 1, 0, 3080247, 1, 0, 3145783, 1, 0, 3211319, 1, 0, 3080248, 1, 0, 3145784, 1, 0, 3211320, 1, 0, 3080249, 1, 0, 3145785, 1, 0, 3211321, 1, 0, 3080250, 1, 0, 3145786, 1, 0, 3211322, 1, 0, 3080251, 1, 0, 3145787, 1, 0, 3211323, 1, 0, 3080252, 1, 0, 3145788, 1, 0, 3211324, 1, 0, 3080253, 1, 0, 3145789, 1, 0, 3211325, 1, 0, 3080254, 1, 0, 3145790, 1, 0, 3211326, 1, 0, 3080255, 1, 0, 3145791, 1, 0, 3211327, 1, 0, 3080256, 1, 0, 3145792, 1, 0, 3211328, 1, 0, 3080257, 1, 0, 3145793, 1, 0, 3211329, 1, 0, 3080258, 1, 0, 3145794, 1, 0, 3211330, 1, 0, 3080259, 1, 0, 3145795, 1, 0, 3211331, 1, 0, 3080260, 1, 0, 3145796, 1, 0, 3211332, 1, 0, 3080261, 1, 0, 3145797, 1, 0, 3211333, 1, 0, 3080262, 1, 0, 3145798, 1, 0, 3211334, 1, 0, 3080263, 1, 0, 3145799, 1, 0, 3211335, 1, 0, 3080264, 1, 0, 3145800, 1, 0, 3211336, 1, 0, 3080265, 1, 0, 3145801, 1, 0, 3211337, 1, 0, 2490373, 1, 0, 2555909, 1, 0, 2621445, 1, 0, 2686981, 1, 0, 2752517, 1, 0, 2818053, 1, 0, 2883589, 1, 0, 2949125, 1, 0, 3014661, 1, 0, 3080197, 1, 0, 3145733, 1, 0, 3211269, 1, 0, 3276805, 1, 0, 3342341, 1, 0, 3407877, 1, 0, 3473413, 1, 0, 3538949, 1, 0, 2490374, 1, 0, 2555910, 1, 0, 2621446, 1, 0, 2686982, 1, 0, 2752518, 1, 0, 2818054, 1, 0, 2883590, 1, 0, 2949126, 1, 0, 3014662, 1, 0, 3080198, 1, 0, 3145734, 1, 0, 3211270, 1, 0, 3276806, 1, 0, 3342342, 1, 0, 3407878, 1, 0, 3473414, 1, 0, 3538950, 1, 0, 2490375, 1, 0, 2555911, 1, 0, 2621447, 1, 0, 2686983, 1, 0, 2752519, 1, 0, 2818055, 1, 0, 2883591, 1, 0, 2949127, 1, 0, 3014663, 1, 0, 3080199, 1, 0, 3145735, 1, 0, 3211271, 1, 0, 3276807, 1, 0, 3342343, 1, 0, 3407879, 1, 0, 3473415, 1, 0, 3538951, 1, 0, 3473401, 1, 0, 3538937, 1, 0, 3604473, 1, 0, 3473402, 1, 0, 3538938, 1, 0, 3604474, 1, 0, 3473403, 1, 0, 3538939, 1, 0, 3604475, 1, 0, 3473404, 1, 0, 3538940, 1, 0, 3604476, 1, 0, 3473405, 1, 0, 3538941, 1, 0, 3604477, 1, 0, 3473406, 1, 0, 3538942, 1, 0, 3604478, 1, 0, 3473407, 1, 0, 3538943, 1, 0, 3604479, 1, 0, 3407872, 1, 0, 3473408, 1, 0, 3538944, 1, 0, 3407873, 1, 0, 3473409, 1, 0, 3538945, 1, 0, 3407874, 1, 0, 3473410, 1, 0, 3538946, 1, 0, 3407875, 1, 0, 3473411, 1, 0, 3538947, 1, 0, 3407876, 1, 0, 3473412, 1, 0, 3538948, 1, 0, 3670009, 1, 0, 3735545, 1, 0, 3801081, 1, 0, 3866617, 1, 0, 3932153, 1, 0, 3997689, 1, 0, 4063225, 1, 0, 4128761, 1, 0, 3670010, 1, 0, 3735546, 1, 0, 3801082, 1, 0, 3866618, 1, 0, 3932154, 1, 0, 3997690, 1, 0, 4063226, 1, 0, 4128762, 1, 0, 3670011, 1, 0, 3735547, 1, 0, 3801083, 1, 0, 3866619, 1, 0, 3932155, 1, 0, 3997691, 1, 0, 4063227, 1, 0, 4128763, 1, 0, 3997692, 1, 0, 4063228, 1, 0, 4128764, 1, 0, 3997693, 1, 0, 4063229, 1, 0, 4128765, 1, 0, 3997694, 1, 0, 4063230, 1, 0, 4128766, 1, 0, 3997695, 1, 0, 4063231, 1, 0, 4128767, 1, 0, 3932160, 1, 0, 3997696, 1, 0, 4063232, 1, 0, 3932161, 1, 0, 3997697, 1, 0, 4063233, 1, 0, 3932162, 1, 0, 3997698, 1, 0, 4063234, 1, 0, 3932163, 1, 0, 3997699, 1, 0, 4063235, 1, 0, 3932164, 1, 0, 3997700, 1, 0, 4063236, 1, 0, 3932165, 1, 0, 3997701, 1, 0, 4063237, 1, 0, 3932166, 1, 0, 3997702, 1, 0, 4063238, 1, 0, 3932167, 1, 0, 3997703, 1, 0, 4063239, 1, 0, 3932168, 1, 0, 3997704, 1, 0, 4063240, 1, 0, 3932169, 1, 0, 3997705, 1, 0, 4063241, 1, 0, 3932170, 1, 0, 3997706, 1, 0, 4063242, 1, 0, 3932171, 1, 0, 3997707, 1, 0, 4063243, 1, 0, 3932172, 1, 0, 3997708, 1, 0, 4063244, 1, 0, 3932173, 1, 0, 3997709, 1, 0, 4063245, 1, 0, 3932174, 1, 0, 3997710, 1, 0, 4063246, 1, 0, 3932175, 1, 0, 3997711, 1, 0, 4063247, 1, 0, 3932176, 1, 0, 3997712, 1, 0, 4063248, 1, 0, 3932177, 1, 0, 3997713, 1, 0, 4063249, 1, 0, 3932178, 1, 0, 3997714, 1, 0, 4063250, 1, 0, 3932179, 1, 0, 3997715, 1, 0, 4063251, 1, 0, 3407889, 1, 0, 3473425, 1, 0, 3538961, 1, 0, 3604497, 1, 0, 3670033, 1, 0, 3735569, 1, 0, 3801105, 1, 0, 3866641, 1, 0, 3407890, 1, 0, 3473426, 1, 0, 3538962, 1, 0, 3604498, 1, 0, 3670034, 1, 0, 3735570, 1, 0, 3801106, 1, 0, 3866642, 1, 0, 3407891, 1, 0, 3473427, 1, 0, 3538963, 1, 0, 3604499, 1, 0, 3670035, 1, 0, 3735571, 1, 0, 3801107, 1, 0, 3866643, 1, 0, 3407880, 1, 0, 3473416, 1, 0, 3538952, 1, 0, 3407881, 1, 0, 3473417, 1, 0, 3538953, 1, 0, 3407882, 1, 0, 3473418, 1, 0, 3538954, 1, 0, 3407883, 1, 0, 3473419, 1, 0, 3538955, 1, 0, 3407884, 1, 0, 3473420, 1, 0, 3538956, 1, 0, 3407885, 1, 0, 3473421, 1, 0, 3538957, 1, 0, 3407886, 1, 0, 3473422, 1, 0, 3538958, 1, 0, 3407887, 1, 0, 3473423, 1, 0, 3538959, 1, 0, 3407888, 1, 0, 3473424, 1, 0, 3538960, 1, 0, 4128773, 1, 0, 4194309, 1, 0, 4259845, 1, 0, 4325381, 1, 0, 4390917, 1, 0, 4456453, 1, 0, 4521989, 1, 0, 4587525, 1, 0, 4653061, 1, 0, 4718597, 1, 0, 4784133, 1, 0, 4849669, 1, 0, 4915205, 1, 0, 4980741, 1, 0, 5046277, 1, 0, 5111813, 1, 0, 5177349, 1, 0, 5242885, 1, 0, 4128774, 1, 0, 4194310, 1, 0, 4259846, 1, 0, 4325382, 1, 0, 4390918, 1, 0, 4456454, 1, 0, 4521990, 1, 0, 4587526, 1, 0, 4653062, 1, 0, 4718598, 1, 0, 4784134, 1, 0, 4849670, 1, 0, 4915206, 1, 0, 4980742, 1, 0, 5046278, 1, 0, 5111814, 1, 0, 5177350, 1, 0, 5242886, 1, 0, 4128775, 1, 0, 4194311, 1, 0, 4259847, 1, 0, 4325383, 1, 0, 4390919, 1, 0, 4456455, 1, 0, 4521991, 1, 0, 4587527, 1, 0, 4653063, 1, 0, 4718599, 1, 0, 4784135, 1, 0, 4849671, 1, 0, 4915207, 1, 0, 4980743, 1, 0, 5046279, 1, 0, 5111815, 1, 0, 5177351, 1, 0, 5242887, 1, 0, 5308421, 1, 0, 5373957, 1, 0, 5439493, 1, 0, 5308422, 1, 0, 5373958, 1, 0, 5439494, 1, 0, 5308423, 1, 0, 5373959, 1, 0, 5439495, 1, 0, 5308424, 1, 0, 5373960, 1, 0, 5439496, 1, 0, 5308425, 1, 0, 5373961, 1, 0, 5439497, 1, 0, 5308426, 1, 0, 5373962, 1, 0, 5439498, 1, 0, 5308427, 1, 0, 5373963, 1, 0, 5439499, 1, 0, 5308428, 1, 0, 5373964, 1, 0, 5439500, 1, 0, 5308429, 1, 0, 5373965, 1, 0, 5439501, 1, 0, 5308430, 1, 0, 5373966, 1, 0, 5439502, 1, 0, 5308431, 1, 0, 5373967, 1, 0, 5439503, 1, 0, 5373949, 1, 0, 5439485, 1, 0, 5505021, 1, 0, 5373950, 1, 0, 5439486, 1, 0, 5505022, 1, 0, 5373951, 1, 0, 5439487, 1, 0, 5505023, 1, 0, 5308416, 1, 0, 5373952, 1, 0, 5439488, 1, 0, 5308417, 1, 0, 5373953, 1, 0, 5439489, 1, 0, 5308418, 1, 0, 5373954, 1, 0, 5439490, 1, 0, 5308419, 1, 0, 5373955, 1, 0, 5439491, 1, 0, 5308420, 1, 0, 5373956, 1, 0, 5439492, 1, 0, 4521973, 1, 0, 4587509, 1, 0, 4653045, 1, 0, 4718581, 1, 0, 4784117, 1, 0, 4849653, 1, 0, 4915189, 1, 0, 4980725, 1, 0, 5046261, 1, 0, 5111797, 1, 0, 5177333, 1, 0, 5242869, 1, 0, 5308405, 1, 0, 5373941, 1, 0, 5439477, 1, 0, 5505013, 1, 0, 5570549, 1, 0, 5636085, 1, 0, 5701621, 1, 0, 5767157, 1, 0, 5832693, 1, 0, 5898229, 1, 0, 5963765, 1, 0, 6029301, 1, 0, 6094837, 1, 0, 6160373, 1, 0, 6225909, 1, 0, 6291445, 1, 0, 6356981, 1, 0, 6422517, 1, 0, 6488053, 1, 0, 4521974, 1, 0, 4587510, 1, 0, 4653046, 1, 0, 4718582, 1, 0, 4784118, 1, 0, 4849654, 1, 0, 4915190, 1, 0, 4980726, 1, 0, 5046262, 1, 0, 5111798, 1, 0, 5177334, 1, 0, 5242870, 1, 0, 5308406, 1, 0, 5373942, 1, 0, 5439478, 1, 0, 5505014, 1, 0, 5570550, 1, 0, 5636086, 1, 0, 5701622, 1, 0, 5767158, 1, 0, 5832694, 1, 0, 5898230, 1, 0, 5963766, 1, 0, 6029302, 1, 0, 6094838, 1, 0, 6160374, 1, 0, 6225910, 1, 0, 6291446, 1, 0, 6356982, 1, 0, 6422518, 1, 0, 6488054, 1, 0, 4521975, 1, 0, 4587511, 1, 0, 4653047, 1, 0, 4718583, 1, 0, 4784119, 1, 0, 4849655, 1, 0, 4915191, 1, 0, 4980727, 1, 0, 5046263, 1, 0, 5111799, 1, 0, 5177335, 1, 0, 5242871, 1, 0, 5308407, 1, 0, 5373943, 1, 0, 5439479, 1, 0, 5505015, 1, 0, 5570551, 1, 0, 5636087, 1, 0, 5701623, 1, 0, 5767159, 1, 0, 5832695, 1, 0, 5898231, 1, 0, 5963767, 1, 0, 6029303, 1, 0, 6094839, 1, 0, 6160375, 1, 0, 6225911, 1, 0, 6291447, 1, 0, 6356983, 1, 0, 6422519, 1, 0, 6488055, 1, 0, 4521976, 1, 0, 4587512, 1, 0, 4653048, 1, 0, 4521977, 1, 0, 4587513, 1, 0, 4653049, 1, 0, 4521978, 1, 0, 4587514, 1, 0, 4653050, 1, 0, 4521979, 1, 0, 4587515, 1, 0, 4653051, 1, 0, 4521980, 1, 0, 4587516, 1, 0, 4653052, 1, 0, 4521981, 1, 0, 4587517, 1, 0, 4653053, 1, 0, 4521982, 1, 0, 4587518, 1, 0, 4653054, 1, 0, 4521983, 1, 0, 4587519, 1, 0, 4653055, 1, 0, 4718589, 1, 0, 4784125, 1, 0, 4849661, 1, 0, 4915197, 1, 0, 4980733, 1, 0, 5046269, 1, 0, 5111805, 1, 0, 5177341, 1, 0, 5242877, 1, 0, 5308413, 1, 0, 4718590, 1, 0, 4784126, 1, 0, 4849662, 1, 0, 4915198, 1, 0, 4980734, 1, 0, 5046270, 1, 0, 5111806, 1, 0, 5177342, 1, 0, 5242878, 1, 0, 5308414, 1, 0, 4718591, 1, 0, 4784127, 1, 0, 4849663, 1, 0, 4915199, 1, 0, 4980735, 1, 0, 5046271, 1, 0, 5111807, 1, 0, 5177343, 1, 0, 5242879, 1, 0, 5308415, 1, 0, 4456461, 1, 0, 4521997, 1, 0, 4587533, 1, 0, 4653069, 1, 0, 4718605, 1, 0, 4784141, 1, 0, 4849677, 1, 0, 4915213, 1, 0, 4980749, 1, 0, 5046285, 1, 0, 5111821, 1, 0, 5177357, 1, 0, 5242893, 1, 0, 4456462, 1, 0, 4521998, 1, 0, 4587534, 1, 0, 4653070, 1, 0, 4718606, 1, 0, 4784142, 1, 0, 4849678, 1, 0, 4915214, 1, 0, 4980750, 1, 0, 5046286, 1, 0, 5111822, 1, 0, 5177358, 1, 0, 5242894, 1, 0, 4456463, 1, 0, 4521999, 1, 0, 4587535, 1, 0, 4653071, 1, 0, 4718607, 1, 0, 4784143, 1, 0, 4849679, 1, 0, 4915215, 1, 0, 4980751, 1, 0, 5046287, 1, 0, 5111823, 1, 0, 5177359, 1, 0, 5242895, 1, 0, 4456464, 1, 0, 4522000, 1, 0, 4587536, 1, 0, 4456465, 1, 0, 4522001, 1, 0, 4587537, 1, 0, 4456466, 1, 0, 4522002, 1, 0, 4587538, 1, 0, 4456467, 1, 0, 4522003, 1, 0, 4587539, 1, 0, 4456468, 1, 0, 4522004, 1, 0, 4587540, 1, 0, 4456469, 1, 0, 4522005, 1, 0, 4587541, 1, 0, 4456470, 1, 0, 4522006, 1, 0, 4587542, 1, 0, 4456471, 1, 0, 4522007, 1, 0, 4587543, 1, 0, 4653077, 1, 0, 4718613, 1, 0, 4784149, 1, 0, 4849685, 1, 0, 4915221, 1, 0, 4980757, 1, 0, 5046293, 1, 0, 5111829, 1, 0, 5177365, 1, 0, 5242901, 1, 0, 5308437, 1, 0, 5373973, 1, 0, 5439509, 1, 0, 5505045, 1, 0, 5570581, 1, 0, 5636117, 1, 0, 5701653, 1, 0, 5767189, 1, 0, 5832725, 1, 0, 5898261, 1, 0, 5963797, 1, 0, 6029333, 1, 0, 6094869, 1, 0, 6160405, 1, 0, 6225941, 1, 0, 6291477, 1, 0, 6357013, 1, 0, 4653078, 1, 0, 4718614, 1, 0, 4784150, 1, 0, 4849686, 1, 0, 4915222, 1, 0, 4980758, 1, 0, 5046294, 1, 0, 5111830, 1, 0, 5177366, 1, 0, 5242902, 1, 0, 5308438, 1, 0, 5373974, 1, 0, 5439510, 1, 0, 5505046, 1, 0, 5570582, 1, 0, 5636118, 1, 0, 5701654, 1, 0, 5767190, 1, 0, 5832726, 1, 0, 5898262, 1, 0, 5963798, 1, 0, 6029334, 1, 0, 6094870, 1, 0, 6160406, 1, 0, 6225942, 1, 0, 6291478, 1, 0, 6357014, 1, 0, 4653079, 1, 0, 4718615, 1, 0, 4784151, 1, 0, 4849687, 1, 0, 4915223, 1, 0, 4980759, 1, 0, 5046295, 1, 0, 5111831, 1, 0, 5177367, 1, 0, 5242903, 1, 0, 5308439, 1, 0, 5373975, 1, 0, 5439511, 1, 0, 5505047, 1, 0, 5570583, 1, 0, 5636119, 1, 0, 5701655, 1, 0, 5767191, 1, 0, 5832727, 1, 0, 5898263, 1, 0, 5963799, 1, 0, 6029335, 1, 0, 6094871, 1, 0, 6160407, 1, 0, 6225943, 1, 0, 6291479, 1, 0, 6357015, 1, 0, 2097136, 1, 0, 2162672, 1, 0, 2228208, 1, 0, 2097137, 1, 0, 2162673, 1, 0, 2228209, 1, 0, 2097138, 1, 0, 2162674, 1, 0, 2228210, 1, 0, 2097139, 1, 0, 2162675, 1, 0, 2228211, 1, 0, 2097140, 1, 0, 2162676, 1, 0, 2228212, 1, 0, 2097141, 1, 0, 2162677, 1, 0, 2228213, 1, 0, 2097142, 1, 0, 2162678, 1, 0, 2228214, 1, 0, 2097143, 1, 0, 2162679, 1, 0, 2228215, 1, 0, 2097144, 1, 0, 2162680, 1, 0, 2228216, 1, 0, 2097145, 1, 0, 2162681, 1, 0, 2228217, 1, 0, 2097146, 1, 0, 2162682, 1, 0, 2228218, 1, 0, 2097147, 1, 0, 2162683, 1, 0, 2228219, 1, 0, 2097148, 1, 0, 2162684, 1, 0, 2228220, 1, 0, 2097149, 1, 0, 2162685, 1, 0, 2228221, 1, 0, 2097150, 1, 0, 2162686, 1, 0, 2228222, 1, 0, 2097151, 1, 0, 2162687, 1, 0, 2228223, 1, 0, 2031616, 1, 0, 2097152, 1, 0, 2162688, 1, 0, 2031617, 1, 0, 2097153, 1, 0, 2162689, 1, 0, 2031618, 1, 0, 2097154, 1, 0, 2162690, 1, 0, 2031619, 1, 0, 2097155, 1, 0, 2162691, 1, 0, 2031620, 1, 0, 2097156, 1, 0, 2162692, 1, 0, 1310704, 1, 0, 1376240, 1, 0, 1441776, 1, 0, 1507312, 1, 0, 1572848, 1, 0, 1638384, 1, 0, 1703920, 1, 0, 1769456, 1, 0, 1834992, 1, 0, 1900528, 1, 0, 1966064, 1, 0, 2031600, 1, 0, 1310705, 1, 0, 1376241, 1, 0, 1441777, 1, 0, 1507313, 1, 0, 1572849, 1, 0, 1638385, 1, 0, 1703921, 1, 0, 1769457, 1, 0, 1834993, 1, 0, 1900529, 1, 0, 1966065, 1, 0, 2031601, 1, 0, 1310706, 1, 0, 1376242, 1, 0, 1441778, 1, 0, 1507314, 1, 0, 1572850, 1, 0, 1638386, 1, 0, 1703922, 1, 0, 1769458, 1, 0, 1834994, 1, 0, 1900530, 1, 0, 1966066, 1, 0, 2031602, 1, 0, 1310696, 1, 0, 1376232, 1, 0, 1441768, 1, 0, 1310697, 1, 0, 1376233, 1, 0, 1441769, 1, 0, 1310698, 1, 0, 1376234, 1, 0, 1441770, 1, 0, 1310699, 1, 0, 1376235, 1, 0, 1441771, 1, 0, 1310700, 1, 0, 1376236, 1, 0, 1441772, 1, 0, 1310701, 1, 0, 1376237, 1, 0, 1441773, 1, 0, 1310702, 1, 0, 1376238, 1, 0, 1441774, 1, 0, 1310703, 1, 0, 1376239, 1, 0, 1441775, 1, 0, 1507304, 1, 0, 1572840, 1, 0, 1638376, 1, 0, 1703912, 1, 0, 1769448, 1, 0, 1834984, 1, 0, 1900520, 1, 0, 1966056, 1, 0, 2031592, 1, 0, 2097128, 1, 0, 2162664, 1, 0, 2228200, 1, 0, 2293736, 1, 0, 2359272, 1, 0, 2424808, 1, 0, 2490344, 1, 0, 2555880, 1, 0, 2621416, 1, 0, 2686952, 1, 0, 2752488, 1, 0, 2818024, 1, 0, 2883560, 1, 0, 2949096, 1, 0, 3014632, 1, 0, 1507305, 1, 0, 1572841, 1, 0, 1638377, 1, 0, 1703913, 1, 0, 1769449, 1, 0, 1834985, 1, 0, 1900521, 1, 0, 1966057, 1, 0, 2031593, 1, 0, 2097129, 1, 0, 2162665, 1, 0, 2228201, 1, 0, 2293737, 1, 0, 2359273, 1, 0, 2424809, 1, 0, 2490345, 1, 0, 2555881, 1, 0, 2621417, 1, 0, 2686953, 1, 0, 2752489, 1, 0, 2818025, 1, 0, 2883561, 1, 0, 2949097, 1, 0, 3014633, 1, 0, 1507306, 1, 0, 1572842, 1, 0, 1638378, 1, 0, 1703914, 1, 0, 1769450, 1, 0, 1834986, 1, 0, 1900522, 1, 0, 1966058, 1, 0, 2031594, 1, 0, 2097130, 1, 0, 2162666, 1, 0, 2228202, 1, 0, 2293738, 1, 0, 2359274, 1, 0, 2424810, 1, 0, 2490346, 1, 0, 2555882, 1, 0, 2621418, 1, 0, 2686954, 1, 0, 2752490, 1, 0, 2818026, 1, 0, 2883562, 1, 0, 2949098, 1, 0, 3014634, 1, 0, 2293744, 1, 0, 2359280, 1, 0, 2424816, 1, 0, 2490352, 1, 0, 2555888, 1, 0, 2621424, 1, 0, 2686960, 1, 0, 2752496, 1, 0, 2818032, 1, 0, 2883568, 1, 0, 2949104, 1, 0, 3014640, 1, 0, 2293745, 1, 0, 2359281, 1, 0, 2424817, 1, 0, 2490353, 1, 0, 2555889, 1, 0, 2621425, 1, 0, 2686961, 1, 0, 2752497, 1, 0, 2818033, 1, 0, 2883569, 1, 0, 2949105, 1, 0, 3014641, 1, 0, 2293746, 1, 0, 2359282, 1, 0, 2424818, 1, 0, 2490354, 1, 0, 2555890, 1, 0, 2621426, 1, 0, 2686962, 1, 0, 2752498, 1, 0, 2818034, 1, 0, 2883570, 1, 0, 2949106, 1, 0, 3014642, 1, 0, 2883563, 1, 0, 2949099, 1, 0, 3014635, 1, 0, 2883564, 1, 0, 2949100, 1, 0, 3014636, 1, 0, 2883565, 1, 0, 2949101, 1, 0, 3014637, 1, 0, 2883566, 1, 0, 2949102, 1, 0, 3014638, 1, 0, 2883567, 1, 0, 2949103, 1, 0, 3014639, 1, 0, 2097108, 1, 0, 2162644, 1, 0, 2228180, 1, 0, 2097109, 1, 0, 2162645, 1, 0, 2228181, 1, 0, 2097110, 1, 0, 2162646, 1, 0, 2228182, 1, 0, 2097111, 1, 0, 2162647, 1, 0, 2228183, 1, 0, 2097112, 1, 0, 2162648, 1, 0, 2228184, 1, 0, 2097113, 1, 0, 2162649, 1, 0, 2228185, 1, 0, 2097114, 1, 0, 2162650, 1, 0, 2228186, 1, 0, 2097115, 1, 0, 2162651, 1, 0, 2228187, 1, 0, 2097116, 1, 0, 2162652, 1, 0, 2228188, 1, 0, 2097117, 1, 0, 2162653, 1, 0, 2228189, 1, 0, 2097118, 1, 0, 2162654, 1, 0, 2228190, 1, 0, 2097119, 1, 0, 2162655, 1, 0, 2228191, 1, 0, 2097120, 1, 0, 2162656, 1, 0, 2228192, 1, 0, 2097121, 1, 0, 2162657, 1, 0, 2228193, 1, 0, 2097122, 1, 0, 2162658, 1, 0, 2228194, 1, 0, 2097123, 1, 0, 2162659, 1, 0, 2228195, 1, 0, 2097124, 1, 0, 2162660, 1, 0, 2228196, 1, 0, 2097125, 1, 0, 2162661, 1, 0, 2228197, 1, 0, 2097126, 1, 0, 2162662, 1, 0, 2228198, 1, 0, 2097127, 1, 0, 2162663, 1, 0, 2228199, 1, 0, 2293716, 1, 0, 2359252, 1, 0, 2424788, 1, 0, 2490324, 1, 0, 2555860, 1, 0, 2621396, 1, 0, 2686932, 1, 0, 2752468, 1, 0, 2293717, 1, 0, 2359253, 1, 0, 2424789, 1, 0, 2490325, 1, 0, 2555861, 1, 0, 2621397, 1, 0, 2686933, 1, 0, 2752469, 1, 0, 2621398, 1, 0, 2686934, 1, 0, 2752470, 1, 0, 2621399, 1, 0, 2686935, 1, 0, 2752471, 1, 0, 2621400, 1, 0, 2686936, 1, 0, 2752472, 1, 0, 2621401, 1, 0, 2686937, 1, 0, 2752473, 1, 0, 2621402, 1, 0, 2686938, 1, 0, 2752474, 1, 0, 2621403, 1, 0, 2686939, 1, 0, 2752475, 1, 0, 2621404, 1, 0, 2686940, 1, 0, 2752476, 1, 0, 2621405, 1, 0, 2686941, 1, 0, 2752477, 1, 0, 2621406, 1, 0, 2686942, 1, 0, 2752478, 1, 0, 2621407, 1, 0, 2686943, 1, 0, 2752479, 1, 0, 2621408, 1, 0, 2686944, 1, 0, 2752480, 1, 0, 2621409, 1, 0, 2686945, 1, 0, 2752481, 1, 0, 2621410, 1, 0, 2686946, 1, 0, 2752482, 1, 0, 2293718, 1, 0, 2359254, 1, 0, 2424790, 1, 0, 2490326, 1, 0, 2555862, 1, 0, 2818016, 1, 0, 2883552, 1, 0, 2949088, 1, 0, 3014624, 1, 0, 3080160, 1, 0, 3145696, 1, 0, 3211232, 1, 0, 3276768, 1, 0, 2818017, 1, 0, 2883553, 1, 0, 2949089, 1, 0, 3014625, 1, 0, 3080161, 1, 0, 3145697, 1, 0, 3211233, 1, 0, 3276769, 1, 0, 2818018, 1, 0, 2883554, 1, 0, 2949090, 1, 0, 3014626, 1, 0, 3080162, 1, 0, 3145698, 1, 0, 3211234, 1, 0, 3276770, 1, 0, 3145672, 1, 0, 3211208, 1, 0, 3276744, 1, 0, 3145673, 1, 0, 3211209, 1, 0, 3276745, 1, 0, 3145674, 1, 0, 3211210, 1, 0, 3276746, 1, 0, 3145675, 1, 0, 3211211, 1, 0, 3276747, 1, 0, 3145676, 1, 0, 3211212, 1, 0, 3276748, 1, 0, 3145677, 1, 0, 3211213, 1, 0, 3276749, 1, 0, 3145678, 1, 0, 3211214, 1, 0, 3276750, 1, 0, 3145679, 1, 0, 3211215, 1, 0, 3276751, 1, 0, 3145680, 1, 0, 3211216, 1, 0, 3276752, 1, 0, 3145681, 1, 0, 3211217, 1, 0, 3276753, 1, 0, 3145682, 1, 0, 3211218, 1, 0, 3276754, 1, 0, 3145683, 1, 0, 3211219, 1, 0, 3276755, 1, 0, 3145684, 1, 0, 3211220, 1, 0, 3276756, 1, 0, 3145685, 1, 0, 3211221, 1, 0, 3276757, 1, 0, 3145686, 1, 0, 3211222, 1, 0, 3276758, 1, 0, 3145687, 1, 0, 3211223, 1, 0, 3276759, 1, 0, 3145688, 1, 0, 3211224, 1, 0, 3276760, 1, 0, 3145689, 1, 0, 3211225, 1, 0, 3276761, 1, 0, 3145690, 1, 0, 3211226, 1, 0, 3276762, 1, 0, 3145691, 1, 0, 3211227, 1, 0, 3276763, 1, 0, 3145692, 1, 0, 3211228, 1, 0, 3276764, 1, 0, 3145693, 1, 0, 3211229, 1, 0, 3276765, 1, 0, 3145694, 1, 0, 3211230, 1, 0, 3276766, 1, 0, 3145695, 1, 0, 3211231, 1, 0, 3276767, 1, 0, 1572820, 1, 0, 1638356, 1, 0, 1703892, 1, 0, 1769428, 1, 0, 1834964, 1, 0, 1900500, 1, 0, 1966036, 1, 0, 2031572, 1, 0, 1572821, 1, 0, 1638357, 1, 0, 1703893, 1, 0, 1769429, 1, 0, 1834965, 1, 0, 1900501, 1, 0, 1966037, 1, 0, 2031573, 1, 0, 1572822, 1, 0, 1638358, 1, 0, 1703894, 1, 0, 1769430, 1, 0, 1834966, 1, 0, 1900502, 1, 0, 1966038, 1, 0, 2031574, 1, 0, 1572823, 1, 0, 1638359, 1, 0, 1703895, 1, 0, 1572824, 1, 0, 1638360, 1, 0, 1703896, 1, 0, 1572825, 1, 0, 1638361, 1, 0, 1703897, 1, 0, 1572826, 1, 0, 1638362, 1, 0, 1703898, 1, 0, 1572827, 1, 0, 1638363, 1, 0, 1703899, 1, 0, 1572828, 1, 0, 1638364, 1, 0, 1703900, 1, 0, 1572829, 1, 0, 1638365, 1, 0, 1703901, 1, 0, 1572830, 1, 0, 1638366, 1, 0, 1703902, 1, 0, 1572831, 1, 0, 1638367, 1, 0, 1703903, 1, 0, 1572832, 1, 0, 1638368, 1, 0, 1703904, 1, 0, 1572833, 1, 0, 1638369, 1, 0, 1703905, 1, 0, 1572834, 1, 0, 1638370, 1, 0, 1703906, 1, 0, 1048544, 1, 0, 1114080, 1, 0, 1179616, 1, 0, 1245152, 1, 0, 1310688, 1, 0, 1376224, 1, 0, 1441760, 1, 0, 1507296, 1, 0, 1048545, 1, 0, 1114081, 1, 0, 1179617, 1, 0, 1245153, 1, 0, 1310689, 1, 0, 1376225, 1, 0, 1441761, 1, 0, 1507297, 1, 0, 1048546, 1, 0, 1114082, 1, 0, 1179618, 1, 0, 1245154, 1, 0, 1310690, 1, 0, 1376226, 1, 0, 1441762, 1, 0, 1507298, 1, 0, 1048517, 1, 0, 1114053, 1, 0, 1179589, 1, 0, 1048518, 1, 0, 1114054, 1, 0, 1179590, 1, 0, 1048519, 1, 0, 1114055, 1, 0, 1179591, 1, 0, 1048520, 1, 0, 1114056, 1, 0, 1179592, 1, 0, 1048521, 1, 0, 1114057, 1, 0, 1179593, 1, 0, 1048522, 1, 0, 1114058, 1, 0, 1179594, 1, 0, 1048523, 1, 0, 1114059, 1, 0, 1179595, 1, 0, 1048524, 1, 0, 1114060, 1, 0, 1179596, 1, 0, 1048525, 1, 0, 1114061, 1, 0, 1179597, 1, 0, 1048526, 1, 0, 1114062, 1, 0, 1179598, 1, 0, 1048527, 1, 0, 1114063, 1, 0, 1179599, 1, 0, 1048528, 1, 0, 1114064, 1, 0, 1179600, 1, 0, 1048529, 1, 0, 1114065, 1, 0, 1179601, 1, 0, 1048530, 1, 0, 1114066, 1, 0, 1179602, 1, 0, 1048531, 1, 0, 1114067, 1, 0, 1179603, 1, 0, 1048532, 1, 0, 1114068, 1, 0, 1179604, 1, 0, 1048533, 1, 0, 1114069, 1, 0, 1179605, 1, 0, 1048534, 1, 0, 1114070, 1, 0, 1179606, 1, 0, 1048535, 1, 0, 1114071, 1, 0, 1179607, 1, 0, 1048536, 1, 0, 1114072, 1, 0, 1179608, 1, 0, 1048537, 1, 0, 1114073, 1, 0, 1179609, 1, 0, 1048538, 1, 0, 1114074, 1, 0, 1179610, 1, 0, 1048539, 1, 0, 1114075, 1, 0, 1179611, 1, 0, 1048540, 1, 0, 1114076, 1, 0, 1179612, 1, 0, 1048541, 1, 0, 1114077, 1, 0, 1179613, 1, 0, 1048542, 1, 0, 1114078, 1, 0, 1179614, 1, 0, 1048543, 1, 0, 1114079, 1, 0, 1179615, 1, 0)\n\n[node name=\"MapBorderPoly\" type=\"Polygon2D\" parent=\".\"]\nmodulate = Color(0, 0, 0, 0.560784)\nz_index = 999\npolygon = PackedVector2Array(7000, 8000, 7000, -3000, -13500, -3000, -13500, 8000, -12500, 8000, -12500, -2000, 6000, -2000, 6000, 7000, -12500, 7000, -12500, 8000)\n\n[node name=\"CameraLimits\" type=\"Polygon2D\" parent=\".\"]\nvisible = false\nz_index = 999\ncolor = Color(0, 1, 0, 0.196078)\npolygon = PackedVector2Array(-13237, -2826, 6713, -2758, 6770, 7761, -13305, 7853)\n"
  },
  {
    "path": "src/map/map_small.tscn",
    "content": "[gd_scene load_steps=45 format=4 uid=\"uid://bjvafnsglmpin\"]\n\n[ext_resource type=\"Script\" path=\"res://src/map/map.gd\" id=\"1_icbek\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dbh4ut425s1ja\" path=\"res://assets/tiles/stone_columns.png\" id=\"2_vv6h3\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://28he7nw8q1lo\" path=\"res://assets/tiles/floor.png\" id=\"3_t2r5t\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bb3cy5nc11xm4\" path=\"res://assets/tiles/planks.png\" id=\"4_agesl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dwtspohoptiwn\" path=\"res://assets/tiles/wooden_supports.png\" id=\"5_xwjbe\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://8hg2mltwjvch\" path=\"res://assets/tiles/bridges.png\" id=\"6_p6knj\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ui4kf3f3fnc\" path=\"res://assets/tiles/stairs.png\" id=\"7_rh5uu\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b1jfa4r4faj77\" path=\"res://assets/tiles/wooden_pile.png\" id=\"8_3cvue\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bq4bfj6wa7488\" path=\"res://assets/tiles/floor1_walls.png\" id=\"9_p5vov\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b8kaotwoawygm\" path=\"res://assets/tiles/barrels.png\" id=\"10_bvbfw\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://m7awn68i621a\" path=\"res://assets/tiles/stone_walls.png\" id=\"11_wcu41\"]\n[ext_resource type=\"TileSet\" uid=\"uid://c2ke1gy0rnehu\" path=\"res://resources/tilesets/decorations.tres\" id=\"12_7re5p\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dsaarf0j6pf6g\" path=\"res://src/map/buildable_area.tscn\" id=\"13_6pgbl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://2v03j2bnie6o\" path=\"res://assets/tiles/empty_tiles.png\" id=\"14_v5trd\"]\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_d2fx0\"]\ntile_data = PackedInt32Array(131072, 131082, 1, 131073, 131082, 1, 2, 262154, 1, 65538, 262154, 1, 131074, 393226, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_qfbjk\"]\ntile_data = PackedInt32Array(0, 262145, 6, 65536, 262145, 6, 131072, 262145, 6, 1, 262145, 6, 65537, 262145, 6, 131073, 262145, 6, 2, 262145, 6, 65538, 262145, 6, 131074, 262145, 6)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_ek0n5\"]\ntile_data = PackedInt32Array(0, 131073, 196614, 65536, 131073, 196614, 131072, 131073, 196614, 1, 131073, 196614, 65537, 131073, 196614, 131073, 131073, 196614, 196609, 131073, 196614, 2, 131073, 196614, 65538, 131073, 196614, 131074, 131073, 196614, 196610, 131073, 196614, 262146, 131073, 196614, 3, 131073, 196614, 65539, 131073, 196614, 131075, 131073, 196614, 196611, 131073, 196614, 262147, 131073, 196614, 327683, 131073, 196614, 4, 131073, 196614, 65540, 131073, 196614, 131076, 131073, 196614, 196612, 131073, 196614, 262148, 131073, 196614, 327684, 131073, 196614, 393220, 131073, 196614, 5, 196609, 6, 65541, 196609, 2, 131077, 196609, 6, 196613, 196609, 6, 262149, 1, 4, 327685, 196609, 6, 393221, 262145, 2, 458757, 196609, 6)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_h6mhp\"]\ntile_data = PackedInt32Array(0, 10, 1, 65536, 10, 1, 131072, 10, 1, 196608, 10, 1, 262144, 10, 1, 327680, 10, 1, 393216, 10, 1, 458752, 10, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_oa6ak\"]\ntile_data = PackedInt32Array(0, 10, 1, 65536, 10, 1, 131072, 10, 1, 196608, 10, 1, 262144, 10, 1, 327680, 10, 1, 393216, 10, 1, 458752, 10, 1, 1, 65541, 1, 131073, 65541, 1, 262145, 65541, 1, 393217, 65541, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_42qrd\"]\ntile_data = PackedInt32Array(0, 10, 1, 65536, 10, 1, 131072, 10, 1, 196608, 10, 1, 262144, 10, 1, 327680, 10, 1, 393216, 10, 1, 458752, 10, 1, 1, 393226, 1, 65537, 262164, 196611, 131073, 393226, 1, 196609, 262164, 196611, 262145, 393226, 1, 327681, 262164, 196611, 393217, 393226, 1, 458753, 262164, 196611)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_ijasj\"]\ntile_data = PackedInt32Array(0, 196634, 3, 65536, 262164, 196611, 131072, 196634, 3, 196608, 262164, 196611, 262144, 196634, 3, 327680, 262164, 196611, 393216, 196634, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_6nqay\"]\ntile_data = PackedInt32Array(0, 327706, 3, 131072, 327706, 3, 262144, 327706, 3, 393216, 327706, 3, 65537, 393226, 1, 131073, 65541, 1, 196609, 393226, 1, 262145, 65541, 1, 327681, 393226, 1, 393217, 65541, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_63foq\"]\ntile_data = PackedInt32Array(65536, 65536, 0, 196608, 65536, 0, 1, 131073, 6, 65537, 10, 1, 131073, 10, 1, 196609, 10, 1, 2, 196609, 6, 65538, 393226, 1, 131074, 393226, 1, 196610, 393226, 1)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_vk3cr\"]\ntile_data = PackedInt32Array(65536, 196634, 0, 131072, 196634, 0, 196608, 196634, 0, 1, 65562, 0, 262145, 131098, 0, 2, 65562, 0, 262146, 131098, 0, 3, 65562, 0, 262147, 131098, 0, 65540, 26, 0, 131076, 26, 0, 196612, 26, 0)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_xos4k\"]\ntile_data = PackedInt32Array(0, 196629, 0, 65536, 196631, 3, 131072, 458773, 3, 196608, 196631, 3, 262144, 458773, 3, 327680, 458773, 3, 393216, 458773, 3, 458752, 458773, 3, 524288, 458773, 3, 589824, 458773, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_v4ns7\"]\ntile_data = PackedInt32Array(0, 196629, 0, 65536, 458773, 3, 131072, 458773, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_g7k4a\"]\ntile_data = PackedInt32Array(0, 262149, 131073, 65536, 262149, 131073, 131072, 262149, 131073, 196608, 262149, 131073, 262144, 262149, 131073, 327680, 262149, 131073, 393216, 262149, 131073, 458752, 262149, 131073, 524288, 262149, 131073, 589824, 262149, 131073)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_fiebi\"]\ntile_data = PackedInt32Array(0, 196633, 6, 65536, 65561, 6, 1, 131097, 6, 65537, 196633, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_jl4gk\"]\ntile_data = PackedInt32Array(0, 196628, 3, 65536, 196628, 3, 1, 393241, 3, 65537, 327705, 3, 2, 393241, 3, 65538, 327705, 3, 3, 20, 3, 65539, 262167, 3)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_77y07\"]\ntile_data = PackedInt32Array(65536, 196634, 0, 131072, 196634, 0, 196608, 196634, 0, 262144, 196634, 0, 1, 65562, 0, 65537, 393217, 2, 131073, 196609, 6, 196609, 196609, 6, 262145, 196609, 6, 2, 65562, 0, 65538, 196609, 6, 131074, 196609, 6, 196610, 196609, 2, 262146, 196609, 6, 327682, 196609, 6, 3, 65562, 0, 65539, 196609, 6, 131075, 196609, 6, 196611, 327681, 2, 262147, 196609, 6, 327683, 196609, 6, 393219, 196609, 6, 4, 65562, 0, 65540, 196609, 6, 131076, 196609, 6, 196612, 196609, 6, 262148, 196609, 6, 327684, 196609, 6, 393220, 196609, 6, 458756, 196609, 6, 65541, 26, 0, 131077, 26, 0, 196613, 26, 0, 262149, 26, 0, 327685, 26, 0, 393221, 26, 0, 458757, 26, 0)\n\n[sub_resource type=\"TileMapPattern\" id=\"TileMapPattern_1q1ay\"]\ntile_data = PackedInt32Array(0, 65562, 0, 1, 65562, 0, 131073, 458776, 0, 196609, 458776, 0, 262145, 458776, 0, 327681, 458776, 0, 393217, 458776, 0, 458753, 458776, 0, 2, 65562, 0, 65539, 26, 0, 131075, 26, 0, 196611, 26, 0, 262147, 26, 0, 327683, 26, 0, 393219, 26, 0, 458755, 26, 0, 524291, 26, 0)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_gmax7\"]\ntexture = ExtResource(\"2_vv6h3\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_lnh7f\"]\ntexture = ExtResource(\"3_t2r5t\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 44)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 44)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 44)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 44)\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 44)\n5:0/0 = 0\n5:0/0/texture_origin = Vector2i(0, 44)\n6:0/0 = 0\n6:0/0/texture_origin = Vector2i(0, 44)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 44)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 44)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 44)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 44)\n4:1/0 = 0\n4:1/0/texture_origin = Vector2i(0, 44)\n5:1/0 = 0\n5:1/0/texture_origin = Vector2i(0, 44)\n6:1/0 = 0\n6:1/0/texture_origin = Vector2i(0, 44)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 44)\n0:2/0/probability = 0.1\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 44)\n1:2/0/probability = 0.1\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 44)\n2:2/0/probability = 0.1\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 44)\n3:2/0/probability = 0.1\n4:2/0 = 0\n4:2/0/texture_origin = Vector2i(0, 44)\n4:2/0/probability = 0.1\n5:2/0 = 0\n5:2/0/texture_origin = Vector2i(0, 44)\n5:2/0/probability = 0.2\n6:2/0 = 0\n6:2/0/texture_origin = Vector2i(0, 44)\n6:2/0/probability = 0.1\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 44)\n0:3/0/probability = 0.1\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 44)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 44)\n3:3/next_alternative_id = 2\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 44)\n4:3/0 = 0\n4:3/0/texture_origin = Vector2i(0, 44)\n5:3/0 = 0\n5:3/0/texture_origin = Vector2i(0, 44)\n5:3/0/probability = 0.05\n6:3/0 = 0\n6:3/0/texture_origin = Vector2i(0, 44)\n6:3/0/probability = 0.05\n0:4/0 = 0\n0:4/0/texture_origin = Vector2i(0, 44)\n0:4/0/probability = 0.05\n1:4/0 = 0\n1:4/0/texture_origin = Vector2i(0, 44)\n1:4/0/probability = 0.05\n2:4/0 = 0\n2:4/0/texture_origin = Vector2i(0, 44)\n3:4/0 = 0\n3:4/0/texture_origin = Vector2i(0, 44)\n4:4/0 = 0\n4:4/0/texture_origin = Vector2i(0, 44)\n5:4/0 = 0\n5:4/0/texture_origin = Vector2i(0, 44)\n6:4/0 = 0\n6:4/0/texture_origin = Vector2i(0, 44)\n6:4/0/probability = 0.05\n0:5/0 = 0\n0:5/0/texture_origin = Vector2i(0, 44)\n0:5/0/probability = 0.05\n1:5/0 = 0\n1:5/0/texture_origin = Vector2i(0, 44)\n1:5/0/probability = 0.05\n2:5/0 = 0\n2:5/0/texture_origin = Vector2i(0, 44)\n2:5/0/probability = 0.05\n3:5/0 = 0\n3:5/0/texture_origin = Vector2i(0, 44)\n4:5/0 = 0\n4:5/0/texture_origin = Vector2i(0, 44)\n5:5/0 = 0\n5:5/0/texture_origin = Vector2i(0, 44)\n6:5/0 = 0\n6:5/0/texture_origin = Vector2i(0, 44)\n0:6/0 = 0\n0:6/0/texture_origin = Vector2i(0, 44)\n1:6/0 = 0\n1:6/0/texture_origin = Vector2i(0, 44)\n2:6/next_alternative_id = 5\n2:6/0 = 0\n2:6/0/texture_origin = Vector2i(0, 44)\n3:6/0 = 0\n3:6/0/texture_origin = Vector2i(0, 44)\n4:6/0 = 0\n4:6/0/texture_origin = Vector2i(0, 44)\n5:6/0 = 0\n5:6/0/texture_origin = Vector2i(0, 44)\n6:6/0 = 0\n6:6/0/texture_origin = Vector2i(0, 44)\n7:0/0 = 0\n7:0/0/texture_origin = Vector2i(0, 44)\n7:1/0 = 0\n7:1/0/texture_origin = Vector2i(0, 44)\n7:2/0 = 0\n7:2/0/texture_origin = Vector2i(0, 44)\n7:3/0 = 0\n7:3/0/texture_origin = Vector2i(0, 44)\n7:4/0 = 0\n7:4/0/texture_origin = Vector2i(0, 44)\n7:5/0 = 0\n7:5/0/texture_origin = Vector2i(0, 44)\n7:6/0 = 0\n7:6/0/texture_origin = Vector2i(0, 44)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_gxawd\"]\ntexture = ExtResource(\"4_agesl\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/next_alternative_id = 2\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_512a0\"]\nresource_name = \"wooden-supports\"\ntexture = ExtResource(\"5_xwjbe\")\ntexture_region_size = Vector2i(256, 384)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 128)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 128)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 128)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 128)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 128)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 128)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 128)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 128)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 128)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 128)\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 128)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 128)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 128)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 128)\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 128)\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 128)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_avgj8\"]\ntexture = ExtResource(\"6_p6knj\")\ntexture_region_size = Vector2i(256, 128)\nuse_texture_padding = false\n0:0/0 = 0\n1:0/0 = 0\n0:1/0 = 0\n1:1/0 = 0\n0:2/0 = 0\n1:2/0 = 0\n0:3/0 = 0\n1:3/0 = 0\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_a6dct\"]\ntexture = ExtResource(\"7_rh5uu\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/next_alternative_id = 3\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/next_alternative_id = 2\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/next_alternative_id = 4\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_1hvd6\"]\ntexture = ExtResource(\"8_3cvue\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_koob1\"]\ntexture = ExtResource(\"9_p5vov\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_ryqdi\"]\ntexture = ExtResource(\"10_bvbfw\")\ntexture_region_size = Vector2i(256, 256)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 64)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 64)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 64)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 64)\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 64)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 64)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 64)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 64)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 64)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 64)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 64)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 64)\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_i3vo1\"]\ntexture = ExtResource(\"11_wcu41\")\ntexture_region_size = Vector2i(256, 384)\nuse_texture_padding = false\n0:1/0 = 0\n0:1/0/texture_origin = Vector2i(0, 128)\n4:1/0 = 0\n4:1/0/texture_origin = Vector2i(0, 128)\n6:1/0 = 0\n6:1/0/texture_origin = Vector2i(0, 128)\n0:2/0 = 0\n0:2/0/texture_origin = Vector2i(0, 128)\n1:2/0 = 0\n1:2/0/texture_origin = Vector2i(0, 128)\n2:2/0 = 0\n2:2/0/texture_origin = Vector2i(0, 128)\n3:2/0 = 0\n3:2/0/texture_origin = Vector2i(0, 128)\n4:2/0 = 0\n4:2/0/texture_origin = Vector2i(0, 128)\n5:2/0 = 0\n5:2/0/texture_origin = Vector2i(0, 128)\n6:2/0 = 0\n6:2/0/texture_origin = Vector2i(0, 128)\n7:2/0 = 0\n7:2/0/texture_origin = Vector2i(0, 128)\n0:3/0 = 0\n0:3/0/texture_origin = Vector2i(0, 128)\n1:3/0 = 0\n1:3/0/texture_origin = Vector2i(0, 128)\n2:3/0 = 0\n2:3/0/texture_origin = Vector2i(0, 128)\n3:3/0 = 0\n3:3/0/texture_origin = Vector2i(0, 128)\n4:3/0 = 0\n4:3/0/texture_origin = Vector2i(0, 128)\n5:3/0 = 0\n5:3/0/texture_origin = Vector2i(0, 128)\n6:3/0 = 0\n6:3/0/texture_origin = Vector2i(0, 128)\n7:3/0 = 0\n7:3/0/texture_origin = Vector2i(0, 128)\n0:5/0 = 0\n0:5/0/texture_origin = Vector2i(0, 128)\n2:5/0 = 0\n2:5/0/texture_origin = Vector2i(0, 128)\n4:5/0 = 0\n4:5/0/texture_origin = Vector2i(0, 128)\n6:5/0 = 0\n6:5/0/texture_origin = Vector2i(0, 128)\n0:6/0 = 0\n0:6/0/texture_origin = Vector2i(0, 128)\n1:6/0 = 0\n1:6/0/texture_origin = Vector2i(0, 128)\n2:6/0 = 0\n2:6/0/texture_origin = Vector2i(0, 128)\n3:6/0 = 0\n3:6/0/texture_origin = Vector2i(0, 128)\n4:6/0 = 0\n4:6/0/texture_origin = Vector2i(0, 128)\n5:6/0 = 0\n5:6/0/texture_origin = Vector2i(0, 128)\n6:6/0 = 0\n6:6/0/texture_origin = Vector2i(0, 128)\n7:6/0 = 0\n7:6/0/texture_origin = Vector2i(0, 128)\n0:7/0 = 0\n0:7/0/texture_origin = Vector2i(0, 128)\n1:7/0 = 0\n1:7/0/texture_origin = Vector2i(0, 128)\n2:7/0 = 0\n2:7/0/texture_origin = Vector2i(0, 128)\n3:7/0 = 0\n3:7/0/texture_origin = Vector2i(0, 128)\n4:7/0 = 0\n4:7/0/texture_origin = Vector2i(0, 128)\n5:7/0 = 0\n5:7/0/texture_origin = Vector2i(0, 128)\n6:7/0 = 0\n6:7/0/texture_origin = Vector2i(0, 128)\n7:7/0 = 0\n7:7/0/texture_origin = Vector2i(0, 128)\n0:9/0 = 0\n0:9/0/texture_origin = Vector2i(0, 128)\n6:9/0 = 0\n6:9/0/texture_origin = Vector2i(0, 128)\n0:10/0 = 0\n0:10/0/texture_origin = Vector2i(0, 128)\n1:10/0 = 0\n1:10/0/texture_origin = Vector2i(0, 128)\n2:10/0 = 0\n2:10/0/texture_origin = Vector2i(0, 128)\n3:10/0 = 0\n3:10/0/texture_origin = Vector2i(0, 128)\n4:10/0 = 0\n4:10/0/texture_origin = Vector2i(0, 128)\n5:10/0 = 0\n5:10/0/texture_origin = Vector2i(0, 128)\n6:10/0 = 0\n6:10/0/texture_origin = Vector2i(0, 128)\n7:10/0 = 0\n7:10/0/texture_origin = Vector2i(0, 128)\n0:11/0 = 0\n0:11/0/texture_origin = Vector2i(0, 128)\n1:11/0 = 0\n1:11/0/texture_origin = Vector2i(0, 128)\n2:11/0 = 0\n2:11/0/texture_origin = Vector2i(0, 128)\n3:11/0 = 0\n3:11/0/texture_origin = Vector2i(0, 128)\n4:11/0 = 0\n4:11/0/texture_origin = Vector2i(0, 128)\n5:11/0 = 0\n5:11/0/texture_origin = Vector2i(0, 128)\n6:11/0 = 0\n6:11/0/texture_origin = Vector2i(0, 128)\n7:11/0 = 0\n7:11/0/texture_origin = Vector2i(0, 128)\n0:13/0 = 0\n0:13/0/texture_origin = Vector2i(0, 128)\n2:13/0 = 0\n2:13/0/texture_origin = Vector2i(0, 128)\n4:13/0 = 0\n4:13/0/texture_origin = Vector2i(0, 128)\n6:13/0 = 0\n6:13/0/texture_origin = Vector2i(0, 128)\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 128)\n1:0/0 = 0\n1:0/0/texture_origin = Vector2i(0, 128)\n2:0/0 = 0\n2:0/0/texture_origin = Vector2i(0, 128)\n3:0/0 = 0\n3:0/0/texture_origin = Vector2i(0, 128)\n4:0/0 = 0\n4:0/0/texture_origin = Vector2i(0, 128)\n5:0/0 = 0\n5:0/0/texture_origin = Vector2i(0, 128)\n6:0/0 = 0\n6:0/0/texture_origin = Vector2i(0, 128)\n7:0/0 = 0\n7:0/0/texture_origin = Vector2i(0, 128)\n1:1/0 = 0\n1:1/0/texture_origin = Vector2i(0, 128)\n2:1/0 = 0\n2:1/0/texture_origin = Vector2i(0, 128)\n3:1/0 = 0\n3:1/0/texture_origin = Vector2i(0, 128)\n5:1/0 = 0\n5:1/0/texture_origin = Vector2i(0, 128)\n7:1/0 = 0\n7:1/0/texture_origin = Vector2i(0, 128)\n0:4/0 = 0\n0:4/0/texture_origin = Vector2i(0, 128)\n1:4/0 = 0\n1:4/0/texture_origin = Vector2i(0, 128)\n2:4/0 = 0\n2:4/0/texture_origin = Vector2i(0, 128)\n3:4/0 = 0\n3:4/0/texture_origin = Vector2i(0, 128)\n4:4/0 = 0\n4:4/0/texture_origin = Vector2i(0, 128)\n5:4/0 = 0\n5:4/0/texture_origin = Vector2i(0, 128)\n6:4/0 = 0\n6:4/0/texture_origin = Vector2i(0, 128)\n7:4/0 = 0\n7:4/0/texture_origin = Vector2i(0, 128)\n1:5/0 = 0\n1:5/0/texture_origin = Vector2i(0, 128)\n3:5/0 = 0\n3:5/0/texture_origin = Vector2i(0, 128)\n5:5/0 = 0\n5:5/0/texture_origin = Vector2i(0, 128)\n7:5/0 = 0\n7:5/0/texture_origin = Vector2i(0, 128)\n0:8/0 = 0\n0:8/0/texture_origin = Vector2i(0, 128)\n1:8/0 = 0\n1:8/0/texture_origin = Vector2i(0, 128)\n2:8/0 = 0\n2:8/0/texture_origin = Vector2i(0, 128)\n3:8/0 = 0\n3:8/0/texture_origin = Vector2i(0, 128)\n4:8/0 = 0\n4:8/0/texture_origin = Vector2i(0, 128)\n5:8/0 = 0\n5:8/0/texture_origin = Vector2i(0, 128)\n6:8/0 = 0\n6:8/0/texture_origin = Vector2i(0, 128)\n7:8/0 = 0\n7:8/0/texture_origin = Vector2i(0, 128)\n7:9/0 = 0\n7:9/0/texture_origin = Vector2i(0, 128)\n5:9/0 = 0\n5:9/0/texture_origin = Vector2i(0, 128)\n4:9/0 = 0\n4:9/0/texture_origin = Vector2i(0, 128)\n3:9/0 = 0\n3:9/0/texture_origin = Vector2i(0, 128)\n2:9/0 = 0\n2:9/0/texture_origin = Vector2i(0, 128)\n1:9/0 = 0\n1:9/0/texture_origin = Vector2i(0, 128)\n0:12/0 = 0\n0:12/0/texture_origin = Vector2i(0, 128)\n1:12/0 = 0\n1:12/0/texture_origin = Vector2i(0, 128)\n2:12/0 = 0\n2:12/0/texture_origin = Vector2i(0, 128)\n3:12/0 = 0\n3:12/0/texture_origin = Vector2i(0, 128)\n4:12/0 = 0\n4:12/0/texture_origin = Vector2i(0, 128)\n5:12/0 = 0\n5:12/0/texture_origin = Vector2i(0, 128)\n6:12/0 = 0\n6:12/0/texture_origin = Vector2i(0, 128)\n7:12/0 = 0\n7:12/0/texture_origin = Vector2i(0, 128)\n1:13/0 = 0\n1:13/0/texture_origin = Vector2i(0, 128)\n3:13/0 = 0\n3:13/0/texture_origin = Vector2i(0, 128)\n5:13/0 = 0\n5:13/0/texture_origin = Vector2i(0, 128)\n7:13/0 = 0\n7:13/0/texture_origin = Vector2i(0, 128)\n\n[sub_resource type=\"TileSet\" id=\"TileSet_talwn\"]\ntile_shape = 1\ntile_layout = 5\ntile_size = Vector2i(256, 128)\nnavigation_layer_0/layers = 1\nsources/1 = SubResource(\"TileSetAtlasSource_lnh7f\")\nsources/5 = SubResource(\"TileSetAtlasSource_a6dct\")\nsources/50 = SubResource(\"TileSetAtlasSource_1hvd6\")\nsources/60 = SubResource(\"TileSetAtlasSource_ryqdi\")\nsources/2 = SubResource(\"TileSetAtlasSource_gxawd\")\nsources/4 = SubResource(\"TileSetAtlasSource_avgj8\")\nsources/6 = SubResource(\"TileSetAtlasSource_koob1\")\nsources/9 = SubResource(\"TileSetAtlasSource_i3vo1\")\nsources/0 = SubResource(\"TileSetAtlasSource_gmax7\")\nsources/3 = SubResource(\"TileSetAtlasSource_512a0\")\npattern_0 = SubResource(\"TileMapPattern_d2fx0\")\npattern_1 = SubResource(\"TileMapPattern_qfbjk\")\npattern_2 = SubResource(\"TileMapPattern_vk3cr\")\npattern_3 = SubResource(\"TileMapPattern_xos4k\")\npattern_4 = SubResource(\"TileMapPattern_v4ns7\")\npattern_5 = SubResource(\"TileMapPattern_g7k4a\")\npattern_6 = SubResource(\"TileMapPattern_fiebi\")\npattern_7 = SubResource(\"TileMapPattern_jl4gk\")\npattern_8 = SubResource(\"TileMapPattern_77y07\")\npattern_9 = SubResource(\"TileMapPattern_1q1ay\")\npattern_10 = SubResource(\"TileMapPattern_ek0n5\")\npattern_11 = SubResource(\"TileMapPattern_h6mhp\")\npattern_12 = SubResource(\"TileMapPattern_oa6ak\")\npattern_13 = SubResource(\"TileMapPattern_42qrd\")\npattern_14 = SubResource(\"TileMapPattern_ijasj\")\npattern_15 = SubResource(\"TileMapPattern_6nqay\")\npattern_16 = SubResource(\"TileMapPattern_63foq\")\n\n[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_2k3qd\"]\ntexture = ExtResource(\"14_v5trd\")\ntexture_region_size = Vector2i(256, 512)\nuse_texture_padding = false\n0:0/0 = 0\n0:0/0/texture_origin = Vector2i(0, 192)\n\n[sub_resource type=\"TileSet\" id=\"TileSet_dc62b\"]\ntile_shape = 1\ntile_layout = 5\ntile_size = Vector2i(256, 128)\nsources/1 = SubResource(\"TileSetAtlasSource_2k3qd\")\n\n[node name=\"MapSmall\" type=\"Node2D\" node_paths=PackedStringArray(\"_camera_limits\", \"_ground_indicator_map\")]\ny_sort_enabled = true\nscript = ExtResource(\"1_icbek\")\n_camera_limits = NodePath(\"CameraLimits\")\n_ground_indicator_map = NodePath(\"GroundIndicatorMap\")\n\n[node name=\"MainTileMap\" type=\"TileMap\" parent=\".\"]\ny_sort_enabled = true\ntile_set = SubResource(\"TileSet_talwn\")\nformat = 2\nlayer_0/name = \"lvl1-flat\"\nlayer_0/y_sort_enabled = true\nlayer_0/tile_data = PackedInt32Array(-1507339, 262145, 1, -1441803, 262145, 1, -1310731, 262145, 1, -1245195, 262145, 1, -1179659, 262145, 6, -1114123, 262145, 6, -1048587, 262145, 1, -983051, 262145, 1, -917515, 327681, 2, -851979, 393217, 2, -786443, 262145, 1, -720907, 262145, 1, -655371, 262145, 1, -589835, 262145, 1, -524299, 262145, 1, -458763, 262145, 1, -393227, 262145, 1, -327691, 262145, 1, -262155, 262145, 1, -196619, 262145, 1, -131083, 327681, 3, -1638410, 393217, 6, -1572874, 393217, 6, -1507338, 327681, 6, -1441802, 458753, 6, -1376266, 393217, 6, -1310730, 262145, 6, -1245194, 65537, 0, -1179658, 196609, 5, -1114122, 262145, 6, -1048586, 131073, 6, -983050, 458753, 6, -720906, 196609, 0, -655370, 65537, 0, -589834, 458753, 4, -524298, 1, 0, -458762, 327681, 6, -393226, 393217, 6, -327690, 327681, 6, -262154, 262145, 6, -196618, 458753, 6, -131082, 327681, 1, -1638409, 262145, 6, -1572873, 458753, 6, -1507337, 327681, 6, -1441801, 458753, 6, -1376265, 393217, 6, -1310729, 327681, 6, -1245193, 131073, 6, -1114121, 262145, 6, -1048585, 393217, 6, -983049, 262145, 6, -917513, 262145, 6, -851977, 458753, 6, -786441, 262145, 6, -720905, 262145, 6, -655369, 1, 6, -589833, 1, 1, -524297, 131073, 4, -458761, 262145, 6, -393225, 262145, 6, -327689, 393217, 6, -262153, 262145, 6, -196617, 458753, 6, -131081, 327681, 1, -1507336, 458753, 1, -1441800, 458753, 1, -1376264, 458753, 1, -1310728, 458753, 1, -1245192, 458753, 1, -1179656, 458753, 1, -1114120, 458753, 1, -1048584, 458753, 1, -983048, 458753, 1, -524296, 458753, 1, -458760, 458753, 1, -393224, 458753, 1, -262152, 393217, 6, -196616, 327681, 6, -131080, 327681, 1, -327687, 393217, 1, -262151, 327681, 6, -196615, 327681, 6, -131079, 327681, 1, 196601, 327681, 5, 262137, 131073, 0, 327673, 131073, 0, 393209, 131073, 0, 458745, 131073, 0, 589817, 65537, 2, 655353, 327681, 3, 720889, 131073, 0, 786425, 131073, 0, 851961, 131073, 0, 917497, 327681, 3, -327686, 393217, 1, -262150, 262145, 6, -196614, 262145, 6, -131078, 327681, 1, 196602, 393217, 1, 327674, 262145, 6, 458746, 393217, 6, 524282, 262145, 2, 589818, 262145, 0, 655354, 262145, 0, 720890, 262145, 6, 786426, 393217, 6, 851962, 393217, 6, 917498, 327681, 1, -327685, 393217, 1, -262149, 327681, 6, -196613, 327681, 6, -131077, 327681, 1, 196603, 393217, 1, 262139, 458753, 6, 524283, 327681, 6, 589819, 1, 6, 655355, 393217, 6, 720891, 327681, 6, 786427, 262145, 6, 851963, 458753, 6, 917499, 327681, 1, -327684, 393217, 1, -196612, 458753, 6, -131076, 327681, 1, 196604, 393217, 1, 393212, 65537, 4, 458748, 458753, 1, 524284, 458753, 1, 589820, 458753, 1, 655356, 458753, 1, 720892, 196609, 4, 786428, 262145, 6, 851964, 458753, 6, 917500, 327681, 1, -1179651, 327681, 3, -1114115, 262145, 1, -1048579, 262145, 1, -983043, 262145, 1, -917507, 262145, 1, -786435, 262145, 1, -720899, 458753, 4, -655363, 327681, 5, -589827, 196609, 2, -524291, 262145, 5, -458755, 131073, 0, -393219, 262145, 1, -262147, 327681, 6, -196611, 458753, 6, -131075, 327681, 1, 196605, 393217, 1, 262141, 327681, 6, 393213, 327681, 1, 720893, 393217, 1, 786429, 393217, 6, 851965, 393217, 6, 917501, 327681, 1, -1179650, 393217, 1, -1114114, 393217, 6, -1048578, 393217, 6, -983042, 458753, 6, -917506, 393217, 6, -851970, 458753, 6, -786434, 262145, 6, -720898, 1, 1, -655362, 1, 1, -589826, 1, 1, -524290, 1, 1, -458754, 262145, 6, -393218, 393217, 6, -327682, 327681, 6, -262146, 393217, 6, -196610, 458753, 6, -131074, 327681, 1, 196606, 393217, 1, 393214, 327681, 1, 720894, 393217, 1, 786430, 327681, 6, 851966, 393217, 6, 917502, 262145, 5, -1179649, 393217, 1, -1114113, 327681, 6, -1048577, 262145, 6, -983041, 327681, 6, -917505, 393217, 6, -851969, 458753, 6, -786433, 458753, 6, -720897, 262145, 6, -655361, 458753, 6, -589825, 262145, 6, -524289, 327681, 6, -458753, 393217, 6, -393217, 327681, 6, -327681, 262145, 6, -262145, 393217, 6, -196609, 458753, 6, -131073, 327681, 1, 196607, 393217, 1, 262143, 393217, 6, 393215, 327681, 1, 720895, 393217, 1, 786431, 327681, 6, 851967, 262145, 6, 917503, 262145, 5, -1245184, 393217, 1, -1179648, 262145, 6, -1114112, 262145, 6, -1048576, 65537, 4, -983040, 458753, 1, -917504, 458753, 1, -851968, 458753, 1, -786432, 458753, 1, -720896, 458753, 1, -655360, 458753, 1, -589824, 458753, 1, -524288, 458753, 1, -458752, 458753, 1, -393216, 458753, 1, -327680, 458753, 1, -262144, 458753, 1, -196608, 327681, 3, 131072, 393217, 1, 327680, 327681, 1, 655360, 393217, 1, 720896, 393217, 6, 786432, 262145, 6, 851968, 327681, 1, -1245183, 393217, 1, -1179647, 327681, 6, -1114111, 327681, 6, -1048575, 327681, 1, 131073, 393217, 1, 196609, 262145, 6, 327681, 327681, 1, 655361, 393217, 1, 720897, 393217, 6, 786433, 458753, 6, 851969, 327681, 1, -1245182, 393217, 1, -1179646, 393217, 6, -1114110, 327681, 6, -1048574, 327681, 1, 131074, 393217, 1, 196610, 262145, 6, 327682, 327681, 1, 655362, 393217, 1, 720898, 327681, 6, 786434, 458753, 6, 851970, 327681, 1, -1245181, 393217, 1, -1179645, 458753, 6, -1048573, 327681, 1, 131075, 393217, 1, -1245180, 393217, 1, -1048572, 327681, 1, 131076, 393217, 1, 196612, 393217, 6, 327684, 327681, 1, 655364, 393217, 1, 720900, 262145, 6, 786436, 458753, 6, 851972, 327681, 1, -1245179, 393217, 1, -1048571, 1, 4, -983035, 262145, 1, -917499, 262145, 1, -851963, 262145, 1, -786427, 262145, 1, -720891, 262145, 0, -655355, 393217, 2, -589819, 327681, 2, -524283, 262145, 2, -458747, 458753, 2, -393211, 131073, 2, -327675, 262145, 1, -262139, 262145, 1, -196603, 262145, 1, -131067, 262145, 1, -65531, 262145, 1, 5, 262145, 1, 65541, 262145, 1, 131077, 131073, 4, 262149, 393217, 6, 327685, 327681, 1, 655365, 393217, 1, 720901, 262145, 6, 786437, 393217, 6, 1245189, 131073, 0, 1310725, 262145, 1, 1376261, 262145, 1, 1441797, 262145, 1, 1507333, 262145, 1, 1572869, 262145, 1, 1638405, 262145, 0, 1703941, 262145, 1, -1245178, 393217, 1, -1179642, 327681, 6, -1114106, 458753, 6, -917498, 458753, 6, -720890, 327681, 6, -589818, 327681, 6, -524282, 393217, 6, -458746, 393217, 6, -65530, 262145, 6, 327686, 327681, 1, 655366, 393217, 1, 720902, 458753, 6, 786438, 458753, 6, 851974, 262145, 6, 917510, 262145, 6, 983046, 262145, 6, 1048582, 327681, 6, 1114118, 458753, 6, 1179654, 262145, 6, 1245190, 458753, 6, 1310726, 327681, 6, 1376262, 393217, 6, 1441798, 327681, 6, 1507334, 458753, 6, 1572870, 458753, 6, 1638406, 262145, 6, 1703942, 458753, 6, -1245177, 393217, 1, -917497, 458753, 6, -524281, 458753, 6, -458745, 458753, 6, -262137, 131073, 6, 262151, 393217, 6, 327687, 327681, 1, 655367, 393217, 1, 720903, 393217, 6, 786439, 458753, 6, 851975, 393217, 6, 917511, 458753, 6, 983047, 458753, 6, 1048583, 393217, 6, 1114119, 131073, 6, 1179655, 393217, 6, 1245191, 262145, 6, 1310727, 458753, 6, 1376263, 262145, 6, 1441799, 393217, 6, 1507335, 327681, 6, 1572871, 458753, 6, 1638407, 262145, 6, 1703943, 262145, 6, -1245176, 393217, 1, -1179640, 393217, 6, -1114104, 458753, 6, -1048568, 65537, 4, -983032, 458753, 1, -917496, 458753, 1, -851960, 458753, 1, -786424, 458753, 1, -720888, 458753, 1, -655352, 458753, 1, -589816, 458753, 1, -524280, 458753, 1, -458744, 458753, 1, -393208, 458753, 1, -327672, 458753, 1, -262136, 458753, 1, -196600, 458753, 1, -131064, 458753, 1, -65528, 458753, 1, 8, 458753, 1, 65544, 458753, 1, 131080, 196609, 5, 196616, 327681, 6, 262152, 262145, 6, 327688, 327681, 1, 655368, 393217, 1, 720904, 393217, 6, 786440, 262145, 6, 851976, 65537, 5, 917512, 458753, 1, 983048, 458753, 1, 1048584, 458753, 1, 1114120, 458753, 1, 1179656, 458753, 1, 1245192, 458753, 1, 1310728, 458753, 1, 1376264, 458753, 1, 1441800, 458753, 1, 1507336, 458753, 1, 1572872, 458753, 1, 1638408, 458753, 1, 1703944, 458753, 1, -1769481, 131073, 5, -1703945, 393217, 6, -1376267, 262145, 1, -262148, 327681, 6, 851973, 1, 4, 917509, 262145, 1, 983045, 262145, 1, 1048581, 262145, 1, 1114117, 262145, 1, -851971, 262145, 1, 851971, 327681, 1, 786435, 393217, 6, 720899, 262145, 6, 655363, 393217, 1, 327683, 327681, 1, -786442, 458753, 6, -851978, 327681, 6, -917514, 131073, 4, -1638408, 458753, 1, -1703944, 458753, 1, -1769480, 458753, 1, -1572872, 458753, 1, -1703946, 458753, 6, -1769482, 393217, 6, -1835018, 393217, 6, -1900554, 327681, 6, -1966090, 393217, 6, -2031626, 393217, 6, -2097162, 327681, 6, -2162698, 262145, 6, -2228234, 458753, 6, -2293770, 393217, 6, -2228235, 262145, 1, -2162699, 262145, 1, -2097163, 262145, 1, -2031627, 262145, 1, -1966091, 262145, 1, -1900555, 262145, 1, -1835019, 262145, 1, -1769483, 262145, 1, -1703947, 262145, 1, -1638411, 262145, 1, -1835017, 327681, 6, -1900553, 458753, 6, -1966089, 458753, 6, -2031625, 327681, 6, -2097161, 262145, 6, -2162697, 262145, 6, -2228233, 458753, 6, -2293769, 393217, 6, -2359305, 393217, 6, -1572875, 262145, 1, -1835016, 458753, 1, -1900552, 458753, 1, -1966088, 458753, 1, -2031624, 458753, 1, -2097160, 458753, 1, -2162696, 458753, 1, -2228232, 458753, 1, -2293768, 458753, 1, -2359304, 458753, 1, -1114109, 262145, 6, -1179644, 262145, 6, -1114108, 262145, 6, -1179643, 458753, 6, -1114107, 458753, 6, -1179641, 262145, 6, -1114105, 262145, 6, -1048570, 327681, 6, -983034, 327681, 6, -851962, 262145, 6, -786426, 458753, 6, -655354, 327681, 6, -393210, 458753, 6, -327674, 262145, 6, -262138, 393217, 6, -196602, 458753, 6, -131066, 327681, 6, 6, 262145, 6, 65542, 393217, 6, 131078, 327681, 6, 196614, 393217, 6, 262150, 458753, 6, -1048569, 393217, 6, -983033, 327681, 6, -851961, 458753, 6, -786425, 262145, 6, -720889, 458753, 6, -655353, 458753, 6, -589817, 327681, 6, -393209, 458753, 6, -327673, 458753, 6, -196601, 327681, 6, -131065, 262145, 6, -65529, 327681, 6, 7, 327681, 6, 65543, 327681, 6, 131079, 393217, 6, 196615, 393217, 6, 262138, 262145, 6, 327675, 458753, 6, 262140, 458753, 6, 327676, 458753, 6, 327677, 393217, 6, 262142, 262145, 6, 327678, 262145, 6, 327679, 458753, 6, 196608, 327681, 6, 262144, 327681, 6, 262145, 393217, 6, 262146, 327681, 6, 196611, 327681, 6, 262147, 458753, 6, 262148, 458753, 6, 196613, 327681, 6, 393210, 262145, 6, 393211, 393217, 6, 458747, 458753, 6, -1048567, 327681, 1, -1048566, 327681, 1, -1048565, 327681, 1, -1048564, 327681, 1, -1245175, 393217, 1, -1179639, 327681, 6, -1114103, 393217, 6, -1245174, 393217, 1, -1179638, 393217, 6, -1114102, 458753, 6, -1245173, 393217, 1, -1179637, 262145, 6, -1114101, 262145, 6, -1245172, 393217, 1, -1179636, 327681, 6, -1114100, 262145, 6, -1048563, 1, 4, -983027, 262145, 3, -917491, 262145, 5, -851955, 262145, 5, -1245171, 393217, 1, -1179635, 458753, 6, -1114099, 393217, 6, -1245170, 393217, 1, -1179634, 262145, 6, -1114098, 262145, 6, -1048562, 327681, 6, -983026, 458753, 6, -917490, 131073, 0, -851954, 1, 1, -1245169, 393217, 1, -1179633, 458753, 6, -1114097, 393217, 6, -1048561, 262145, 6, -983025, 393217, 6, -917489, 262145, 6, -851953, 393217, 6, -1245168, 327681, 3, -1179632, 458753, 1, -1114096, 458753, 1, -1048560, 458753, 1, -983024, 458753, 1, -917488, 458753, 1, -851952, 458753, 1, -786419, 262145, 3, -720883, 262145, 1, -655347, 262145, 1, -589811, 262145, 1, -524275, 262145, 1, -458739, 262145, 1, -393203, 262145, 1, -327667, 262145, 1, -262131, 262145, 1, -786418, 131073, 6, -720882, 393217, 6, -655346, 458753, 6, -589810, 393217, 6, -524274, 393217, 6, -458738, 262145, 6, -393202, 327681, 6, -327666, 262145, 6, -262130, 393217, 6, -786417, 262145, 6, -720881, 393217, 6, -655345, 327681, 6, -589809, 327681, 6, -524273, 262145, 6, -458737, 262145, 6, -393201, 327681, 6, -327665, 458753, 6, -262129, 262145, 6, -786416, 458753, 1, -720880, 458753, 1, -655344, 458753, 1, -589808, 458753, 1, -524272, 458753, 1, -458736, 458753, 1, -393200, 196609, 4, -327664, 327681, 6, -262128, 393217, 6, -196595, 458753, 3, -196594, 327681, 1, -196593, 327681, 1, -196592, 327681, 1, -327663, 327681, 6, -262127, 327681, 6, -196591, 327681, 1, -393199, 393217, 1, -393198, 393217, 1, -327662, 458753, 6, -262126, 458753, 6, -196590, 327681, 1, -393197, 393217, 1, -327661, 458753, 6, -262125, 262145, 6, -196589, 327681, 1, -393196, 393217, 1, -327660, 458753, 6, -262124, 458753, 6, -196588, 327681, 1, -458731, 262145, 1, -393195, 131073, 4, -327659, 393217, 6, -262123, 327681, 6, -196587, 327681, 1, -458730, 393217, 6, -393194, 393217, 6, -327658, 262145, 6, -262122, 327681, 6, -196586, 327681, 1, -458729, 458753, 6, -393193, 327681, 6, -327657, 458753, 6, -262121, 262145, 6, -196585, 327681, 1, -458728, 458753, 1, -393192, 458753, 1, -327656, 458753, 1, -262120, 458753, 1, -196584, 458753, 3, -1638379, 262145, 1, -1572843, 262145, 1, -1507307, 262145, 1, -1441771, 262145, 1, -1376235, 262145, 1, -1310699, 262145, 5, -1179627, 262145, 1, -1114091, 262145, 1, -1048555, 262145, 1, -983019, 262145, 1, -917483, 262145, 0, -851947, 393217, 2, -786411, 327681, 2, -720875, 262145, 2, -655339, 458753, 2, -589803, 131073, 2, -524267, 262145, 1, -1638378, 262145, 6, -1572842, 327681, 6, -1507306, 458753, 6, -1441770, 262145, 6, -1376234, 327681, 6, -1179626, 393217, 6, -1114090, 458753, 6, -1048554, 262145, 6, -983018, 458753, 6, -917482, 327681, 6, -851946, 327681, 6, -786410, 327681, 6, -720874, 393217, 6, -655338, 393217, 6, -589802, 458753, 6, -524266, 262145, 6, -1638377, 262145, 6, -1572841, 458753, 6, -1507305, 262145, 6, -1441769, 262145, 6, -1179625, 327681, 6, -1114089, 393217, 6, -1048553, 262145, 6, -983017, 262145, 6, -917481, 458753, 6, -851945, 458753, 6, -786409, 327681, 6, -720873, 458753, 6, -655337, 458753, 6, -589801, 458753, 6, -524265, 458753, 6, -1638376, 458753, 1, -1572840, 458753, 1, -1507304, 458753, 1, -1441768, 458753, 1, -1376232, 458753, 1, -1310696, 458753, 1, -1245160, 458753, 1, -1179624, 458753, 1, -1114088, 458753, 1, -1048552, 458753, 1, -983016, 458753, 1, -917480, 458753, 1, -851944, 458753, 1, -786408, 458753, 1, -720872, 458753, 1, -655336, 458753, 1, -589800, 458753, 1, -524264, 458753, 1, -2162667, 262145, 1, -2097131, 262145, 1, -2031595, 262145, 1, -1966059, 262145, 1, -1900523, 262145, 1, -1834987, 262145, 1, -1769451, 262145, 1, -1703915, 262145, 1, -2097130, 393217, 6, -2031594, 393217, 6, -1966058, 458753, 6, -1900522, 65537, 0, -1834986, 458753, 0, -1769450, 131073, 6, -1703914, 458753, 6, -2097129, 327681, 6, -2031593, 262145, 6, -1966057, 262145, 6, -1834985, 131073, 5, -1769449, 393217, 6, -1703913, 262145, 6, -1966056, 458753, 1, -1900520, 458753, 1, -1834984, 458753, 1, -1769448, 458753, 1, -1703912, 458753, 1, 131081, 393217, 1, 196617, 393217, 6, 262153, 458753, 6, 327689, 327681, 1, 131082, 393217, 1, 196618, 393217, 6, 262154, 458753, 6, 327690, 327681, 1, 131083, 393217, 1, 196619, 393217, 6, 262155, 327681, 6, 327691, 327681, 1, 131084, 393217, 1, 196620, 458753, 6, 262156, 327681, 6, 327692, 327681, 1, 131085, 393217, 1, 196621, 393217, 6, 262157, 262145, 6, 327693, 327681, 1, 131086, 393217, 1, 196622, 393217, 6, 262158, 327681, 6, 327694, 327681, 1, 131087, 393217, 1, 196623, 327681, 6, 262159, 393217, 6, 327695, 327681, 1, 131088, 393217, 1, 196624, 393217, 6, 262160, 393217, 6, 327696, 327681, 1, 131089, 393217, 1, 196625, 393217, 6, 262161, 393217, 6, 327697, 1, 4, 131090, 393217, 1, 196626, 393217, 6, 262162, 262145, 6, 327698, 262145, 6, 131091, 393217, 1, 196627, 327681, 6, 262163, 393217, 6, 327699, 458753, 6, 131092, 327681, 3, 196628, 458753, 1, 262164, 458753, 1, 327700, 458753, 1, 655369, 393217, 1, 720905, 458753, 6, 786441, 393217, 6, 851977, 327681, 1, 655370, 393217, 1, 720906, 458753, 6, 786442, 262145, 6, 851978, 327681, 1, 655371, 393217, 1, 720907, 327681, 6, 786443, 458753, 6, 851979, 327681, 1, 655372, 393217, 1, 720908, 458753, 6, 786444, 393217, 6, 851980, 327681, 1, 655373, 393217, 1, 720909, 327681, 6, 786445, 327681, 6, 851981, 327681, 1, 655374, 393217, 1, 720910, 458753, 6, 786446, 393217, 6, 851982, 327681, 1, 655375, 393217, 1, 720911, 393217, 6, 786447, 393217, 6, 851983, 327681, 1, 655376, 393217, 1, 720912, 393217, 6, 786448, 393217, 6, 851984, 327681, 1, 655377, 393217, 0, 851985, 327681, 1, 393236, 458753, 1, 524308, 458753, 1, 589844, 458753, 1, 655380, 458753, 1, 720916, 458753, 1, 786452, 458753, 1, 851988, 262145, 3, -917512, 458753, 1, -851976, 458753, 1, -786440, 458753, 1, -720904, 458753, 1, -655368, 458753, 1, -589832, 458753, 1, 655378, 393217, 6, 720914, 458753, 6, 786450, 393217, 6, 851986, 327681, 1, 655379, 458753, 6, 720915, 327681, 6, 786451, 393217, 6, 851987, 327681, 1, 458769, 262145, 5, 524305, 262145, 5, 458770, 1, 1, 524306, 1, 1, 589842, 131073, 0, 393235, 458753, 6, 458771, 458753, 6, 524307, 131073, 6, 589843, 393217, 6, 393233, 262145, 1, 589841, 196609, 2, 720913, 327681, 6, 393234, 262145, 6, 458772, 458753, 1, -327688, 196609, 4, -327683, 131073, 4, -2293771, 262145, 1, -2359307, 262145, 1, -2359306, 393217, 6, 786449, 393217, 6, 524281, 65537, 4, 524280, 1, 2, -1572852, 131073, 2, -1572851, 131073, 2, -1638387, 131073, 2, -1638388, 131073, 2, -1179661, 393217, 6, -1245197, 393217, 6, -1245196, 1, 6, -1114125, 327681, 6, -1114124, 196609, 6, -1179660, 327681, 6, -1310732, 458753, 6, -1310733, 458753, 6, -1310734, 196609, 6, -1245198, 131073, 6, -1179662, 262145, 6, -1114126, 1, 6, -1310698, 327681, 4, -1245162, 1, 0, -1245161, 393217, 6, -1310697, 1, 6, -1245163, 262145, 2, -1245164, 327681, 5, -1310700, 327681, 5, -1179628, 327681, 5, -1376236, 327681, 5, -1900521, 1, 1, -1179657, 327681, 6, 1179653, 327681, 5, 1966084, 327681, 3, 2031620, 131073, 5, 2097156, 327681, 6, 2162692, 327681, 6, 2228228, 1, 5, 2293764, 393217, 3, 1966085, 131073, 5, 2031621, 327681, 6, 2097157, 393217, 6, 2162693, 262145, 6, 2228229, 393217, 6, 2293765, 1, 5, 1966086, 393217, 6, 2031622, 327681, 6, 2097158, 393217, 6, 2162694, 393217, 6, 2228230, 458753, 6, 2293766, 458753, 6, 1966087, 262145, 6, 2031623, 458753, 6, 2097159, 327681, 6, 2162695, 327681, 6, 2228231, 327681, 6, 2293767, 327681, 6, 1966088, 196609, 5, 2031624, 458753, 6, 2097160, 458753, 6, 2162696, 327681, 6, 2228232, 458753, 6, 2293768, 65537, 5, 1966089, 458753, 3, 2031625, 458753, 1, 2097161, 458753, 6, 2162697, 458753, 6, 2228233, 65537, 4, 2293769, 393217, 3, 1769478, 327681, 6, 1769479, 393217, 6, 1835015, 458753, 6, 1900551, 327681, 6, 1900550, 262145, 6, 1835014, 327681, 6, 1769477, 262145, 1, 1835013, 262145, 1, 1900549, 262145, 1, 1769480, 458753, 1, 1835016, 458753, 1, 1900552, 458753, 1, 2359301, 262145, 1, 2424837, 262145, 1, 2490373, 262145, 1, 2555909, 262145, 1, 2621445, 262145, 1, 2686981, 262145, 1, 2752517, 262145, 1, 2818053, 262145, 1, 2883589, 262145, 1, 2949125, 262145, 1, 3014661, 262145, 1, 3080197, 262145, 1, 2359302, 262145, 6, 2424838, 262145, 6, 2490374, 327681, 6, 2555910, 458753, 6, 2621446, 262145, 6, 2686982, 458753, 6, 2752518, 327681, 6, 2818054, 393217, 6, 2883590, 327681, 6, 2949126, 458753, 6, 3014662, 458753, 6, 3080198, 262145, 6, 3145734, 458753, 6, 3211270, 327681, 6, 2359303, 327681, 6, 2424839, 458753, 6, 2490375, 393217, 6, 2555911, 458753, 6, 2621447, 393217, 6, 2686983, 262145, 6, 2752519, 458753, 6, 2818055, 262145, 6, 2883591, 393217, 6, 2949127, 327681, 6, 3014663, 458753, 6, 3080199, 262145, 6, 3145735, 196609, 6, 3211271, 393217, 6, 3276807, 458753, 6, 2359304, 458753, 1, 2424840, 458753, 1, 2490376, 458753, 1, 2555912, 458753, 1, 2621448, 458753, 1, 2686984, 458753, 1, 2752520, 458753, 1, 2818056, 458753, 1, 2883592, 458753, 1, 2949128, 458753, 1, 3014664, 458753, 1, 3080200, 458753, 1, 3145736, 458753, 1, 3211272, 458753, 1, 3276808, 458753, 1, 2031626, 327681, 5, 2097162, 393217, 6, 2162698, 393217, 6, 2228234, 327681, 1, 2031627, 393217, 1, 2097163, 262145, 6, 2162699, 262145, 6, 2228235, 327681, 1, 2031628, 393217, 1, 2097164, 458753, 6, 2162700, 458753, 6, 2228236, 327681, 1, 2031629, 393217, 1, 2097165, 458753, 6, 2162701, 458753, 6, 2228237, 327681, 1, 2031630, 393217, 1, 2097166, 327681, 6, 2162702, 393217, 6, 2228238, 327681, 1, 2031631, 393217, 1, 2097167, 262145, 6, 2162703, 262145, 6, 2228239, 327681, 1, 2031632, 393217, 1, 2097168, 393217, 6, 2162704, 458753, 6, 2228240, 327681, 1, 2031633, 393217, 1, 2097169, 327681, 6, 2162705, 327681, 6, 2228241, 327681, 1, 2031634, 393217, 1, 2097170, 262145, 6, 2162706, 393217, 6, 2228242, 327681, 1, 2031635, 393217, 1, 2097171, 262145, 6, 2162707, 327681, 6, 2228243, 327681, 1, 2031636, 393217, 1, 2097172, 327681, 6, 2162708, 458753, 6, 2228244, 327681, 1, 2031637, 393217, 1, 2097173, 393217, 6, 2162709, 458753, 6, 2228245, 327681, 1, 2031638, 393217, 1, 2097174, 262145, 6, 2162710, 131073, 6, 2228246, 327681, 1, 2031639, 393217, 1, 2097175, 458753, 6, 2162711, 327681, 6, 2228247, 327681, 1, 2031640, 393217, 1, 2097176, 458753, 6, 2162712, 458753, 6, 2228248, 327681, 1, 2097141, 393217, 1, 2097142, 393217, 1, 2162678, 327681, 6, 2097143, 393217, 1, 2162679, 65537, 6, 2228215, 458753, 6, 2097144, 393217, 1, 2162680, 393217, 6, 2228216, 262145, 6, 2293752, 327681, 1, 2097145, 393217, 1, 2162681, 262145, 6, 2228217, 327681, 6, 2293753, 327681, 1, 2097146, 393217, 1, 2162682, 458753, 6, 2228218, 327681, 6, 2293754, 327681, 1, 2097147, 393217, 1, 2162683, 327681, 6, 2228219, 393217, 6, 2293755, 327681, 1, 2097148, 393217, 1, 2162684, 327681, 6, 2228220, 458753, 6, 2293756, 327681, 1, 2097149, 393217, 1, 2162685, 393217, 6, 2228221, 262145, 6, 2293757, 327681, 1, 2097150, 393217, 1, 2162686, 393217, 6, 2228222, 393217, 6, 2293758, 327681, 1, 2097151, 393217, 1, 2162687, 458753, 6, 2228223, 393217, 6, 2293759, 327681, 1, 2031616, 393217, 1, 2097152, 262145, 6, 2162688, 393217, 6, 2228224, 327681, 1, 2031617, 393217, 1, 2097153, 262145, 6, 2162689, 458753, 6, 2228225, 327681, 1, 2031618, 393217, 1, 2097154, 327681, 6, 2162690, 393217, 6, 2228226, 327681, 1, 2031619, 393217, 1, 2097155, 458753, 6, 2162691, 327681, 6, 2228227, 327681, 1, 1310704, 393217, 1, 1376240, 458753, 6, 1441776, 393217, 6, 1507312, 1, 4, 1572848, 262145, 1, 1638384, 131073, 0, 1703920, 262145, 1, 1769456, 262145, 1, 1310705, 393217, 1, 1376241, 458753, 6, 1441777, 393217, 6, 1507313, 393217, 6, 1572849, 327681, 6, 1638385, 262145, 6, 1703921, 458753, 6, 1769457, 393217, 6, 1834993, 262145, 6, 1310706, 393217, 1, 1376242, 458753, 6, 1441778, 458753, 6, 1507314, 393217, 6, 1572850, 393217, 6, 1638386, 393217, 6, 1703922, 262145, 6, 1769458, 262145, 6, 1834994, 458753, 6, 1900530, 327681, 6, 1310707, 393217, 3, 1376243, 458753, 1, 1441779, 458753, 1, 1507315, 458753, 1, 1572851, 458753, 1, 1638387, 458753, 1, 1703923, 458753, 1, 1769459, 458753, 1, 1834995, 458753, 1, 1900531, 458753, 1, 1966067, 458753, 1, 1245214, 393217, 1, 1310750, 262145, 6, 1376286, 458753, 6, 1441822, 327681, 1, 1245215, 393217, 1, 1310751, 262145, 6, 1376287, 131073, 6, 1441823, 327681, 1, 1245216, 393217, 1, 1310752, 393217, 6, 1376288, 327681, 6, 1441824, 327681, 1, 1245217, 393217, 1, 1310753, 262145, 6, 1376289, 393217, 6, 1441825, 327681, 1, 1245218, 393217, 1, 1310754, 458753, 6, 1376290, 327681, 6, 1441826, 1, 5, 1245219, 393217, 1, 1310755, 393217, 6, 1376291, 327681, 6, 1441827, 458753, 6, 1245220, 393217, 1, 1310756, 262145, 6, 1376292, 458753, 6, 1441828, 393217, 6, 1245221, 393217, 3, 1310757, 458753, 1, 1376293, 458753, 1, 1441829, 458753, 1, 2031641, 393217, 1, 2097177, 262145, 6, 2162713, 393217, 6, 2228249, 327681, 1, 1245210, 393217, 3, 1310746, 262145, 1, 1376282, 262145, 1, 1441818, 262145, 1, 1507354, 262145, 1, 1572890, 131073, 0, 1638426, 262145, 1, 1703962, 262145, 1, 1769498, 262145, 1, 1835034, 262145, 1, 1900570, 262145, 1, 1966106, 262145, 0, 2031642, 131073, 5, 2097178, 262145, 6, 2162714, 393217, 6, 2228250, 1, 5, 2293786, 327681, 5, 2359322, 131073, 0, 2424858, 262145, 1, 2490394, 262145, 1, 2555930, 262145, 1, 2621466, 262145, 1, 2687002, 262145, 1, 1245211, 393217, 1, 1310747, 262145, 6, 1376283, 262145, 6, 1441819, 458753, 6, 1507355, 262145, 6, 1572891, 262145, 6, 1638427, 262145, 6, 1703963, 262145, 6, 1769499, 262145, 6, 1835035, 262145, 6, 1900571, 327681, 6, 1966107, 327681, 6, 2031643, 262145, 6, 2097179, 262145, 6, 2162715, 327681, 6, 2228251, 327681, 6, 2293787, 458753, 6, 2359323, 327681, 6, 2424859, 393217, 6, 2490395, 393217, 6, 2555931, 393217, 6, 2621467, 327681, 6, 2687003, 393217, 6, 1245212, 393217, 1, 1310748, 458753, 6, 1376284, 262145, 6, 1441820, 262145, 6, 1507356, 458753, 6, 1572892, 458753, 6, 1638428, 327681, 6, 1703964, 262145, 6, 1769500, 327681, 6, 1835036, 327681, 6, 1900572, 327681, 6, 1966108, 458753, 6, 2031644, 458753, 6, 2097180, 327681, 6, 2162716, 393217, 6, 2228252, 262145, 6, 2293788, 458753, 6, 2359324, 393217, 6, 2424860, 327681, 6, 2490396, 458753, 6, 2555932, 393217, 6, 2621468, 393217, 6, 2687004, 262145, 6, 1245213, 393217, 1, 1310749, 458753, 6, 1376285, 458753, 6, 1441821, 65537, 5, 1507357, 458753, 1, 1572893, 458753, 1, 1638429, 458753, 1, 1703965, 458753, 1, 1769501, 458753, 1, 1835037, 458753, 1, 1900573, 458753, 1, 1966109, 458753, 1, 2031645, 458753, 1, 2097181, 458753, 1, 2162717, 458753, 1, 2228253, 458753, 1, 2293789, 458753, 1, 2359325, 458753, 1, 2424861, 458753, 1, 2490397, 458753, 1, 2555933, 458753, 1, 2621469, 458753, 1, 2687005, 458753, 1, 1507362, 262145, 1, 1572898, 131073, 0, 1638434, 262145, 1, 1703970, 262145, 1, 1769506, 262145, 1, 1835042, 262145, 1, 1900578, 262145, 1, 1966114, 262145, 0, 2031650, 262145, 1, 2097186, 262145, 1, 2162722, 262145, 1, 2228258, 262145, 1, 1507363, 393217, 6, 1572899, 458753, 6, 1638435, 393217, 6, 1703971, 327681, 6, 1769507, 327681, 6, 1835043, 458753, 6, 1900579, 327681, 6, 1966115, 393217, 6, 2031651, 327681, 6, 2097187, 262145, 6, 2162723, 262145, 6, 1507364, 327681, 6, 1572900, 327681, 6, 1638436, 393217, 6, 1703972, 393217, 6, 1769508, 458753, 6, 1835044, 393217, 6, 1900580, 458753, 6, 1966116, 262145, 6, 2031652, 327681, 6, 2097188, 458753, 6, 2162724, 327681, 6, 1507365, 458753, 1, 1572901, 458753, 1, 1638437, 458753, 1, 1703973, 458753, 1, 1769509, 458753, 1, 1835045, 458753, 1, 1900581, 458753, 1, 1966117, 458753, 1, 2031653, 196609, 4, 2097189, 458753, 6, 1310699, 393217, 1, 1310700, 393217, 1, 1376236, 458753, 6, 1441772, 262145, 6, 1310701, 393217, 1, 1376237, 262145, 6, 1441773, 393217, 6, 1507309, 327681, 1, 1310702, 393217, 1, 1376238, 393217, 6, 1441774, 1, 6, 1507310, 327681, 1, 1310703, 393217, 1, 1376239, 458753, 6, 1441775, 393217, 6, 1507311, 327681, 1, 2031654, 393217, 1, 2097190, 393217, 6, 2031655, 393217, 1, 2031656, 393217, 1, 983082, 327681, 5, 1048618, 262145, 1, 1114154, 262145, 1, 1179690, 131073, 0, 1245226, 327681, 5, 1310762, 131073, 0, 1376298, 262145, 1, 1441834, 262145, 1, 983083, 393217, 1, 1114155, 458753, 6, 1179691, 327681, 6, 1245227, 327681, 6, 1310763, 262145, 6, 1376299, 262145, 6, 1441835, 262145, 6, 983084, 393217, 1, 1114156, 393217, 6, 1179692, 327681, 6, 1245228, 327681, 6, 1310764, 393217, 6, 1376300, 458753, 6, 1441836, 393217, 6, 983085, 393217, 1, 1114157, 458753, 6, 1179693, 65537, 4, 1245229, 458753, 1, 1310765, 458753, 1, 1376301, 458753, 1, 1441837, 458753, 1, 983086, 393217, 1, 1114158, 393217, 6, 1179694, 327681, 1, 983087, 393217, 1, 1114159, 262145, 6, 1179695, 327681, 1, 983088, 393217, 1, 1114160, 458753, 6, 1179696, 327681, 1, 983089, 393217, 1, 1114161, 327681, 6, 1179697, 327681, 1, 983090, 393217, 1, 1114162, 393217, 6, 1179698, 327681, 1, 1507374, 393217, 1, 1572910, 327681, 6, 1507375, 393217, 1, 1507370, 327681, 5, 1572906, 262145, 1, 1638442, 262145, 1, 1703978, 393217, 3, 1507371, 458753, 6, 1572907, 393217, 6, 1638443, 393217, 6, 1703979, 327681, 1, 1507372, 393217, 6, 1572908, 393217, 6, 1638444, 393217, 6, 1507373, 196609, 4, 1572909, 458753, 6, -1376233, 262145, 6, -2162666, 327681, 6, -2162665, 327681, 6, -2162664, 458753, 1, -2097128, 458753, 1, -2031592, 458753, 1, 1048619, 393217, 6, 1048620, 327681, 6, 1048621, 458753, 6, 1048622, 327681, 6, 1048623, 262145, 6, 1048624, 393217, 6, 1048625, 327681, 6, 1048626, 262145, 6)\nlayer_1/name = \"lvl1-tall\"\nlayer_1/y_sort_enabled = true\nlayer_1/z_index = 10\nlayer_1/tile_data = PackedInt32Array(-589832, 131081, 0, -589836, 6, 0, -655372, 6, 0, -720908, 6, 0, -786444, 6, 0, -851980, 6, 0, -917516, 6, 0, -983052, 6, 0, -1048588, 6, 0, -1179660, 131075, 2, -1310732, 6, 0, -1376268, 6, 0, -1441804, 6, 0, -1507340, 6, 0, -1572876, 6, 0, -1638412, 6, 0, -1703948, 6, 0, -1769484, 6, 0, -1835020, 6, 0, -1900556, 6, 0, -1966092, 6, 0, -2031628, 6, 0, -2097164, 6, 0, -2162700, 6, 0, -2228236, 6, 0, -1114124, 6, 0, -1048587, 262153, 10, -524300, 6, 0, -458764, 6, 0, -393228, 6, 0, -327692, 6, 0, -262156, 6, 0, -196620, 6, 0, -131084, 6, 0, -1179652, 6, 0, -1114116, 6, 0, -1048580, 6, 0, -983044, 6, 0, -917508, 6, 0, -851972, 6, 0, -786436, 6, 0, -720900, 6, 0, -655364, 6, 0, -589828, 6, 0, -524292, 6, 0, -458756, 6, 0, -983036, 6, 0, -917500, 6, 0, -851964, 6, 0, -786428, 6, 0, -720892, 6, 0, -655356, 6, 0, -589820, 6, 0, -524284, 6, 0, -458748, 6, 0, -393212, 6, 0, -327676, 6, 0, -262140, 6, 0, -196604, 6, 0, -131068, 6, 0, -65532, 6, 0, 4, 6, 0, 196600, 6, 0, 262136, 6, 0, 327672, 6, 0, 393208, 6, 0, 458744, 6, 0, 524280, 6, 0, 589816, 6, 0, 655352, 6, 0, 720888, 6, 0, 786424, 6, 0, 851960, 6, 0, 917496, 6, 0, 917508, 6, 0, 983044, 6, 0, 1048580, 6, 0, 1114116, 6, 0, 1179652, 6, 0, 1245188, 6, 0, 1310724, 6, 0, 1376260, 6, 0, 1441796, 6, 0, 1507332, 6, 0, 1572868, 6, 0, 1638404, 6, 0, 655357, 65542, 0, 655358, 65542, 0, 655359, 65542, 0, 589824, 65542, 0, 589825, 65542, 0, 589826, 65542, 0, 589827, 65542, 0, 589828, 65542, 0, 589829, 65542, 0, 589830, 65542, 0, 589831, 65542, 0, 589832, 65542, 0, 131065, 65542, 0, 131066, 65542, 0, 131067, 65542, 0, 131068, 65542, 0, 131069, 65542, 0, 131070, 65542, 0, 131071, 65542, 0, 65536, 65542, 0, 65537, 65542, 0, 65538, 65542, 0, 65539, 65542, 0, -1245187, 65542, 0, -1245186, 65542, 0, -1245185, 65542, 0, -1310720, 65542, 0, -1310719, 65542, 0, -1310718, 65542, 0, -1310717, 65542, 0, -1310716, 65542, 0, -1310715, 65542, 0, -1310714, 65542, 0, -1310713, 65542, 0, -1310712, 65542, 0, -393223, 65542, 0, -393222, 65542, 0, -393221, 65542, 0, -393220, 6, 1, -1245188, 6, 1, 65540, 6, 1, 131064, 6, 1, -720904, 196617, 1, -655368, 196617, 1, -786440, 196617, 1, -851976, 196617, 1, -917512, 196617, 2, -1310711, 65542, 0, -1310710, 65542, 0, -1310709, 65542, 0, -1310708, 65542, 0, -1310707, 65542, 0, -1310706, 65542, 0, -1310705, 65542, 0, -1310704, 65542, 0, -458735, 65542, 0, -458734, 65542, 0, -458733, 65542, 0, -458732, 6, 1, -983028, 6, 0, -917492, 6, 0, -851956, 6, 0, -786420, 6, 0, -720884, 6, 0, -655348, 6, 0, -589812, 6, 0, -524276, 6, 0, -458740, 6, 0, -393204, 6, 0, -327668, 6, 0, -262132, 6, 0, -196596, 6, 0, -1507308, 6, 0, -1441772, 6, 0, -1376236, 6, 0, -1310700, 6, 0, -1245164, 6, 0, -1179628, 6, 0, -1114092, 6, 0, -1048556, 6, 0, -983020, 6, 0, -917484, 6, 0, -851948, 6, 0, -786412, 6, 0, -720876, 6, 0, -655340, 6, 0, -589804, 6, 0, -524268, 6, 0, -2162668, 6, 0, -2097132, 6, 0, -2031596, 6, 0, -1966060, 6, 0, -1900524, 6, 0, -1834988, 6, 0, -1769452, 6, 0, -1703916, 6, 0, -1638380, 6, 0, -1572844, 6, 0, 589833, 65542, 0, 589834, 65542, 0, 589835, 65542, 0, 589836, 65542, 0, 589837, 65542, 0, 589838, 65542, 0, 589839, 65542, 0, 589840, 6, 1, 393232, 6, 0, 458768, 6, 0, 524304, 6, 0, 65545, 65542, 0, 65546, 65542, 0, 65547, 65542, 0, 65548, 65542, 0, 65549, 65542, 0, 65550, 65542, 0, 65551, 65542, 0, 65552, 65542, 0, 65553, 65542, 0, 65554, 65542, 0, 65555, 65542, 0, 65556, 65542, 0, -2293772, 6, 0, -2359308, 6, 0, -1376267, 60, 1, -983051, 9, 3, -917515, 393225, 2, -1310731, 65545, 2, -655363, 262153, 11, -524291, 65545, 0, -589824, 327689, 0, -589827, 131122, 2, -1114123, 262153, 2, -1245195, 9, 0, -720899, 60, 0, -458747, 60, 1, -262139, 9, 13, -327675, 262153, 12, -196603, 262153, 12, 196605, 131081, 3, 196604, 131081, 2, 196606, 393225, 2, 196601, 9, 10, -1179650, 393225, 7, 917502, 327689, 11, 917503, 327689, 11, 524305, 262153, 11, 458769, 262153, 11, 655374, 9, 2, 655373, 131081, 3, -196595, 131081, 10, -393197, 393225, 10, -393198, 393225, 10, -196589, 327689, 11, -196590, 327689, 11, -196584, 65536, 1, -1245183, 131132, 1, -917491, 65539, 2, -851955, 65539, 3, 1966083, 6, 1, 2293763, 6, 0, 1900548, 6, 1, 1900553, 65542, 0, 1703940, 6, 0, 1769476, 6, 0, 1835012, 6, 0, 2031604, 65542, 0, 2031605, 65542, 0, 2031606, 65542, 0, 2031607, 65542, 0, 2031608, 65542, 0, 2031609, 65542, 0, 2031610, 65542, 0, 2031611, 65542, 0, 2031612, 65542, 0, 2031613, 65542, 0, 2031614, 65542, 0, 2031615, 65542, 0, 1966080, 65542, 0, 1966081, 65542, 0, 1966082, 65542, 0, 1572847, 6, 0, 1638383, 6, 0, 1703919, 6, 0, 1769455, 6, 0, 1834991, 6, 0, 1245160, 65542, 0, 1245161, 65542, 0, 1245162, 65542, 0, 1245163, 65542, 0, 1245164, 65542, 0, 1245165, 65542, 0, 1245166, 65542, 0, 1245167, 65542, 0, 1245168, 65542, 0, 1245169, 65542, 0, 1245170, 65542, 0, 1245171, 65542, 0, 2359300, 6, 0, 2424836, 6, 0, 2490372, 6, 0, 2555908, 6, 0, 2621444, 6, 0, 2686980, 6, 0, 2752516, 6, 0, 2818052, 6, 0, 2883588, 6, 0, 2949124, 6, 0, 3014660, 6, 0, 3080196, 6, 0, 3145732, 6, 0, 3211268, 6, 0, 3276804, 6, 0, 3342340, 6, 1, 3342345, 65542, 0, 3342346, 65542, 0, 3342347, 65542, 0, 3342348, 65542, 0, 3342349, 65542, 0, 3342350, 65542, 0, 3342351, 65542, 0, 3342352, 65542, 0, 3342355, 65542, 0, 3342356, 65542, 0, 3342339, 65542, 0, 1966090, 65542, 0, 1966091, 65542, 0, 1966092, 65542, 0, 1966093, 65542, 0, 1966094, 65542, 0, 1966095, 65542, 0, 1966096, 65542, 0, 1966097, 65542, 0, 1966098, 65542, 0, 1966099, 65542, 0, 1966100, 65542, 0, 1966101, 65542, 0, 1966102, 65542, 0, 1966103, 65542, 0, 1966104, 65542, 0, 1966105, 6, 1, 1179674, 65542, 0, 1179675, 65542, 0, 1179676, 65542, 0, 1179677, 65542, 0, 1179678, 65542, 0, 1179679, 65542, 0, 1179680, 65542, 0, 1179681, 65542, 0, 1179682, 65542, 0, 1179683, 65542, 0, 1179684, 65542, 0, 1179685, 65542, 0, 2752542, 65542, 0, 2752543, 65542, 0, 1966118, 65542, 0, 1966119, 65542, 0, 1966120, 65542, 0, 1966121, 65542, 0, 1966122, 65542, 0, 1966123, 65542, 0, 917546, 65542, 0, 917547, 65542, 0, 917548, 65542, 0, 917549, 65542, 0, 917550, 65542, 0, 917551, 65542, 0, 917552, 65542, 0, 917553, 65542, 0, 917554, 65542, 0, 917555, 65542, 0, 917556, 65542, 0, 917557, 65542, 0, 917558, 65542, 0, 983081, 6, 0, 1048617, 6, 0, 1114153, 6, 0, 1179689, 6, 0, 1245225, 6, 0, 1310761, 6, 0, 1376297, 6, 0, 1441833, 6, 0, 1507369, 6, 0, 1572905, 6, 0, 1638441, 6, 0, 1703977, 6, 0, 1441838, 65542, 0, 1441839, 65542, 0, 1507361, 6, 0, 1572897, 6, 0, 1638433, 6, 0, 1703969, 6, 0, 1769505, 6, 0, 1835041, 6, 0, 1900577, 6, 0, 1966113, 6, 0, 2031649, 6, 0, 2097185, 6, 0, 2162721, 6, 0, 2228257, 6, 0, 2293793, 6, 0, 2359329, 6, 0, 2424865, 6, 0, 2490401, 6, 0, 2555937, 6, 0, 2621473, 6, 0, 2293785, 6, 0, 2359321, 6, 0, 2424857, 6, 0, 2490393, 6, 0, 2555929, 6, 0, 2621465, 6, 0, 2687001, 6, 0, 2752537, 6, 0, 2818073, 6, 0, 2883609, 6, 0, 2949145, 6, 0, 3014681, 6, 0, 1245209, 6, 0, 1310745, 6, 0, 1376281, 6, 0, 1441817, 6, 0, 1507353, 6, 0, 1572889, 6, 0, 1638425, 6, 0, 1703961, 6, 0, 1769497, 6, 0, 1835033, 6, 0, 1900569, 6, 0)\nlayer_2/name = \"lvl2-flat\"\nlayer_2/y_sort_enabled = true\nlayer_2/y_sort_origin = 128\nlayer_2/z_index = 10\nlayer_2/tile_data = PackedInt32Array(-1835025, 262145, 5, -1769489, 458753, 5, -1703953, 393217, 5, -1638417, 393217, 5, -1572881, 458753, 2, -1507345, 458753, 5, -1376273, 458753, 5, -1310737, 458753, 4, -1245201, 393217, 5, -1179665, 196609, 6, -1114129, 458753, 6, -1048593, 262145, 6, -983057, 327681, 6, -917521, 327681, 5, -851985, 327681, 5, -786449, 262145, 5, -720913, 393217, 5, -655377, 262145, 5, -589841, 327681, 5, -524305, 393217, 5, -1900560, 262145, 5, -1835024, 458753, 2, -1769488, 458753, 5, -1703952, 327681, 5, -1638416, 393217, 5, -1572880, 458753, 2, -1507344, 458753, 5, -1441808, 458753, 5, -1376272, 262145, 5, -1310736, 393217, 5, -1245200, 327681, 4, -1179664, 131073, 6, -1114128, 131073, 6, -1048592, 458753, 6, -786448, 262145, 5, -720912, 393217, 5, -655376, 327681, 5, -589840, 458753, 5, -524304, 262145, 5, -1966095, 327681, 5, -1900559, 458753, 2, -1835023, 327681, 2, -1769487, 327681, 5, -1703951, 393217, 5, -1638415, 393217, 5, -1572879, 327681, 5, -1507343, 327681, 5, -1441807, 458753, 5, -1376271, 262145, 5, -1179663, 458753, 5, -1114127, 458753, 5, -1048591, 327681, 5, -851983, 458753, 5, -786447, 327681, 2, -720911, 458753, 2, -655375, 458753, 2, -589839, 262145, 5, -524303, 458753, 5, -1900558, 327681, 5, -1638414, 262145, 5, -1572878, 393217, 5, -1507342, 393217, 5, -1441806, 327681, 5, -1376270, 262145, 5, -1310734, 327681, 5, -1179662, 458753, 5, -1114126, 458753, 5, -851982, 327681, 2, -786446, 262145, 5, -720910, 393217, 5, -655374, 65537, 2, -589838, 458753, 2, -524302, 262145, 5, -1835021, 458753, 5, -1769485, 458753, 5, -1441805, 327681, 5, -1376269, 327681, 5, -1310733, 393217, 5, -1179661, 393217, 5, -1114125, 393217, 5, -1048589, 458753, 5, -917517, 262145, 5, -851981, 262145, 5, -786445, 458753, 5, -720909, 327681, 5, -655373, 262145, 5, -589837, 262145, 5, -524301, 327681, 5, -1507336, 458753, 5, -1441800, 327681, 5, -1376264, 458753, 5, -1310728, 458753, 4, -1245192, 393217, 5, -1179656, 393217, 5, -1114120, 393217, 5, -1048584, 327681, 5, -983048, 327681, 5, -917512, 393217, 5, -851976, 393217, 5, -786440, 458753, 5, -720904, 327681, 5, -655368, 458753, 5, -589832, 458753, 5, -524296, 262145, 5, -458760, 262145, 5, -1572871, 327681, 5, -1507335, 262145, 5, -1441799, 393217, 5, -1376263, 458753, 5, -1310727, 327681, 4, -1245191, 393217, 2, -1179655, 458753, 5, -1114119, 327681, 2, -1048583, 393217, 5, -983047, 327681, 5, -917511, 393217, 5, -851975, 393217, 5, -786439, 327681, 5, -720903, 393217, 5, -655367, 327681, 5, -589831, 393217, 5, -524295, 327681, 5, -458759, 458753, 5, -1572870, 131073, 6, -1507334, 393217, 5, -1441798, 393217, 6, -1310726, 131073, 2, -1245190, 458753, 5, -1179654, 393217, 5, -1114118, 196609, 0, -1048582, 327681, 5, -983046, 393217, 5, -917510, 327681, 5, -851974, 393217, 5, -786438, 458753, 5, -720902, 327681, 5, -655366, 458753, 5, -589830, 458753, 5, -524294, 262145, 5, -458758, 262145, 5, -1572869, 1, 6, -1507333, 262145, 5, -1441797, 393217, 6, -1310725, 131073, 2, -1245189, 458753, 5, -1179653, 458753, 4, -1114117, 327681, 4, -1048581, 327681, 5, -983045, 262145, 5, -917509, 262145, 5, -851973, 458753, 5, -786437, 327681, 5, -720901, 327681, 5, -655365, 458753, 5, -589829, 458753, 5, -524293, 458753, 5, -458757, 458753, 5, -1900552, 393217, 5, -1835016, 393217, 5, -1769480, 458753, 5, -1703944, 393217, 5, -1638408, 327681, 5, -1900551, 393217, 5, -1835015, 262145, 5, -1638407, 393217, 5, -1966086, 393217, 5, -1900550, 327681, 5, -1835014, 327681, 5, -1638406, 393217, 5, -1572868, 327681, 5, -1507332, 262145, 5, -1441796, 196609, 5, -1310724, 393217, 5, -1572867, 327681, 5, -1507331, 262145, 5, -1441795, 458753, 5, -1376259, 327681, 5, -1310723, 327681, 5, -1572866, 262145, 5, -1507330, 262145, 5, -1441794, 131073, 1, -1376258, 65537, 5, -1310722, 458753, 5, -1572865, 393217, 5, -1507329, 458753, 4, -1441793, 458753, 2, -1376257, 262145, 4, -1310721, 458753, 5, -1966080, 327681, 5, -1900544, 1, 2, -1835008, 262145, 5, -1703936, 327681, 5, -1638400, 458753, 5, -1572864, 262145, 4, -1507328, 458753, 2, -1441792, 327681, 2, -1376256, 393217, 5, -1900543, 458753, 5, -1835007, 262145, 4, -1703935, 327681, 5, -1638399, 393217, 5, -1572863, 262145, 4, -1507327, 393217, 5, -1376255, 327681, 5, -1835006, 393217, 5, -1703934, 327681, 5, -1638398, 458753, 5, -1572862, 393217, 5, -1507326, 458753, 2, -1441790, 327681, 5, -1376254, 262145, 5, -1703933, 327681, 5, -1638397, 262145, 6, -1572861, 262145, 0, -1507325, 196609, 2, -1441789, 458753, 5, -1376253, 458753, 5, -1703932, 458753, 5, -1638396, 393217, 6, -1572860, 458753, 6, -1507324, 65537, 1, -1441788, 393217, 5, -1376252, 393217, 5, -1638395, 262145, 6, -1572859, 327681, 6, -1507323, 65537, 1, -1441787, 393217, 5, -1376251, 458753, 5, -1572858, 393217, 5, -1507322, 262145, 5, -1441786, 327681, 5, -1376250, 393217, 5, -1507321, 327681, 4, -1441785, 262145, 5, -1376249, 327681, 5, -1441784, 393217, 5, -1376248, 327681, 5, -1376247, 393217, 5, 327689, 327681, 5, 393225, 327681, 5, 458761, 262145, 5, 524297, 393217, 5, 917513, 458753, 2, 983049, 458753, 4, 1048585, 458753, 2, 1114121, 458753, 5, 1179657, 458753, 5, 1245193, 262145, 5, 1310729, 458753, 5, 1376265, 458753, 5, 1441801, 262145, 5, 1507337, 327681, 4, 1572873, 393217, 5, 1638409, 262145, 5, 1703945, 262145, 5, 1769481, 262145, 4, 1835017, 393217, 5, 1900553, 262145, 5, 327690, 327681, 5, 393226, 458753, 5, 458762, 393217, 5, 524298, 262145, 5, 917514, 458753, 5, 983050, 458753, 5, 1048586, 393217, 5, 1114122, 393217, 5, 1179658, 327681, 4, 1245194, 262145, 5, 1310730, 327681, 5, 1376266, 393217, 5, 1441802, 458753, 2, 1507338, 458753, 5, 1572874, 262145, 5, 1638410, 262145, 5, 1703946, 458753, 4, 1769482, 1, 2, 1835018, 458753, 4, 1900554, 262145, 5, 327691, 393217, 5, 393227, 458753, 5, 458763, 327681, 5, 524299, 262145, 5, 917515, 458753, 5, 983051, 262145, 4, 1048587, 1, 2, 1114123, 393217, 2, 1179659, 1, 2, 1245195, 393217, 5, 1310731, 458753, 5, 1376267, 327681, 2, 1441803, 327681, 4, 1507339, 458753, 2, 1572875, 393217, 5, 1638411, 262145, 5, 1703947, 458753, 4, 1769483, 393217, 5, 1835019, 458753, 5, 1900555, 327681, 5, 393228, 262145, 5, 458764, 458753, 5, 524300, 458753, 5, 917516, 458753, 2, 983052, 327681, 5, 1048588, 327681, 2, 1114124, 393217, 5, 1179660, 262145, 4, 1245196, 393217, 5, 1310732, 262145, 5, 1376268, 65537, 2, 1441804, 458753, 4, 1507340, 196609, 2, 1572876, 393217, 5, 1638412, 393217, 5, 1703948, 393217, 5, 1769484, 458753, 5, 1835020, 65537, 2, 1900556, 458753, 5, 393229, 393217, 5, 458765, 393217, 5, 524301, 393217, 5, 917517, 458753, 4, 983053, 327681, 5, 1048589, 131073, 4, 1114125, 131073, 0, 1179661, 131073, 0, 1245197, 458753, 5, 1310733, 458753, 5, 1376269, 262145, 5, 1441805, 393217, 5, 1507341, 458753, 2, 1572877, 262145, 5, 1638413, 327681, 5, 1703949, 458753, 5, 1769485, 327681, 5, 1835021, 458753, 4, 1900557, 262145, 5, 327694, 393217, 5, 917518, 327681, 2, 983054, 393217, 5, 1048590, 262145, 3, 1114126, 65537, 0, 1179662, 65537, 0, 1245198, 327681, 4, 1310734, 393217, 5, 1441806, 262145, 5, 1507342, 262145, 5, 1572878, 327681, 5, 1638414, 458753, 5, 1703950, 393217, 5, 1769486, 327681, 5, 1900558, 458753, 5, 458749, 393217, 5, 524285, 393217, 5, 589821, 458753, 5, 458750, 393217, 5, 524286, 458753, 5, 589822, 262145, 5, 458751, 458753, 5, 524287, 262145, 5, 589823, 262145, 5, 393216, 458753, 5, 458752, 327681, 5, 524288, 393217, 5, 393217, 393217, 5, 458753, 327681, 5, 524289, 262145, 5, 393218, 327681, 5, 458754, 262145, 5, 524290, 262145, 5, 393219, 262145, 5, 458755, 262145, 5, 524291, 458753, 5, 393220, 262145, 5, 458756, 458753, 5, 524292, 327681, 5, 393221, 393217, 5, 458757, 262145, 5, 524293, 393217, 5, 393222, 327681, 5, 458758, 393217, 5, 524294, 327681, 5, 393223, 262145, 5, 458759, 393217, 5, 524295, 393217, 5, 393224, 458753, 5, 458760, 393217, 5, 524296, 458753, 5, 393212, 262145, 5, 458748, 327681, 5, 524284, 262145, 5, 589820, 327681, 5, 393213, 393217, 5, 393214, 393217, 5, 393215, 458753, 5, 327680, 393217, 5, 327681, 262145, 5, 327682, 393217, 5, 327683, 262145, 5, 327684, 262145, 5, 327685, 393217, 5, 327686, 262145, 5, 327687, 393217, 5, 327688, 458753, 5, -1048576, 262145, 5, -983040, 327681, 5, -917504, 262145, 5, -851968, 458753, 5, -786432, 327681, 5, -720896, 393217, 5, -655360, 327681, 5, -589824, 327681, 5, -524288, 262145, 5, -458752, 458753, 5, -393216, 327681, 5, -327680, 327681, 5, -262144, 458753, 5, -196608, 327681, 5, -131072, 393217, 5, -65536, 458753, 5, -1048575, 327681, 5, -983039, 393217, 5, -917503, 458753, 5, -851967, 262145, 5, -786431, 393217, 5, -720895, 327681, 5, -655359, 262145, 5, -589823, 262145, 5, -524287, 327681, 5, -458751, 393217, 5, -393215, 458753, 5, -327679, 327681, 5, -262143, 327681, 5, -196607, 393217, 5, -131071, 458753, 5, -65535, 393217, 5, -1048574, 393217, 5, -983038, 458753, 5, -917502, 393217, 5, -851966, 327681, 5, -786430, 458753, 5, -720894, 458753, 5, -655358, 327681, 5, -589822, 327681, 5, -524286, 458753, 5, -458750, 393217, 5, -393214, 327681, 5, -327678, 393217, 5, -262142, 458753, 5, -196606, 262145, 5, -131070, 393217, 5, -65534, 458753, 5, -1048573, 262145, 5, -983037, 458753, 5, -917501, 262145, 5, -851965, 393217, 5, -786429, 393217, 5, -720893, 262145, 5, -655357, 458753, 5, -589821, 393217, 5, -524285, 327681, 5, -458749, 393217, 5, -393213, 262145, 5, -327677, 393217, 5, -262141, 458753, 5, -196605, 393217, 5, -131069, 262145, 5, -65533, 327681, 5, -131081, 327681, 5, -65545, 65537, 0, -9, 65537, 4, 65527, 458753, 2, -131080, 458753, 5, -65544, 458753, 5, -8, 327681, 5, 65528, 327681, 5, -131079, 393217, 5, -65543, 327681, 5, -7, 262145, 5, 65529, 458753, 5, -131078, 458753, 5, -65542, 393217, 5, -6, 393217, 5, 65530, 262145, 5, -131077, 262145, 5, -65541, 327681, 5, -5, 458753, 5, 65531, 327681, 5, -131076, 458753, 5, -65540, 458753, 5, -4, 262145, 5, 65532, 458753, 5, -131075, 262145, 5, -65539, 327681, 5, -3, 327681, 5, 65533, 262145, 5, -131074, 458753, 5, -65538, 327681, 5, -2, 262145, 5, 65534, 327681, 5, -131073, 393217, 5, -65537, 458753, 5, -1, 458753, 5, 65535, 393217, 5, 0, 262145, 5, 1, 327681, 5, 2, 458753, 5, 3, 262145, 5, -131086, 458753, 2, -65550, 262145, 5, -14, 458753, 2, 65522, 393217, 5, -131085, 458753, 5, -65549, 458753, 2, -13, 458753, 5, 65523, 262145, 4, -131084, 393217, 5, -65548, 262145, 5, -12, 262145, 4, -131083, 262145, 5, -65547, 1, 1, -131082, 458753, 2, -65546, 327681, 6, -10, 327681, 6, 65526, 262145, 5, -458769, 458753, 2, -393233, 327681, 5, -327697, 458753, 2, -262161, 262145, 2, -196625, 458753, 5, -131089, 327681, 5, -65553, 262145, 5, -17, 458753, 5, 65519, 262145, 5, -458768, 393217, 5, -393232, 262145, 5, -327696, 327681, 5, -262160, 393217, 5, -196624, 262145, 5, -131088, 262145, 5, -65552, 393217, 5, -16, 458753, 5, 65520, 262145, 5, -458767, 458753, 2, -393231, 65537, 2, -327695, 458753, 5, -262159, 327681, 4, -196623, 458753, 5, -131087, 262145, 5, -65551, 262145, 5, -15, 131073, 2, 65521, 262145, 4, -458766, 1, 2, -196622, 327681, 5, -458765, 327681, 5, -196621, 262145, 5, 131055, 327681, 5, 196591, 262145, 5, 262127, 458753, 5, 327663, 262145, 5, 393199, 327681, 5, 458735, 393217, 5, 589807, 393217, 5, 655343, 393217, 5, 720879, 327681, 5, 786415, 327681, 5, 851951, 458753, 5, 131056, 327681, 5, 196592, 262145, 5, 262128, 262145, 5, 327664, 393217, 5, 393200, 393217, 5, 458736, 458753, 5, 589808, 458753, 5, 655344, 262145, 5, 720880, 393217, 5, 786416, 262145, 5, 851952, 393217, 5, 131057, 327681, 5, 196593, 262145, 5, 262129, 458753, 5, 327665, 327681, 2, 524273, 458753, 5, 589809, 327681, 5, 655345, 262145, 5, 720881, 393217, 5, 786417, 458753, 5, 917489, 458753, 5, 131058, 458753, 2, 196594, 327681, 5, 262130, 262145, 5, 327666, 393217, 5, 393202, 262145, 5, 458738, 262145, 5, 524274, 327681, 5, 589810, 393217, 5, 655346, 262145, 5, 720882, 327681, 5, 786418, 393217, 5, 131059, 262145, 5, 262131, 458753, 2, 327667, 327681, 4, 458739, 327681, 5, 524275, 458753, 2, 589811, 327681, 3, 655347, 458753, 5, 720883, 327681, 3, 786419, 262145, 5, 851955, 393217, 5, 917491, 458753, 5, 131060, 458753, 2, 196596, 458753, 5, 262132, 262145, 5, 327668, 262145, 2, 393204, 393217, 5, 458740, 458753, 2, 524276, 458753, 5, 589812, 458753, 2, 655348, 458753, 5, 720884, 196609, 2, 851956, 393217, 5, 917492, 262145, 5, 262133, 458753, 2, 327669, 393217, 5, 393205, 458753, 5, 458741, 458753, 2, 524277, 458753, 2, 589813, 393217, 5, 655349, 262145, 4, 720885, 327681, 5, 851957, 1, 2, 262134, 393217, 5, 327670, 458753, 2, 393206, 458753, 4, 458742, 262145, 5, 524278, 393217, 5, 589814, 393217, 5, 655350, 458753, 2, 720886, 327681, 5, 786422, 196609, 2, 851958, 458753, 2, 917494, 458753, 2, 983030, 327681, 5, 131063, 262145, 5, 196599, 393217, 5, 262135, 262145, 5, 327671, 327681, 5, 393207, 262145, 5, 458743, 327681, 5, 524279, 393217, 5, 589815, 327681, 5, 655351, 262145, 5, 720887, 327681, 5, 786423, 327681, 5, 851959, 393217, 5, 917495, 327681, 5, 983031, 393217, 5, 917496, 458753, 5, 983032, 327681, 5, 1048568, 393217, 5, 1114104, 327681, 5, 917497, 458753, 5, 983033, 458753, 4, 1048569, 458753, 2, 1114105, 458753, 2, 917498, 327681, 5, 983034, 393217, 5, 1048570, 458753, 5, 1114106, 393217, 2, 917499, 393217, 5, 983035, 327681, 5, 1048571, 458753, 2, 1114107, 458753, 5, 917500, 262145, 5, 983036, 262145, 5, 1048572, 393217, 5, 1114108, 458753, 5, 917501, 262145, 5, 983037, 327681, 5, 1048573, 327681, 5, 1114109, 131073, 2, 917502, 458753, 5, 983038, 262145, 5, 1048574, 458753, 2, 1114110, 458753, 2, 917503, 458753, 5, 983039, 458753, 2, 1048575, 327681, 2, 1114111, 262145, 5, 851968, 327681, 5, 917504, 458753, 5, 983040, 393217, 2, 1048576, 393217, 5, 851969, 393217, 5, 917505, 327681, 4, 983041, 262145, 5, 1048577, 458753, 5, 851970, 393217, 5, 917506, 262145, 2, 983042, 131073, 2, 1048578, 262145, 5, 1114114, 327681, 5, 1179650, 262145, 4, 1245186, 262145, 5, 1310722, 458753, 5, 1376258, 131073, 2, 1441794, 262145, 5, 1507330, 327681, 5, 1572866, 393217, 5, 1638402, 458753, 4, 1703938, 262145, 2, 1769474, 458753, 5, 1835010, 327681, 5, 1900546, 327681, 5, 851971, 458753, 5, 917507, 393217, 5, 983043, 393217, 5, 1048579, 458753, 5, 1114115, 458753, 5, 1179651, 458753, 5, 1245187, 393217, 5, 1310723, 393217, 5, 1376259, 393217, 5, 1441795, 458753, 5, 1507331, 327681, 5, 1572867, 458753, 5, 1638403, 262145, 5, 2228226, 458753, 5, 2293763, 458753, 5, 1179640, 393217, 5, 1245176, 262145, 5, 1179641, 262145, 5, 1245177, 458753, 2, 1179642, 327681, 2, 1245178, 458753, 5, 1179643, 458753, 5, 1245179, 327681, 5, 1179644, 393217, 5, 1245180, 262145, 2, 1179645, 262145, 4, 1245181, 262145, 4, 1179646, 458753, 2, 1245182, 327681, 5, 1179647, 458753, 5, 1245183, 262145, 5, 1114112, 458753, 2, 1179648, 393217, 5, 1114113, 458753, 5, 1179649, 262145, 5, 1048566, 262145, 4, 1114102, 458753, 2, 1179638, 393217, 5, 1245174, 327681, 4, 1048567, 458753, 2, 1114103, 327681, 5, 1179639, 458753, 5, 1245175, 458753, 5, 917512, 393217, 5, 983048, 393217, 5, 1048584, 327681, 5, 1114120, 458753, 5, 1179656, 393217, 5, 1245192, 393217, 5, 1310728, 327681, 5, 1376264, 262145, 5, 1441800, 458753, 5, 1507336, 393217, 5, 1572872, 458753, 5, 1638408, 458753, 5, -2031630, 393217, 5, -2031624, 262145, 5, -2097158, 393217, 5, -2031622, 327681, 5, -2097157, 327681, 5, -2031621, 458753, 2, -2097156, 327681, 5, -2031620, 458753, 2, -2097155, 393217, 5, -2031619, 262145, 5, -2031618, 393217, 5, -1507341, 327681, 5, -1572877, 393217, 5, -1703949, 458753, 5, -1703950, 327681, 5, -1769486, 393217, 5, -1835022, 458753, 2, -1966088, 262145, 5, -1966087, 262145, 5, -2031623, 393217, 5, -2097160, 393217, 5, -2097159, 262145, 5, -2097165, 393217, 5, -2031629, 262145, 5, -1966094, 327681, 5, -1441791, 327681, 5, -1638413, 458753, 5, -1900557, 327681, 5, -1966093, 458753, 5, -2162692, 458753, 2, -2162693, 393217, 5, -2228229, 327681, 5, -2228230, 458753, 5, -2293766, 131073, 2, -2293767, 262145, 5, -2293768, 262145, 2, -2359304, 262145, 5, -2162694, 458753, 5, -2228231, 327681, 5, -2359303, 327681, 5, -2162695, 262145, 5, -2162696, 393217, 5, -2228232, 393217, 5, 917485, 327681, 5, 851949, 393217, 5, 851948, 262145, 5, 786412, 327681, 5, 786411, 262145, 5, 720875, 327681, 5, 524264, 393217, 5, -1245209, 327681, 5, -1310744, 262145, 5, -1376279, 458753, 5, -1441814, 327681, 5, -1310745, 327681, 6, -1376280, 458753, 5, -1441815, 458753, 5, -1507350, 327681, 5, -1572885, 393217, 5, -1638420, 327681, 5, -1703955, 393217, 5, -1769490, 262145, 5, -1703954, 327681, 5, -1638419, 262145, 5, -1572884, 393217, 5, -1507349, 262145, 5, -1179673, 327681, 5, -1245208, 458753, 5, -1310743, 262145, 5, -1376278, 262145, 5, -1441813, 327681, 5, -1507348, 458753, 5, -1572883, 131073, 2, -1638418, 393217, 5, -1114137, 393217, 5, -1179672, 393217, 5, -1245207, 327681, 5, -1310742, 196609, 2, -1376277, 458753, 5, -1441812, 393217, 5, -1507347, 458753, 2, -1572882, 458753, 2, 393192, 327681, 5, 458728, 458753, 5, 589803, 393217, 5, 655339, 393217, 5, 655340, 327681, 5, 720876, 327681, 5, 720877, 458753, 5, 786413, 458753, 5, 786414, 327681, 5, 851950, 458753, 5, 720878, 327681, 5, 655342, 327681, 5, 655341, 262145, 5, 589805, 327681, 5, 589804, 262145, 5, 524268, 458753, 5, 524267, 262145, 5, 458731, 262145, 5, 327656, 262145, 5, 262120, 262145, 5, 589806, 262145, 5, 524270, 458753, 5, 524269, 327681, 5, 458733, 458753, 5, 458732, 458753, 5, 393196, 393217, 5, 196585, 327681, 5, -24, 327681, 5, 65513, 327681, 5, 131049, 458753, 5, 131050, 262145, 5, 196586, 458753, 5, 196587, 393217, 5, 262123, 262145, 5, 262124, 458753, 5, 327660, 327681, 5, 393198, 262145, 5, -65560, 393217, 5, -65559, 327681, 5, -23, 393217, 5, -22, 458753, 5, 65514, 393217, 5, 65515, 393217, 5, 131051, 458753, 5, 131052, 327681, 5, 196588, 393217, 5, 196589, 458753, 5, 262125, 262145, 5, 262126, 393217, 5, 327662, 262145, 5, 196590, 458753, 5, 131054, 458753, 5, 131053, 262145, 5, 65517, 327681, 5, 65516, 393217, 5, -20, 262145, 5, -21, 327681, 5, -65557, 393217, 5, -65558, 393217, 5, -131094, 262145, 5, -131095, 262145, 5, -196631, 393217, 5, -458777, 393217, 5, -393240, 327681, 5, -327704, 458753, 5, -327703, 327681, 5, -262167, 262145, 5, -196630, 327681, 5, -196629, 458753, 5, -131093, 327681, 5, -131092, 393217, 5, -65556, 458753, 5, -65555, 458753, 5, -19, 262145, 5, -18, 327681, 5, 65518, 262145, 5, -65554, 458753, 5, -131090, 458753, 5, -131091, 393217, 5, -196627, 458753, 5, -262164, 196609, 6, -262165, 458753, 5, -327701, 393217, 6, -327702, 393217, 5, -393238, 327681, 4, -393239, 458753, 2, -458775, 262145, 5, -458776, 262145, 5, -524312, 458753, 5, -524313, 262145, 5, -589849, 393217, 5, -196626, 393217, 5, -262163, 327681, 6, -327700, 327681, 6, -393237, 1, 6, -458774, 262145, 6, -524311, 393217, 5, -589848, 393217, 5, -655385, 393217, 5, -786457, 458753, 5, -720921, 393217, 5, -720920, 327681, 5, -655384, 458753, 5, -655383, 327681, 5, -589847, 458753, 5, -589846, 327681, 6, -524310, 65537, 6, -524309, 65537, 6, -458773, 262145, 6, -458772, 196609, 6, -393236, 327681, 6, -393235, 131073, 6, -327699, 458753, 2, -327698, 458753, 2, -851993, 393217, 5, -786456, 393217, 5, -720919, 458753, 5, -655382, 262145, 5, -589845, 65537, 6, -524308, 327681, 6, -458771, 65537, 6, -393234, 327681, 4, -262162, 262145, 4, -458770, 65537, 6, -524306, 131073, 6, -524307, 327681, 6, -589843, 327681, 6, -589844, 65537, 6, -655380, 196609, 6, -655381, 1, 6, -720917, 393217, 5, -720918, 262145, 5, -786454, 327681, 5, -786455, 327681, 5, -851991, 262145, 5, -851992, 458753, 5, -917528, 262145, 5, -917529, 458753, 5, -983065, 262145, 5, -1048601, 1, 2, -1048600, 393217, 5, -983064, 327681, 5, -983063, 458753, 5, -917527, 458753, 5, -917526, 393217, 5, -851990, 458753, 5, -851989, 327681, 5, -786453, 327681, 5, -786452, 327681, 3, -720916, 131073, 1, -720915, 393217, 3, -655379, 262145, 6, -655378, 262145, 6, -589842, 327681, 6, -1114136, 327681, 5, -1114135, 196609, 2, -1048599, 393217, 5, -1048598, 393217, 5, -983062, 327681, 5, -983061, 458753, 5, -917525, 262145, 5, -917524, 393217, 5, -851988, 393217, 5, -851987, 262145, 5, -786451, 393217, 3, -786450, 327681, 3, -720914, 327681, 3, -1179671, 327681, 5, -1179670, 1, 2, -1114134, 327681, 5, -1114133, 65537, 2, -1048597, 393217, 5, -1048596, 327681, 4, -983060, 262145, 4, -917523, 458753, 5, -917522, 393217, 5, -851986, 393217, 5, -1245206, 327681, 5, -1179669, 458753, 2, -1114132, 327681, 4, -1048595, 327681, 5, -983058, 1, 6, -1245205, 262145, 5, -1179668, 262145, 4, -1048594, 131073, 6, -1310741, 327681, 5, -1310740, 458753, 5, -1245204, 327681, 5, -1245203, 262145, 5, -1179667, 262145, 5, -1179666, 1, 6, -1114130, 65537, 6, -1376276, 327681, 5, -1376275, 393217, 5, -1310739, 393217, 5, -1310738, 393217, 5, -1441811, 262145, 2, -1376274, 458753, 5, -1245202, 393217, 5, -1441810, 458753, 2, -1507346, 393217, 5, -917518, 327681, 2, -983054, 262145, 5, -1048590, 262145, 5, -25, 327681, 5, 65511, 262145, 5, 131047, 393217, 5, 196583, 327681, 5, 262119, 458753, 5, 327655, 458753, 5, 393191, 262145, 5, -65561, 458753, 5, -327705, 262145, 5, -393241, 262145, 5, 262121, 262145, 5, 262122, 458753, 5, 458729, 262145, 5, 458730, 262145, 5, 327659, 393217, 5, 393195, 458753, 5, 458727, 262145, 5, 1835022, 327681, 5, 1114127, 262145, 5, 1048591, 262145, 5, 983055, 327681, 5, 327695, 393217, 5, 327692, 262145, 5, 327693, 327681, 5, 1376270, 327681, 5, 983056, 458753, 5, 1048592, 393217, 5, 1114128, 65537, 2, 1900559, 393217, 5, 1769488, 262145, 5, 1835024, 327681, 2, 1900560, 262145, 5, 458766, 393217, 5, 393230, 393217, 5, 393231, 262145, 5, 458767, 393217, 5, 524302, 327681, 5, 1179663, 262145, 4, 1245199, 327681, 5, 1310735, 327681, 5, 1376271, 393217, 5, 1441807, 262145, 5, 1507343, 458753, 5, 1572879, 458753, 5, 1638415, 262145, 5, 1703951, 393217, 5, 917519, 458753, 5, 1769487, 327681, 5, -262166, 327681, 2, -851984, 327681, 5, -983055, 327681, 4, -983056, 393217, 5, -917520, 458753, 5, -917519, 458753, 5, -1376260, 196609, 4, -1245198, 393217, 5, -1310735, 262145, 5, -1245199, 262145, 5, -1376262, 1, 4, -1376261, 393217, 6, 2293768, 327681, 5, -1572872, 262145, 5, -393230, 262145, 5, -327694, 262145, 5, -262158, 262145, 5, -393229, 393217, 5, -327693, 458753, 5, -262157, 393217, 5, -11, 1, 4, 65525, 393217, 5, 131061, 393217, 5, 196597, 458753, 2, 65524, 458753, 2, 196595, 458753, 2, 196598, 327681, 4, 393203, 262145, 5, 393201, 458753, 5, -196628, 327681, 5, 458737, 393217, 5, 524272, 458753, 5, 524271, 458753, 5, 458734, 262145, 5, 393197, 327681, 5, 327661, 327681, 5, 393194, 458753, 5, 393193, 262145, 5, 327657, 262145, 5, 327658, 327681, 5, 196584, 458753, 5, 131048, 458753, 5, 65512, 458753, 5, -131096, 458753, 5, -196632, 262145, 5, -262168, 393217, 5, -262169, 393217, 5, -196633, 458753, 5, -131097, 262145, 5, 524265, 262145, 5, 524266, 262145, 5, 589802, 393217, 5, 655338, 327681, 5, 720874, 393217, 5, 720873, 327681, 5, 655337, 393217, 5, 589801, 458753, 5, 655336, 262145, 5, 589800, 262145, 5, 524263, 327681, 5, 589799, 458753, 5, 655335, 393217, 5, 720872, 262145, 5, 786409, 327681, 5, 786410, 327681, 5, 720871, 393217, 5, 786407, 327681, 5, 786408, 393217, 5, 851944, 393217, 5, 851945, 327681, 5, 851946, 458753, 5, 851947, 458753, 5, 917482, 393217, 5, 917483, 393217, 5, 917484, 393217, 5, 917486, 458753, 5, 917487, 327681, 5, 917488, 393217, 5, 851953, 458753, 5, 851954, 458753, 5, 917490, 327681, 5, 786420, 327681, 5, 786421, 327681, 5, 917493, 262145, 5, 1835023, 327681, 5, 524303, 327681, 5, 917520, 458753, 5, -1376245, 393217, 5, -1376246, 393217, 5, -1441782, 458753, 5, -1441783, 458753, 5, -1376244, 458753, 5, -1441781, 458753, 5, -1507318, 458753, 5, -1507319, 262145, 5, -1507320, 458753, 2, -1572856, 458753, 5, -1572857, 458753, 2, -1572855, 458753, 5, -1638393, 458753, 5, -1638394, 327681, 5, -1703943, 458753, 5, -1769479, 393217, 5, -1769478, 262145, 5, -1703942, 458753, 5, -1769477, 327681, 5, -1703941, 458753, 5, -1638405, 327681, 5, -1835013, 393217, 5, -1900549, 458753, 5, -1966085, 393217, 5, -1703940, 458753, 5, -1638404, 262145, 5, -1769476, 327681, 5, -1835012, 458753, 5, -1900548, 262145, 5, -1966084, 327681, 2, -1703939, 458753, 5, -1638403, 393217, 5, -1769475, 262145, 5, -1835011, 262145, 5, -1900547, 393217, 5, -1966083, 262145, 5, -1769474, 458753, 5, -1703938, 327681, 5, -1835010, 393217, 5, -1900546, 196609, 2, -1966082, 327681, 5, -1638402, 327681, 5, -1900545, 327681, 5, -1835009, 458753, 2, -1769473, 327681, 5, -1703937, 327681, 5, -2031616, 458753, 2, -1769471, 393217, 5, -1769472, 458753, 2, -1769470, 327681, 5, -1769469, 458753, 2, -1900542, 327681, 5, -1966079, 262145, 5, -1966081, 1, 2, -2031617, 262145, 5, -2097154, 262145, 5, -1966078, 327681, 2, -1835005, 327681, 5, -1835004, 262145, 5, -1769468, 262145, 5, -1769467, 327681, 5, -1703931, 262145, 5, -2031615, 393217, 5, -2097152, 196609, 2, -2097153, 327681, 2, -2162691, 1, 2, -1703930, 393217, 5, -1900540, 393217, 5, -1900541, 393217, 5, -1966077, 262145, 5, -1638401, 262145, 5, -983053, 327681, 5, -1114131, 458753, 5, -983059, 327681, 5, -1441809, 458753, 2, -2359302, 458753, 5, -2359301, 393217, 5, -2293765, 393217, 5, -2359300, 458753, 5, -2293764, 458753, 5, -2228228, 262145, 5, -2359299, 327681, 5, -2293763, 327681, 5, -2228227, 393217, 5, -2359298, 262145, 5, -2293762, 327681, 5, -2228226, 393217, 5, -2162690, 262145, 5, -2359297, 458753, 5, -2293761, 393217, 5, -2228225, 262145, 5, -2162689, 262145, 5, -2424832, 458753, 5, -2359296, 393217, 5, -2293760, 262145, 5, -2228224, 327681, 5, -2162688, 262145, 5, -2424831, 262145, 5, -2359295, 327681, 5, -2293759, 393217, 5, -2228223, 262145, 2, -2162687, 262145, 5, -2097151, 262145, 5, -2424830, 393217, 5, -2359294, 262145, 5, -2293758, 262145, 5, -2228222, 262145, 5, -2162686, 458753, 5, -2097150, 262145, 5, -2031614, 458753, 5, -2424829, 327681, 5, -2359293, 393217, 5, -2293757, 393217, 5, -2228221, 458753, 5, -2162685, 327681, 5, -2097149, 262145, 5, -2031613, 393217, 2, -2424828, 393217, 5, -2359292, 327681, 5, -2293756, 458753, 5, -2228220, 327681, 5, -2162684, 262145, 2, -2097148, 262145, 5, -2031612, 262145, 5, -1966076, 327681, 5, -2424827, 327681, 5, -2359291, 393217, 5, -2293755, 393217, 5, -2228219, 262145, 5, -2162683, 393217, 5, -2097147, 327681, 5, -2031611, 262145, 5, -1966075, 458753, 5, -1900539, 393217, 5, -1835003, 262145, 5, -2424826, 327681, 5, -2359290, 393217, 5, -2293754, 262145, 5, -2228218, 262145, 5, -2162682, 458753, 2, -2097146, 458753, 5, -2031610, 262145, 5, -1966074, 262145, 5, -1900538, 393217, 5, -1835002, 262145, 5, -1769466, 327681, 5, -2424825, 262145, 5, -2359289, 393217, 5, -2293753, 262145, 5, -2228217, 458753, 5, -2162681, 458753, 5, -2097145, 327681, 5, -2031609, 262145, 5, -1966073, 458753, 5, -1900537, 393217, 5, -1835001, 327681, 5, -1769465, 458753, 5, -1703929, 1, 2, -2424824, 458753, 5, -2359288, 393217, 5, -2293752, 458753, 5, -2228216, 393217, 5, -2162680, 327681, 2, -2097144, 262145, 5, -2031608, 458753, 5, -1966072, 458753, 5, -1900536, 262145, 5, -1835000, 262145, 5, -1769464, 196609, 2, -1703928, 393217, 5, -1638392, 458753, 5, -2424823, 458753, 5, -2359287, 458753, 5, -2293751, 327681, 5, -2228215, 262145, 5, -2162679, 327681, 5, -2097143, 393217, 5, -2031607, 458753, 5, -1966071, 327681, 5, -1900535, 262145, 5, -1834999, 262145, 5, -1769463, 262145, 5, -1703927, 393217, 5, -1638391, 327681, 5, -2424822, 262145, 5, -2359286, 327681, 5, -2293750, 393217, 5, -2228214, 393217, 5, -2162678, 262145, 5, -2097142, 393217, 5, -2031606, 262145, 5, -1966070, 327681, 5, -1900534, 262145, 5, -1834998, 1, 0, -1769462, 131073, 0, -1703926, 458753, 5, -1638390, 393217, 5, -1572854, 458753, 5, -2424821, 458753, 5, -2359285, 393217, 5, -2293749, 458753, 5, -2228213, 393217, 5, -2162677, 458753, 2, -2097141, 458753, 5, -2031605, 327681, 2, -1966069, 327681, 5, -1900533, 393217, 0, -1834997, 393217, 6, -1769461, 393217, 6, -1703925, 65537, 4, -1638389, 262145, 5, -1572853, 393217, 5, -1507317, 1, 6, -2424820, 458753, 5, -2359284, 393217, 5, -2293748, 393217, 5, -2228212, 458753, 5, -2162676, 458753, 5, -2097140, 458753, 5, -2031604, 458753, 5, -1966068, 393217, 5, -1900532, 393217, 5, -1834996, 262145, 6, -1769460, 262145, 6, -1703924, 327681, 1, -1638388, 65538, 0, -1572852, 458753, 5, -1507316, 458753, 5, -1441780, 262145, 4, -2424819, 262145, 5, -2359283, 393217, 5, -2293747, 327681, 5, -2228211, 262145, 5, -2162675, 393217, 5, -2097139, 65537, 2, -2031603, 262145, 5, -1966067, 327681, 5, -1900531, 458753, 5, -1834995, 262145, 6, -1769459, 131073, 6, -1703923, 327681, 1, -1638387, 196610, 2, -1572851, 327681, 5, -1507315, 393217, 5, -1441779, 262145, 5, -1376243, 393217, 5, -2424818, 458753, 5, -2359282, 327681, 5, -2293746, 393217, 5, -2228210, 262145, 5, -2162674, 393217, 5, -2097138, 327681, 5, -2031602, 393217, 5, -1966066, 458753, 5, -1900530, 458753, 5, -1834994, 196609, 5, -1769458, 65537, 6, -1703922, 327681, 1, -1638386, 327681, 5, -1572850, 393217, 5, -1507314, 393217, 5, -1441778, 393217, 5, -1376242, 393217, 5, -2424817, 458753, 5, -2359281, 393217, 5, -2293745, 458753, 2, -2228209, 458753, 5, -2162673, 327681, 5, -2097137, 393217, 5, -2031601, 458753, 2, -1966065, 458753, 5, -1900529, 327681, 5, -1834993, 262145, 5, -1769457, 327681, 5, -1703921, 327681, 4, -1638385, 458753, 5, -1572849, 393217, 4, -1507313, 262145, 5, -1441777, 327681, 5, -1376241, 393217, 5, -2424816, 327681, 5, -2359280, 458753, 5, -2293744, 327681, 5, -2228208, 262145, 5, -2162672, 327681, 2, -2097136, 262145, 5, -2031600, 327681, 5, -1966064, 393217, 5, -1900528, 262145, 5, -1834992, 327681, 5, -1769456, 393217, 5, -1703920, 262145, 5, -1638384, 458753, 5, -1572848, 393217, 5, -1507312, 458753, 5, -1441776, 262145, 4, -1376240, 393217, 5, -2424815, 262145, 5, -2359279, 393217, 5, -2293743, 393217, 5, -2228207, 327681, 2, -2162671, 327681, 5, -2097135, 458753, 5, -2031599, 458753, 5, -1966063, 393217, 5, -1900527, 327681, 5, -1834991, 262145, 5, -1769455, 262145, 5, -1703919, 458753, 5, -1638383, 458753, 2, -1572847, 262145, 5, -1507311, 327681, 5, -1441775, 327681, 5, -1376239, 458753, 5, -2424814, 262145, 5, -2359278, 393217, 5, -2293742, 65537, 2, -2228206, 262145, 5, -2162670, 327681, 5, -2097134, 393217, 5, -2031598, 458753, 5, -1966062, 393217, 5, -1900526, 458753, 5, -1834990, 458753, 5, -1769454, 262145, 5, -1703918, 327681, 5, -1638382, 393217, 5, -1572846, 262145, 5, -1507310, 327681, 5, -1441774, 393217, 5, -1376238, 327681, 4, -1048565, 262145, 5, -983029, 393217, 5, -917493, 458753, 5, -851957, 327681, 5, -786421, 327681, 5, -720885, 458753, 5, -655349, 458753, 5, -589813, 458753, 5, -524277, 393217, 5, -458741, 262145, 5, -393205, 262145, 5, -327669, 393217, 5, -262133, 393217, 5, -1048568, 262145, 5, -1048567, 262145, 5, -1048566, 327681, 5, -983032, 458753, 5, -983031, 458753, 5, -983030, 327681, 5, -917496, 458753, 5, -851960, 458753, 5, -786424, 262145, 5, -720888, 327681, 5, -655352, 262145, 5, -589816, 393217, 5, -524280, 393217, 5, -458744, 393217, 5, -393208, 393217, 5, -327672, 262145, 5, -262136, 262145, 5, -196600, 262145, 5, -131064, 262145, 5, -917495, 458753, 5, -851959, 327681, 5, -786423, 393217, 5, -720887, 393217, 5, -655351, 262145, 5, -589815, 327681, 5, -524279, 262145, 5, -458743, 327681, 5, -393207, 262145, 5, -327671, 327681, 5, -262135, 458753, 5, -196599, 262145, 5, -131063, 458753, 5, -917494, 327681, 5, -851958, 327681, 5, -786422, 327681, 5, -720886, 458753, 5, -655350, 327681, 5, -589814, 458753, 5, -524278, 393217, 5, -458742, 393217, 5, -393206, 262145, 5, -327670, 262145, 5, -262134, 458753, 5, -196598, 393217, 5, -131062, 458753, 5, -196597, 458753, 5, -131061, 262145, 5, -524272, 458753, 5, -524271, 327681, 5, -524270, 458753, 5, -524269, 262145, 5, -1310704, 458753, 5, -1245168, 393217, 5, -1179632, 262145, 5, -1114096, 393217, 5, -1048560, 393217, 5, -983024, 262145, 5, -917488, 262145, 5, -851952, 327681, 5, -786416, 262145, 5, -720880, 327681, 5, -655344, 262145, 5, -589808, 262145, 5, -1310703, 458753, 4, -1245167, 393217, 6, -1179631, 458753, 2, -1114095, 393217, 5, -1048559, 393217, 5, -983023, 458753, 5, -917487, 393217, 5, -851951, 393217, 5, -786415, 327681, 5, -720879, 393217, 5, -655343, 327681, 5, -589807, 458753, 5, -1310702, 393217, 5, -1245166, 1, 0, -1179630, 327681, 0, -1114094, 458753, 5, -1048558, 262145, 5, -983022, 458753, 5, -917486, 393217, 5, -851950, 327681, 5, -786414, 393217, 5, -720878, 458753, 5, -655342, 262145, 5, -589806, 393217, 5, -1507309, 458753, 5, -1441773, 262145, 5, -1376237, 458753, 5, -1310701, 327681, 4, -1245165, 393217, 5, -1179629, 327681, 5, -1114093, 393217, 5, -1048557, 458753, 5, -983021, 393217, 5, -917485, 327681, 5, -851949, 327681, 5, -786413, 458753, 5, -720877, 327681, 5, -655341, 262145, 5, -589805, 393217, 5, -2359277, 262145, 5, -2293741, 393217, 5, -2228205, 458753, 2, -2162669, 458753, 2, -2097133, 393217, 5, -2031597, 262145, 5, -1966061, 393217, 5, -1900525, 393217, 5, -1834989, 458753, 5, -1769453, 393217, 5, -1703917, 458753, 5, -1638381, 458753, 5, -1572845, 458753, 5, -2097127, 262145, 5, -2031591, 393217, 5, -1966055, 393217, 5, -1900519, 262145, 5, -1834983, 262145, 5, -1769447, 393217, 5, -1703911, 458753, 5, -1638375, 262145, 5, -1572839, 327681, 5, -1507303, 327681, 5, -1441767, 458753, 5, -1376231, 327681, 5, -1310695, 393217, 5, -1245159, 458753, 5, -1179623, 262145, 4, -1048551, 327681, 5, -983015, 393217, 3, -917479, 262145, 5, -851943, 262145, 2, -786407, 262145, 5, -720871, 262145, 5, -655335, 458753, 5, -589799, 458753, 2, -524263, 262145, 5, -458727, 458753, 3, -393191, 458753, 3, -327655, 393217, 5, -262119, 262145, 5, -196583, 262145, 5, -2031590, 262145, 5, -1966054, 393217, 2, -1900518, 458753, 2, -1834982, 393217, 5, -1769446, 327681, 5, -1703910, 327681, 5, -1638374, 458753, 4, -1572838, 262145, 5, -1507302, 458753, 5, -1441766, 327681, 5, -1376230, 393217, 5, -1310694, 262145, 4, -1245158, 1, 0, -1179622, 196609, 6, -1114086, 262145, 6, -1048550, 327681, 5, -983014, 327681, 5, -917478, 262145, 5, -851942, 458753, 5, -786406, 327681, 5, -720870, 131073, 4, -655334, 458753, 2, -589798, 327681, 5, -524262, 393217, 5, -458726, 458753, 3, -393190, 458753, 3, -327654, 262145, 5, -262118, 393217, 6, -196582, 262145, 6, -1966053, 458753, 2, -1900517, 262145, 5, -1834981, 262145, 5, -1769445, 327681, 5, -1703909, 327681, 5, -1638373, 458753, 5, -1572837, 65537, 6, -1507301, 458753, 5, -1441765, 327681, 5, -1376229, 262145, 5, -1310693, 393217, 5, -1245157, 262145, 5, -1179621, 196609, 1, -1114085, 196609, 1, -1048549, 327681, 4, -983013, 262145, 2, -917477, 262145, 5, -851941, 458753, 2, -786405, 262145, 5, -720869, 65537, 6, -655333, 65537, 2, -589797, 393217, 5, -524261, 458753, 5, -458725, 262145, 5, -393189, 458753, 5, -327653, 262145, 6, -262117, 262145, 6, -196581, 327681, 6, -1834980, 393217, 5, -1769444, 393217, 5, -1703908, 458753, 5, -1638372, 262145, 5, -1572836, 327681, 5, -1507300, 262145, 5, -1441764, 393217, 5, -1376228, 262145, 5, -1310692, 262145, 5, -1245156, 262145, 5, -1179620, 262145, 5, -1114084, 458753, 5, -1048548, 393217, 5, -983012, 262145, 5, -917476, 65537, 5, -851940, 196609, 5, -786404, 262145, 5, -720868, 393217, 5, -655332, 327681, 5, -589796, 458753, 5, -524260, 393217, 5, -458724, 327681, 5, -393188, 393217, 5, -327652, 458753, 6, -262116, 262145, 6, -196580, 458753, 6, -1834979, 458753, 2, -1769443, 262145, 5, -1703907, 262145, 5, -1638371, 262145, 5, -1572835, 458753, 5, -1507299, 262145, 5, -1441763, 262145, 5, -1376227, 262145, 5, -1310691, 458753, 2, -1245155, 327681, 5, -1179619, 327681, 5, -1114083, 327681, 5, -1048547, 393217, 5, -983011, 458753, 4, -917475, 1, 4, -851939, 131073, 5, -786403, 262145, 5, -720867, 393217, 5, -655331, 327681, 5, -589795, 458753, 4, -524259, 393217, 5, -458723, 262145, 5, -393187, 458753, 5, -327651, 327681, 5, -262115, 458753, 6, -196579, 327681, 6, -1769442, 393217, 5, -1703906, 262145, 5, -1638370, 458753, 5, -1572834, 393217, 5, -1507298, 458753, 5, -1441762, 327681, 4, -1376226, 393217, 5, -1310690, 458753, 5, -1245154, 327681, 5, -1179618, 262145, 5, -1114082, 458753, 5, -1048546, 458753, 2, -983010, 458753, 2, -917474, 327681, 5, -851938, 327681, 5, -786402, 262145, 5, -720866, 393217, 5, -655330, 393217, 5, -589794, 393217, 5, -524258, 327681, 5, -458722, 393217, 5, -393186, 458753, 5, -327650, 458753, 5, -262114, 262145, 5, -196578, 262145, 5, -1703905, 458753, 2, -1638369, 458753, 5, -1572833, 262145, 5, -1507297, 1, 6, -1441761, 65537, 6, -1376225, 262145, 6, -1310689, 262145, 6, -1245153, 65537, 2, -1179617, 393217, 5, -1114081, 393217, 5, -1048545, 458753, 5, -983009, 393217, 5, -917473, 393217, 5, -851937, 458753, 5, -786401, 327681, 5, -720865, 458753, 5, -655329, 458753, 5, -589793, 262145, 5, -524257, 458753, 5, -458721, 327681, 5, -393185, 1, 2, -327649, 262145, 5, -262113, 393217, 5, -196577, 262145, 5, -1638368, 458753, 5, -1572832, 393217, 5, -1507296, 65537, 6, -1441760, 393217, 6, -1376224, 131073, 6, -1310688, 327681, 6, -1245152, 458753, 6, -1179616, 196609, 0, -1114080, 262145, 5, -1048544, 327681, 5, -983008, 262145, 5, -917472, 458753, 5, -851936, 458753, 2, -786400, 458753, 2, -720864, 327681, 5, -655328, 458753, 5, -589792, 393217, 5, -524256, 327681, 5, -458720, 393217, 5, -393184, 393217, 2, -327648, 458753, 5, -262112, 458753, 5, -196576, 327681, 5, -1507295, 131073, 6, -1441759, 131073, 6, -1376223, 262145, 6, -1310687, 65537, 6, -1245151, 327681, 6, -1179615, 196609, 0, -1114079, 327681, 5, -1048543, 262145, 5, -983007, 393217, 5, -917471, 458753, 5, -851935, 458753, 2, -786399, 393217, 2, -720863, 393217, 5, -655327, 458753, 2, -589791, 458753, 5, -524255, 327681, 5, -458719, 393217, 5, -393183, 393217, 5, -327647, 262145, 5, -262111, 458753, 5, -196575, 393217, 5, -1441758, 65537, 6, -1376222, 327681, 6, -1310686, 196609, 6, -1245150, 393217, 6, -1179614, 65537, 2, -1114078, 458753, 5, -1048542, 458753, 2, -983006, 327681, 5, -917470, 262145, 5, -851934, 458753, 5, -786398, 393217, 5, -720862, 262145, 5, -655326, 327681, 5, -589790, 393217, 5, -524254, 327681, 5, -458718, 393217, 5, -393182, 458753, 5, -327646, 458753, 5, -262110, 262145, 5, -196574, 393217, 5, -1441757, 393217, 2, -1376221, 393217, 2, -1310685, 327681, 5, -1245149, 65537, 2, -1179613, 458753, 5, -1114077, 393217, 5, -1048541, 327681, 5, -983005, 458753, 5, -917469, 262145, 5, -851933, 458753, 5, -786397, 262145, 5, -720861, 393217, 5, -655325, 327681, 5, -589789, 458753, 5, -524253, 327681, 5, -458717, 327681, 5, -393181, 458753, 5, -327645, 327681, 5, -262109, 327681, 5, -196573, 458753, 5, -1376220, 327681, 5, -1310684, 393217, 5, -1245148, 262145, 5, -1179612, 393217, 5, -1114076, 458753, 5, -1048540, 327681, 5, -983004, 393217, 5, -917468, 327681, 5, -851932, 327681, 5, -786396, 262145, 5, -720860, 458753, 5, -655324, 458753, 5, -589788, 458753, 5, -524252, 327681, 5, -458716, 262145, 5, -393180, 393217, 5, -327644, 262145, 5, -262108, 458753, 5, -196572, 262145, 5, -65528, 393217, 5, 8, 262145, 5, -65527, 327681, 5, 9, 262145, 5, -65526, 393217, 5, 10, 393217, 5, -65525, 327681, 5, 11, 393217, 5, -65524, 262145, 5, 12, 458753, 5, -65523, 393217, 5, 13, 393217, 5, -65522, 458753, 5, 14, 262145, 5, -65521, 262145, 5, 15, 458753, 5, -65520, 393217, 5, 16, 458753, 5, -65519, 458753, 5, 17, 458753, 5, -65518, 458753, 5, 18, 393217, 5, -196596, 262145, 5, -131060, 393217, 5, -196595, 393217, 5, -131059, 327681, 5, -196594, 458753, 5, -131058, 393217, 5, -196593, 458753, 5, -131057, 262145, 5, -196592, 393217, 5, -131056, 262145, 5, -196591, 262145, 5, -131055, 393217, 5, -196590, 327681, 5, -131054, 393217, 5, -196589, 393217, 5, -131053, 393217, 5, -65517, 393217, 5, 19, 458753, 5, -196588, 327681, 5, -131052, 1, 1, -65516, 196609, 2, 20, 458753, 4, -196587, 458753, 4, -131051, 262145, 6, -65515, 196609, 0, 21, 327681, 2, -196586, 393217, 5, -131050, 1, 2, -65514, 393217, 5, 22, 327681, 5, -196585, 458753, 5, -131049, 458753, 5, -65513, 458753, 5, 23, 327681, 5, -196584, 458753, 5, -131048, 262145, 5, -65512, 458753, 2, 24, 327681, 5, -131047, 458753, 2, -65511, 327681, 4, 25, 262145, 4, 2293762, 458753, 5, 131062, 262145, 5, 851943, 458753, 5, 917479, 262145, 5, 917480, 393217, 5, 917481, 327681, 5, 65557, 262145, 5, 131093, 327681, 5, 196629, 458753, 4, 262165, 393217, 5, 327701, 262145, 2, 393237, 327681, 2, 458773, 458753, 2, 524309, 1, 0, 589845, 131073, 0, 655381, 131073, 0, 720917, 458753, 4, 786453, 393217, 5, 851989, 327681, 5, 65558, 458753, 5, 131094, 458753, 2, 196630, 458753, 4, 262166, 327681, 5, 327702, 458753, 5, 393238, 327681, 2, 458774, 327681, 5, 524310, 327681, 4, 589846, 458753, 4, 655382, 131073, 5, 720918, 196609, 6, 786454, 262145, 4, 851990, 262145, 5, 65559, 327681, 2, 131095, 262145, 5, 196631, 393217, 5, 262167, 393217, 5, 327703, 262145, 5, 393239, 393217, 5, 458775, 327681, 5, 524311, 327681, 4, 589847, 458753, 5, 655383, 458753, 5, 720919, 458753, 2, 786455, 327681, 2, 851991, 393217, 5, 65560, 327681, 5, 131096, 458753, 4, 196632, 458753, 5, 262168, 393217, 5, 327704, 458753, 5, 393240, 1, 2, 458776, 458753, 5, 524312, 262145, 5, 589848, 393217, 5, 655384, 458753, 5, 720920, 327681, 5, 786456, 393217, 5, 851992, 458753, 5, 65561, 458753, 4, 131097, 327681, 2, 196633, 262145, 5, 262169, 327681, 5, 327705, 327681, 2, 393241, 458753, 2, 458777, 458753, 2, 524313, 327681, 5, 589849, 327681, 5, 655385, 393217, 5, 720921, 393217, 5, 786457, 458753, 5, 851993, 458753, 5, 1179664, 327681, 4, 917521, 262145, 5, 983057, 393217, 5, 1048593, 458753, 5, 1114129, 262145, 5, 1179665, 458753, 2, 917522, 458753, 4, 983058, 458753, 5, 1048594, 458753, 2, 1114130, 458753, 2, 1179666, 458753, 5, 917523, 327681, 2, 983059, 393217, 5, 1048595, 262145, 5, 1114131, 458753, 5, 1179667, 393217, 5, 917524, 458753, 5, 983060, 262145, 5, 1048596, 393217, 5, 1114132, 458753, 5, 1179668, 393217, 5, 917525, 393217, 5, 983061, 393217, 5, 1048597, 393217, 5, 1114133, 458753, 5, 1179669, 262145, 5, 917526, 327681, 5, 983062, 393217, 5, 1048598, 393217, 5, 1114134, 458753, 5, 1179670, 458753, 5, 917527, 458753, 5, 983063, 327681, 5, 1048599, 458753, 5, 1114135, 327681, 5, 1179671, 393217, 5, 917528, 393217, 5, 983064, 393217, 5, 1048600, 262145, 5, 917529, 393217, 5, 983065, 262145, 5, 1048601, 458753, 5, 2293769, 327681, 5, 2293770, 262145, 5, 2293771, 393217, 5, 2293772, 393217, 5, 1245200, 458753, 5, 1310736, 393217, 5, 1376272, 393217, 5, 1441808, 458753, 5, 1507344, 327681, 5, 1572880, 458753, 5, 1638416, 262145, 2, 1703952, 65537, 2, 1245201, 393217, 5, 1310737, 262145, 5, 1376273, 393217, 5, 1441809, 458753, 5, 1507345, 393217, 5, 1572881, 262145, 5, 1638417, 458753, 5, 1703953, 458753, 5, 1769489, 393217, 5, 1835025, 458753, 5, 1900561, 458753, 2, 1245202, 262145, 5, 1310738, 262145, 5, 1376274, 458753, 6, 1441810, 327681, 6, 1507346, 327681, 5, 1572882, 262145, 5, 1638418, 327681, 5, 1703954, 458753, 2, 1769490, 327681, 5, 1835026, 131073, 2, 1900562, 327681, 5, 1245203, 262145, 5, 1310739, 262145, 5, 1376275, 393217, 6, 1441811, 327681, 6, 1507347, 262145, 6, 1572883, 393217, 5, 1638419, 131073, 2, 1703955, 393217, 5, 1769491, 262145, 5, 1835027, 327681, 5, 1900563, 327681, 5, 1245204, 327681, 5, 1310740, 393217, 5, 1376276, 262145, 5, 1441812, 327681, 6, 1507348, 393217, 6, 1572884, 458753, 5, 1638420, 458753, 5, 1703956, 393217, 5, 1769492, 262145, 5, 1835028, 327681, 5, 1900564, 327681, 5, 1245205, 262145, 5, 1310741, 262145, 5, 1376277, 262145, 5, 1441813, 458753, 5, 1507349, 393217, 5, 1572885, 262145, 5, 1638421, 393217, 5, 1703957, 327681, 5, 1769493, 458753, 5, 1835029, 458753, 5, 1900565, 327681, 5, 1245206, 327681, 5, 1310742, 327681, 5, 1376278, 262145, 5, 1441814, 327681, 5, 1507350, 458753, 5, 1572886, 393217, 5, 1245207, 327681, 5, 1310743, 262145, 5, 1376279, 393217, 5, 1441815, 393217, 5, 1507351, 393217, 5, 1572887, 393217, 5, 1310744, 327681, 5, 1376280, 262145, 5, 1441816, 262145, 5, 1507352, 262145, 5, 1572888, 327681, 5, -131046, 196609, 6, -65510, 458753, 5, 26, 327681, 5, 65562, 458753, 4, 131098, 393217, 5, 196634, 393217, 2, 262170, 262145, 4, 327706, 327681, 5, 393242, 327681, 4, 458778, 196609, 6, 524314, 458753, 5, 589850, 327681, 5, 655386, 262145, 5, 720922, 393217, 5, 786458, 262145, 6, 851994, 327681, 6, 917530, 458753, 6, 983066, 327681, 5, 1048602, 327681, 5, -131045, 65537, 1, -65509, 327681, 5, 27, 458753, 5, 65563, 262145, 5, 131099, 458753, 4, 196635, 131073, 6, 262171, 1, 1, 327707, 1, 1, 393243, 1, 1, 458779, 327681, 6, 524315, 393217, 5, 589851, 262145, 5, 655387, 458753, 5, 720923, 458753, 6, 786459, 458753, 6, 851995, 458753, 6, 917531, 327681, 6, 983067, 262145, 5, 1048603, 458753, 5, -131044, 393217, 5, -65508, 393217, 5, 28, 262145, 5, 65564, 1, 0, 131100, 65537, 6, 196636, 262145, 6, 262172, 65537, 6, 327708, 196609, 6, 393244, 458753, 6, 458780, 262145, 6, 524316, 196609, 0, 589852, 327681, 5, 655388, 327681, 5, 720924, 393217, 6, 786460, 327681, 6, 851996, 393217, 6, 917532, 393217, 6, 983068, 393217, 5, 1048604, 393217, 5, -131043, 327681, 5, -65507, 262145, 5, 29, 327681, 5, 65565, 1, 0, 131101, 1, 6, 196637, 262145, 6, 262173, 65537, 6, 327709, 393217, 6, 393245, 327681, 6, 458781, 393217, 6, 524317, 65537, 0, 589853, 458753, 5, 655389, 458753, 5, 720925, 458753, 6, 786461, 458753, 6, 851997, 393217, 6, 917533, 262145, 6, 983069, 327681, 5, 1048605, 458753, 5, -131042, 262145, 5, -65506, 393217, 5, 30, 262145, 5, 65566, 1, 0, 131102, 262145, 6, 196638, 262145, 6, 262174, 65537, 6, 327710, 65537, 6, 393246, 262145, 6, 458782, 327681, 6, 524318, 327681, 5, 589854, 393217, 5, 655390, 458753, 5, 720926, 327681, 6, 786462, 327681, 6, 851998, 327681, 6, 917534, 262145, 5, 983070, 327681, 5, 1048606, 393217, 5, -131041, 393217, 5, -65505, 327681, 5, 31, 393217, 5, 65567, 458753, 2, 131103, 262145, 6, 196639, 131073, 6, 262175, 327681, 6, 327711, 65537, 6, 393247, 458753, 6, 458783, 262145, 6, 524319, 262145, 5, 589855, 393217, 5, 655391, 327681, 5, 720927, 327681, 6, 786463, 262145, 6, 851999, 393217, 5, 917535, 262145, 5, 983071, 393217, 5, 1048607, 262145, 5, -131040, 327681, 5, -65504, 458753, 5, 32, 458753, 5, 65568, 458753, 2, 131104, 262145, 5, 196640, 131073, 6, 262176, 327681, 6, 327712, 393217, 6, 393248, 393217, 6, 458784, 458753, 5, 524320, 327681, 5, 589856, 393217, 5, 655392, 393217, 5, 720928, 393217, 5, 786464, 327681, 5, 852000, 393217, 5, 917536, 393217, 5, 983072, 262145, 5, 1048608, 393217, 5, -131039, 393217, 5, -65503, 262145, 5, 33, 458753, 5, 65569, 262145, 5, 131105, 393217, 5, 196641, 393217, 5, 262177, 393217, 5, 327713, 262145, 5, 393249, 327681, 5, 458785, 393217, 5, 524321, 458753, 5, 589857, 458753, 5, 655393, 393217, 5, 720929, 458753, 5, 786465, 393217, 5, 852001, 327681, 5, 917537, 458753, 5, 983073, 262145, 5, 1048609, 393217, 5, 851976, 458753, 5, 851977, 327681, 5, 851978, 327681, 5, 851979, 458753, 5, 851980, 262145, 5, 851981, 327681, 5, 851982, 262145, 5, 851983, 327681, 5, 851984, 327681, 5, 851985, 327681, 5, 851986, 458753, 5, 851987, 458753, 5, 851988, 327681, 5, 131092, 262145, 2, 196628, 327681, 5, 262164, 458753, 5, 327700, 327681, 5, 393236, 458753, 2, 458772, 262145, 5, 524308, 327681, 5, 589844, 327681, 5, 655380, 327681, 5, 720916, 458753, 5, 786452, 458753, 2, 65556, 393217, 5, -983016, 458753, 5, -917480, 262145, 5, -851944, 393217, 5, -786408, 262145, 5, -720872, 393217, 5, -655336, 327681, 5, -589800, 262145, 5, -524264, 458753, 5, -458728, 458753, 5, -393192, 458753, 5, -327656, 393217, 5, -262120, 393217, 5, -2031592, 262145, 5, -1966056, 262145, 5, -1900520, 327681, 5, -1834984, 262145, 5, -1769448, 393217, 5, -1703912, 327681, 5, -1638376, 393217, 5, -1572840, 327681, 5, -1507304, 458753, 5, -1441768, 458753, 5, -1376232, 262145, 5, -1310696, 393217, 5, -1245160, 327681, 5, -1179624, 262145, 5, -1114088, 327681, 5, -1048552, 327681, 5, -2162664, 458753, 5, -2097128, 393217, 5, -2490365, 262145, 5, -2490364, 393217, 5, -2490363, 262145, 5, -2490362, 327681, 5, -2490361, 327681, 5, -2490360, 458753, 5, -2490359, 393217, 5, -2490358, 393217, 5, -2490357, 327681, 5, -2490356, 393217, 5, -2490355, 393217, 5, -2490354, 262145, 5, -2490353, 393217, 5, -2490352, 327681, 5, -2490351, 393217, 2, -2424840, 458753, 5, -2424839, 393217, 5, -2424838, 262145, 5, -2424837, 262145, 5, -2424836, 393217, 5, -2424835, 262145, 5, -2424834, 458753, 5, -2424833, 327681, 5, -2490368, 393217, 5, -2490367, 327681, 5, -2490366, 327681, 5, -1245197, 2, 0, -1114087, 327681, 5, -917492, 2, 0, -983028, 2, 0, 1703939, 458753, 5, 1769475, 262145, 5, 1835011, 458753, 5, 1703944, 262145, 5, 1769480, 458753, 5, 1835016, 393217, 5, 2359298, 458753, 5, 2424834, 393217, 5, 2490370, 393217, 5, 2555906, 393217, 5, 2359299, 458753, 5, 2424835, 262145, 5, 2490371, 262145, 5, 2555907, 262145, 5, 2359304, 458753, 5, 2424840, 393217, 5, 2490376, 262145, 5, 2555912, 327681, 5, 2359305, 458753, 5, 2424841, 327681, 5, 2490377, 327681, 5, 2555913, 327681, 5, 2359306, 262145, 5, 2424842, 393217, 5, 2490378, 393217, 5, 2555914, 393217, 5, 2359307, 458753, 5, 2424843, 327681, 5, 2490379, 393217, 5, 2555915, 393217, 5, 2359308, 393217, 5, 2424844, 393217, 5, 2490380, 393217, 5, 2555916, 327681, 5, 2490381, 393217, 5, 2555917, 327681, 5, 2621442, 327681, 5, 2621443, 393217, 5, 2490382, 393217, 5, 2555918, 262145, 5, 2490383, 393217, 5, 2555919, 327681, 5, 2490384, 327681, 5, 2555920, 458753, 5, 2490385, 262145, 5, 2555921, 327681, 5, 2490386, 327681, 5, 2555922, 327681, 5, 2490387, 327681, 5, 2555923, 262145, 5, 2490388, 262145, 5, 2555924, 262145, 5, 2490389, 458753, 5, 2555925, 393217, 5, 2621448, 458753, 5, 2621449, 458753, 5, 2621450, 262145, 5, 2621451, 393217, 5, 2621452, 458753, 5, 2621453, 393217, 5, 2621454, 327681, 5, 2621455, 393217, 5, 2621456, 393217, 5, 2621457, 458753, 5, 2621458, 393217, 5, 2621459, 262145, 5, 2621460, 393217, 5, 2686984, 327681, 5, 2752520, 65537, 2, 2818056, 458753, 5, 2883592, 458753, 5, 2949128, 327681, 5, 3014664, 458753, 5, 3080200, 458753, 5, 3145736, 327681, 5, 3211272, 458753, 5, 3276808, 65537, 2, 2686985, 393217, 5, 2752521, 327681, 5, 2818057, 262145, 5, 2883593, 458753, 5, 2949129, 327681, 5, 3014665, 327681, 5, 3080201, 458753, 5, 3145737, 196609, 2, 3211273, 393217, 5, 3276809, 262145, 5, 2686986, 393217, 5, 2752522, 262145, 5, 2818058, 262145, 5, 2883594, 458753, 5, 2949130, 262145, 5, 3014666, 65537, 2, 3080202, 393217, 5, 3145738, 393217, 5, 3211274, 262145, 5, 3276810, 458753, 5, 2686987, 131073, 2, 2752523, 262145, 5, 2818059, 327681, 5, 2883595, 458753, 5, 2949131, 393217, 5, 3014667, 65537, 2, 3080203, 262145, 5, 3145739, 458753, 5, 3211275, 327681, 5, 3276811, 327681, 5, 2686988, 393217, 5, 2752524, 262145, 5, 2818060, 327681, 5, 2883596, 458753, 5, 2949132, 327681, 5, 3014668, 262145, 5, 3080204, 262145, 5, 3145740, 262145, 5, 3211276, 393217, 5, 3276812, 393217, 5, 2686989, 458753, 5, 2752525, 458753, 5, 2818061, 393217, 5, 2883597, 131073, 2, 2949133, 458753, 5, 3014669, 458753, 5, 3080205, 327681, 5, 3145741, 458753, 5, 3211277, 393217, 5, 3276813, 458753, 5, 2686990, 65537, 2, 2752526, 393217, 5, 2818062, 393217, 5, 2883598, 327681, 5, 2949134, 458753, 5, 3014670, 327681, 5, 3080206, 458753, 5, 3145742, 393217, 5, 3211278, 1, 2, 3276814, 262145, 5, 2686991, 262145, 5, 2752527, 327681, 5, 2818063, 262145, 5, 2883599, 393217, 5, 2949135, 131073, 2, 3014671, 196609, 2, 3080207, 262145, 5, 3145743, 458753, 5, 3211279, 262145, 5, 3276815, 327681, 5, 2686992, 393217, 5, 2752528, 262145, 5, 2818064, 262145, 5, 2883600, 327681, 5, 2949136, 458753, 5, 3014672, 262145, 5, 3080208, 131073, 2, 3145744, 458753, 5, 3211280, 458753, 5, 3276816, 393217, 5, 2686993, 327681, 5, 2752529, 262145, 5, 2818065, 327681, 5, 2883601, 327681, 5, 2949137, 458753, 5, 3014673, 458753, 5, 3080209, 1, 2, 3145745, 262145, 5, 3211281, 393217, 5, 3276817, 393217, 5, 2686994, 196609, 2, 2752530, 393217, 5, 2818066, 65537, 2, 2883602, 327681, 5, 2949138, 458753, 5, 3014674, 327681, 5, 3080210, 458753, 5, 3145746, 393217, 5, 3211282, 393217, 5, 3276818, 262145, 5, 2686995, 393217, 5, 2752531, 393217, 5, 2818067, 458753, 5, 2883603, 1, 2, 2949139, 393217, 5, 3014675, 327681, 5, 3080211, 262145, 5, 3145747, 327681, 5, 3211283, 393217, 5, 3276819, 327681, 5, 2686996, 458753, 5, 2752532, 327681, 5, 2818068, 393217, 5, 2883604, 262145, 5, 2949140, 131073, 2, 3014676, 458753, 5, 2686997, 327681, 5, 2752533, 327681, 5, 2818069, 393217, 5, 2883605, 327681, 5, 2949141, 393217, 5, 3014677, 393217, 5, 2686978, 262145, 5, 2752514, 262145, 5, 2818050, 458753, 5, 2883586, 262145, 5, 2686979, 327681, 5, 2752515, 458753, 5, 2818051, 327681, 5, 2883587, 262145, 5, 2949123, 393217, 5, 2621461, 131073, 2, 852002, 327681, 5, 917538, 458753, 5, 983074, 458753, 5, 852003, 393217, 5, 917539, 327681, 5, 983075, 327681, 5, 852004, 458753, 5, 917540, 262145, 5, 983076, 393217, 5, 1769494, 393217, 5, 1835030, 458753, 5, 1900566, 393217, 5, 1769495, 327681, 5, 1835031, 393217, 5, 1900567, 393217, 5, 1638422, 327681, 5, 1703958, 393217, 5, 1638423, 262145, 5, 1703959, 262145, 5, 1638424, 393217, 5, 1703960, 327681, 5, -131037, 458753, 5, -65501, 262145, 5, 35, 262145, 5, 65571, 393217, 5, 131107, 262145, 5, 196643, 262145, 5, 262179, 393217, 5, 327715, 393217, 5, 393251, 262145, 5, 458787, 393217, 5, 524323, 458753, 5, 589859, 458753, 5, 655395, 327681, 5, 720931, 262145, 5, 786467, 262145, 5, -131036, 458753, 5, -65500, 458753, 5, 36, 262145, 5, 65572, 327681, 5, 131108, 458753, 5, 196644, 393217, 5, 262180, 327681, 5, 327716, 327681, 5, 393252, 458753, 5, 458788, 327681, 5, 524324, 393217, 5, 589860, 327681, 5, 655396, 327681, 5, 720932, 393217, 5, 786468, 327681, 5, -327643, 327681, 5, -262107, 327681, 5, -196571, 458753, 5, -131035, 327681, 5, -65499, 393217, 5, 37, 393217, 5, 65573, 393217, 5, 131109, 393217, 5, 196645, 393217, 5, 262181, 262145, 5, 327717, 458753, 5, 393253, 393217, 5, 458789, 458753, 5, 524325, 262145, 5, 589861, 458753, 5, 655397, 458753, 5, 720933, 327681, 5, -327642, 393217, 5, -262106, 262145, 5, -196570, 393217, 5, -131034, 327681, 5, -65498, 327681, 5, 38, 327681, 5, 65574, 327681, 5, 131110, 393217, 5, 196646, 458753, 5, 262182, 393217, 5, 327718, 262145, 5, 393254, 393217, 5, 458790, 458753, 5, 524326, 327681, 5, 589862, 393217, 5, 655398, 458753, 5, 720934, 458753, 5, -327641, 393217, 5, -262105, 393217, 5, -196569, 327681, 5, -131033, 393217, 5, -65497, 262145, 5, 39, 327681, 5, 65575, 393217, 5, 131111, 262145, 5, 196647, 393217, 5, 262183, 393217, 5, 327719, 393217, 5, 393255, 327681, 5, 458791, 458753, 5, 524327, 327681, 5, 589863, 393217, 5, 655399, 262145, 5, 720935, 262145, 5, -327640, 262145, 5, -262104, 393217, 5, -196568, 327681, 5, -131032, 458753, 5, -65496, 393217, 5, 40, 458753, 5, 65576, 327681, 5, 131112, 393217, 5, 196648, 393217, 5, 262184, 262145, 5, 327720, 327681, 5, 393256, 458753, 5, 458792, 262145, 5, 524328, 327681, 5, 589864, 458753, 5, 655400, 458753, 5, 720936, 262145, 5, -327639, 458753, 5, -262103, 393217, 5, -196567, 393217, 5, -131031, 327681, 5, -65495, 262145, 5, 41, 327681, 5, 65577, 327681, 5, 131113, 458753, 5, 196649, 458753, 5, 262185, 458753, 5, 327721, 393217, 5, 393257, 458753, 5, 458793, 262145, 5, 524329, 262145, 5, 589865, 262145, 5, 655401, 458753, 5, 720937, 262145, 5, -131038, 262145, 5, -65502, 393217, 5, 34, 393217, 5, 65570, 458753, 5, 131106, 262145, 5, 196642, 393217, 5, 262178, 327681, 5, 327714, 327681, 5, 393250, 262145, 5, 458786, 262145, 5, 524322, 327681, 5, 589858, 393217, 5, 655394, 458753, 5, 720930, 458753, 5, 786466, 262145, 5, -917540, 262145, 5, -852004, 393217, 5, -786468, 262145, 5, -720932, 458753, 5, -655396, 393217, 5, -589860, 262145, 5, -524324, 327681, 5, -458788, 458753, 5, -393252, 393217, 5, -327716, 393217, 5, -262180, 458753, 5, -196644, 393217, 5, -131108, 262145, 5, -983075, 327681, 5, -917539, 327681, 5, -852003, 458753, 5, -786467, 262145, 5, -720931, 458753, 5, -655395, 262145, 5, -589859, 393217, 5, -524323, 458753, 5, -458787, 458753, 5, -393251, 393217, 5, -327715, 458753, 5, -262179, 458753, 5, -196643, 393217, 5, -131107, 262145, 5, -1048610, 458753, 5, -983074, 458753, 5, -917538, 393217, 5, -852002, 393217, 5, -786466, 327681, 5, -720930, 458753, 5, -655394, 458753, 5, -589858, 262145, 5, -524322, 327681, 5, -458786, 327681, 5, -393250, 393217, 5, -327714, 262145, 5, -262178, 393217, 5, -196642, 393217, 5, -131106, 458753, 5, -1114145, 458753, 5, -1048609, 327681, 5, -983073, 458753, 5, -917537, 327681, 5, -852001, 458753, 5, -786465, 458753, 5, -720929, 393217, 5, -655393, 393217, 5, -589857, 327681, 5, -524321, 458753, 5, -458785, 458753, 5, -393249, 262145, 5, -327713, 393217, 5, -262177, 262145, 5, -196641, 262145, 5, -131105, 393217, 5, -65569, 393217, 5, -33, 262145, 5, 65503, 393217, 5, 131039, 262145, 5, 196575, 393217, 5, 262111, 262145, 5, 327647, 393217, 5, 393183, 458753, 5, 458719, 393217, 5, 524255, 393217, 5, 589791, 327681, 5, 655327, 262145, 5, -1179680, 327681, 5, -1114144, 327681, 5, -1048608, 262145, 5, -983072, 262145, 5, -917536, 327681, 5, -852000, 458753, 5, -786464, 393217, 5, -720928, 262145, 5, -655392, 327681, 5, -589856, 393217, 5, -524320, 262145, 5, -458784, 262145, 5, -393248, 262145, 5, -327712, 262145, 5, -262176, 458753, 5, -196640, 458753, 5, -131104, 393217, 5, -65568, 262145, 5, -32, 262145, 5, 65504, 393217, 5, 131040, 262145, 5, 196576, 458753, 5, 262112, 393217, 5, 327648, 262145, 5, 393184, 262145, 5, 458720, 393217, 5, 524256, 458753, 5, 589792, 393217, 5, 655328, 458753, 5, 720864, 327681, 5, -1179679, 327681, 5, -1114143, 458753, 5, -1048607, 262145, 5, -983071, 262145, 5, -917535, 458753, 5, -851999, 327681, 5, -786463, 393217, 5, -720927, 458753, 5, -655391, 262145, 5, -589855, 327681, 5, -524319, 458753, 5, -458783, 458753, 5, -393247, 458753, 5, -327711, 262145, 5, -262175, 327681, 5, -196639, 458753, 5, -131103, 393217, 5, -65567, 262145, 5, -31, 327681, 5, 65505, 458753, 5, 131041, 458753, 5, 196577, 458753, 5, 262113, 327681, 5, 327649, 327681, 5, 393185, 393217, 5, 458721, 393217, 5, 524257, 262145, 5, 589793, 393217, 5, 655329, 262145, 5, 720865, 327681, 5, -1179678, 458753, 5, -1114142, 327681, 5, -1048606, 393217, 5, -983070, 393217, 5, -917534, 393217, 5, -851998, 262145, 5, -786462, 458753, 5, -720926, 262145, 5, -655390, 262145, 5, -589854, 393217, 5, -524318, 327681, 5, -458782, 393217, 5, -393246, 458753, 5, -327710, 458753, 5, -262174, 458753, 5, -196638, 458753, 5, -131102, 458753, 5, -65566, 262145, 5, -30, 393217, 5, 65506, 262145, 5, 131042, 262145, 5, 196578, 327681, 5, 262114, 393217, 5, 327650, 458753, 5, 393186, 393217, 5, 458722, 327681, 5, 524258, 393217, 5, 589794, 262145, 5, 655330, 262145, 5, 720866, 393217, 5, -1179677, 458753, 5, -1114141, 393217, 5, -1048605, 393217, 5, -983069, 393217, 5, -917533, 262145, 5, -851997, 393217, 5, -786461, 458753, 5, -720925, 327681, 5, -655389, 262145, 5, -589853, 327681, 5, -524317, 458753, 5, -458781, 393217, 5, -393245, 262145, 5, -327709, 458753, 5, -262173, 262145, 5, -196637, 327681, 5, -131101, 327681, 5, -65565, 393217, 5, -29, 262145, 5, 65507, 393217, 5, 131043, 458753, 5, 196579, 393217, 5, 262115, 393217, 5, 327651, 327681, 5, 393187, 458753, 5, 458723, 458753, 5, 524259, 327681, 5, 589795, 458753, 5, 655331, 393217, 5, 720867, 458753, 5, -1179676, 458753, 5, -1114140, 458753, 5, -1048604, 262145, 5, -983068, 393217, 5, -917532, 262145, 5, -851996, 393217, 5, -786460, 458753, 5, -720924, 458753, 5, -655388, 327681, 5, -589852, 327681, 5, -524316, 262145, 5, -458780, 262145, 5, -393244, 458753, 5, -327708, 393217, 5, -262172, 327681, 5, -196636, 458753, 5, -131100, 262145, 5, -65564, 327681, 5, -28, 458753, 5, 65508, 458753, 5, 131044, 262145, 5, 196580, 458753, 5, 262116, 458753, 5, 327652, 393217, 5, 393188, 458753, 5, 458724, 458753, 5, 524260, 458753, 5, 589796, 327681, 5, 655332, 262145, 5, 720868, 458753, 5, -1179675, 262145, 5, -1114139, 458753, 5, -1048603, 458753, 5, -983067, 327681, 5, -917531, 262145, 5, -851995, 393217, 5, -786459, 458753, 5, -720923, 262145, 5, -655387, 393217, 5, -589851, 458753, 5, -524315, 393217, 5, -458779, 458753, 5, -393243, 458753, 5, -327707, 393217, 5, -262171, 393217, 5, -196635, 458753, 5, -131099, 458753, 5, -65563, 393217, 5, -27, 393217, 5, 65509, 327681, 5, 131045, 393217, 5, 196581, 458753, 5, 262117, 262145, 5, 327653, 393217, 5, 393189, 327681, 5, 458725, 393217, 5, 524261, 393217, 5, 589797, 458753, 5, 655333, 458753, 5, 720869, 327681, 5, 786405, 262145, 5, 851941, 458753, 5, 917477, 327681, 5, -1179674, 458753, 5, -1114138, 458753, 5, -1048602, 262145, 5, -983066, 458753, 5, -917530, 262145, 5, -851994, 458753, 5, -786458, 458753, 5, -720922, 327681, 5, -655386, 393217, 5, -589850, 458753, 5, -524314, 327681, 5, -458778, 458753, 5, -393242, 393217, 5, -327706, 262145, 5, -262170, 327681, 5, -196634, 262145, 5, -131098, 262145, 5, -65562, 327681, 5, -26, 393217, 5, 65510, 393217, 5, 131046, 262145, 5, 196582, 458753, 5, 262118, 327681, 5, 327654, 262145, 5, 393190, 262145, 5, 458726, 262145, 5, 524262, 262145, 5, 589798, 393217, 5, 655334, 458753, 5, 720870, 327681, 5, 786406, 262145, 5, 851942, 262145, 5, 917478, 393217, 5, 2293760, 262145, 5, 2359296, 327681, 5, 2424832, 458753, 5, 2490368, 458753, 5, 2555904, 458753, 5, 2621440, 262145, 5, 2686976, 458753, 5, 2752512, 393217, 5, 2293761, 393217, 5, 2359297, 458753, 5, 2424833, 262145, 5, 2490369, 327681, 5, 2555905, 327681, 5, 2621441, 458753, 5, 2686977, 327681, 5, 2752513, 458753, 5, 2818049, 458753, 5, 2293751, 327681, 5, 2293752, 327681, 5, 2293753, 327681, 5, 2293754, 327681, 5, 2293755, 262145, 5, 2293756, 458753, 5, 2293757, 458753, 5, 2293758, 327681, 5, 2293759, 262145, 5, 2228224, 262145, 5, 2228225, 458753, 5, 1376243, 262145, 5, 1441779, 327681, 5, 1507315, 327681, 5, 1572851, 262145, 5, 1638387, 393217, 5, 1703923, 393217, 5, 1769459, 393217, 5, 1834995, 327681, 5, 1900531, 262145, 5, 1966067, 393217, 5, 1376244, 458753, 5, 1441780, 327681, 5, 1507316, 327681, 5, 1572852, 327681, 5, 1638388, 262145, 5, 1703924, 262145, 5, 1769460, 393217, 5, 1834996, 393217, 5, 1900532, 393217, 5, 1966068, 327681, 5, 1376245, 458753, 5, 1441781, 458753, 5, 1507317, 393217, 5, 1572853, 262145, 5, 1638389, 393217, 5, 1703925, 262145, 5, 1769461, 458753, 5, 1834997, 458753, 5, 1900533, 262145, 5, 1966069, 327681, 5, 1376246, 327681, 5, 1441782, 327681, 5, 1507318, 458753, 5, 1572854, 262145, 5, 1638390, 393217, 5, 1703926, 458753, 5, 1769462, 262145, 5, 1834998, 393217, 5, 1900534, 327681, 5, 1966070, 393217, 5, 1376247, 327681, 5, 1441783, 262145, 5, 1507319, 327681, 5, 1572855, 262145, 5, 1638391, 327681, 5, 1703927, 458753, 5, 1769463, 393217, 5, 1834999, 262145, 5, 1900535, 393217, 5, 1966071, 458753, 5, 1376248, 327681, 5, 1441784, 393217, 5, 1507320, 458753, 5, 1572856, 393217, 5, 1638392, 393217, 5, 1703928, 458753, 5, 1769464, 393217, 5, 1835000, 458753, 5, 1900536, 393217, 5, 1966072, 327681, 5, 1376249, 262145, 5, 1441785, 262145, 5, 1507321, 393217, 5, 1572857, 458753, 5, 1638393, 327681, 5, 1703929, 458753, 5, 1769465, 262145, 5, 1835001, 327681, 5, 1900537, 458753, 5, 1966073, 458753, 5, 1376250, 262145, 5, 1441786, 458753, 5, 1507322, 327681, 5, 1572858, 327681, 5, 1638394, 458753, 5, 1703930, 458753, 5, 1769466, 393217, 5, 1835002, 262145, 5, 1900538, 327681, 5, 1966074, 262145, 5, 1376251, 327681, 5, 1441787, 262145, 5, 1507323, 262145, 5, 1572859, 327681, 5, 1638395, 262145, 5, 1703931, 393217, 5, 1769467, 262145, 5, 1835003, 262145, 5, 1900539, 262145, 5, 1966075, 393217, 5, 1376252, 262145, 5, 1441788, 327681, 5, 1507324, 327681, 5, 1572860, 393217, 5, 1638396, 327681, 5, 1703932, 458753, 5, 1769468, 262145, 5, 1835004, 262145, 5, 1900540, 327681, 5, 1966076, 393217, 5, 1376253, 393217, 5, 1441789, 262145, 5, 1507325, 458753, 5, 1572861, 458753, 5, 1638397, 327681, 5, 1703933, 458753, 5, 1769469, 393217, 5, 1835005, 327681, 5, 1900541, 262145, 5, 1966077, 327681, 5, 1376254, 262145, 5, 1441790, 393217, 5, 1507326, 262145, 5, 1572862, 458753, 5, 1638398, 393217, 5, 1703934, 393217, 5, 1769470, 458753, 5, 1835006, 327681, 5, 1900542, 262145, 5, 1966078, 458753, 5, 1376255, 393217, 5, 1441791, 393217, 5, 1507327, 393217, 5, 1572863, 327681, 5, 1638399, 393217, 5, 1703935, 262145, 5, 1769471, 393217, 5, 1835007, 327681, 5, 1900543, 458753, 5, 1966079, 262145, 5, 1310720, 393217, 5, 1376256, 262145, 5, 1441792, 262145, 5, 1507328, 262145, 5, 1572864, 327681, 5, 1638400, 262145, 5, 1703936, 393217, 5, 1769472, 262145, 5, 1835008, 393217, 5, 1900544, 393217, 5, 1310721, 262145, 5, 1376257, 262145, 5, 1441793, 262145, 5, 1507329, 327681, 5, 1572865, 327681, 5, 1638401, 393217, 5, 1703937, 393217, 5, 1769473, 458753, 5, 1835009, 262145, 5, 1900545, 262145, 5, 1310707, 458753, 5, 1310708, 262145, 5, 1310709, 262145, 5, 1310710, 458753, 5, 1310711, 327681, 5, 1310712, 262145, 5, 1310713, 393217, 5, 1310714, 262145, 5, 1310715, 327681, 5, 1310716, 327681, 5, 1310717, 262145, 5, 1310718, 327681, 5, 1310719, 327681, 5, 1245184, 327681, 5, 1245185, 458753, 5, 983027, 262145, 5, 1048563, 262145, 5, 1114099, 393217, 5, 1179635, 458753, 5, 1245171, 458753, 5, 983028, 327681, 5, 1048564, 327681, 5, 1114100, 458753, 5, 1179636, 327681, 5, 1245172, 458753, 5, 983029, 262145, 5, 1048565, 458753, 5, 1114101, 458753, 5, 1179637, 393217, 5, 1245173, 262145, 5, 917475, 262145, 5, 917476, 458753, 5, 983024, 262145, 5, 1048560, 262145, 5, 1114096, 262145, 5, 1179632, 262145, 5, 983025, 327681, 5, 1048561, 262145, 5, 1114097, 458753, 5, 1179633, 262145, 5, 983026, 262145, 5, 1048562, 327681, 5, 1114098, 262145, 5, 1179634, 262145, 5, 2293773, 262145, 5, 2359309, 262145, 5, 2293774, 262145, 5, 2359310, 262145, 5, 2293775, 393217, 5, 2359311, 327681, 5, 2293776, 393217, 5, 2359312, 327681, 5, 2293777, 327681, 5, 2359313, 458753, 5, 2293778, 393217, 5, 2359314, 458753, 5, 2293779, 458753, 5, 2359315, 262145, 5, 2228233, 262145, 5, 2228234, 262145, 5, 2228235, 393217, 5, 2228236, 327681, 5, 2228237, 458753, 5, 2424845, 327681, 5, 2228238, 327681, 5, 2424846, 262145, 5, 2228239, 262145, 5, 2424847, 393217, 5, 2228240, 458753, 5, 2424848, 458753, 5, 2228241, 458753, 5, 2424849, 262145, 5, 2228242, 393217, 5, 2424850, 458753, 5, 2228243, 262145, 5, 2424851, 262145, 5, 2228244, 458753, 5, 2293780, 458753, 5, 2359316, 262145, 5, 2424852, 262145, 5, 2228245, 262145, 5, 2293781, 262145, 5, 2359317, 458753, 5, 2424853, 393217, 5, 2228246, 393217, 5, 2293782, 458753, 5, 2359318, 458753, 5, 2424854, 458753, 5, 2228247, 262145, 5, 2293783, 262145, 5, 2359319, 458753, 5, 2424855, 327681, 5, 2228248, 262145, 5, 2293784, 262145, 5, 2359320, 262145, 5, 2424856, 393217, 5, 2490390, 393217, 5, 2555926, 262145, 5, 2621462, 393217, 5, 2686998, 393217, 5, 2752534, 327681, 5, 2818070, 327681, 5, 2883606, 262145, 5, 2949142, 262145, 5, 3014678, 262145, 5, 2490391, 393217, 5, 2555927, 327681, 5, 2621463, 458753, 5, 2686999, 393217, 5, 2752535, 393217, 5, 2818071, 458753, 5, 2883607, 262145, 5, 2949143, 393217, 5, 3014679, 458753, 5, 2490392, 393217, 5, 2555928, 458753, 5, 2621464, 458753, 5, 2687000, 458753, 5, 2752536, 458753, 5, 2818072, 327681, 5, 1703973, 262145, 5, 1769509, 262145, 5, 1835045, 327681, 5, 1900581, 393217, 5, 1703974, 327681, 5, 1769510, 393217, 5, 1835046, 262145, 5, 1900582, 262145, 5, 1703975, 458753, 5, 1769511, 327681, 5, 1835047, 327681, 5, 1900583, 327681, 5, 1703976, 262145, 5, 1703977, 458753, 5, 1703978, 262145, 5, 786469, 262145, 5, 852005, 458753, 5, 917541, 262145, 5, 983077, 393217, 5, 1048613, 393217, 5, 1114149, 458753, 5, 1179685, 393217, 5, 1245221, 458753, 5, 1310757, 458753, 5, 1376293, 327681, 5, 1441829, 393217, 5, 1507365, 393217, 5, 1572901, 393217, 5, 1638437, 327681, 5, 786470, 327681, 5, 852006, 327681, 5, 917542, 458753, 5, 983078, 458753, 5, 1048614, 458753, 5, 1114150, 458753, 5, 1179686, 458753, 5, 1245222, 393217, 5, 1310758, 327681, 5, 1376294, 327681, 5, 1441830, 393217, 5, 1507366, 393217, 5, 1572902, 458753, 5, 1638438, 393217, 5, 786471, 262145, 5, 852007, 393217, 5, 917543, 393217, 5, 983079, 393217, 5, 1048615, 458753, 5, 1114151, 327681, 5, 1179687, 327681, 5, 1245223, 262145, 5, 1310759, 393217, 5, 1376295, 393217, 5, 1441831, 393217, 5, 1507367, 458753, 5, 1572903, 262145, 5, 1638439, 458753, 5, 786472, 262145, 5, 852008, 393217, 5, 917544, 327681, 5, 983080, 327681, 5, 1048616, 327681, 5, 1114152, 327681, 5, 1179688, 458753, 5, 1245224, 458753, 5, 1310760, 393217, 5, 1376296, 327681, 5, 1441832, 393217, 5, 1507368, 262145, 5, 1572904, 393217, 5, 1638440, 262145, 5, 1114136, 327681, 5, 1114137, 393217, 5, 1114138, 393217, 5, 1114139, 393217, 5, 1114140, 262145, 5, 1114141, 458753, 5, 1114142, 458753, 5, 1114143, 262145, 5, 1114144, 458753, 5, 1114145, 393217, 5, 1048610, 393217, 5, 1114146, 458753, 5, 1048611, 327681, 5, 1114147, 327681, 5, 1048612, 327681, 5, 1114148, 262145, 5, 1179672, 327681, 5, 1245208, 458753, 5, 1769496, 393217, 5, 1835032, 458753, 5, 1900568, 393217, 5, 786401, 393217, 5, 786402, 262145, 5, 851938, 262145, 5, 786403, 393217, 5, 851939, 458753, 5, 786404, 393217, 5, 851940, 262145, 5, -327727, 458753, 5, -262191, 393217, 5, -393262, 458753, 5, -327726, 458753, 5, -458797, 327681, 5, -393261, 393217, 5, -327725, 458753, 5, -262189, 458753, 5, -458796, 327681, 5, -393260, 393217, 5, -327724, 262145, 5, -262188, 262145, 5, -196652, 327681, 5, -458795, 393217, 5, -393259, 262145, 5, -327723, 262145, 5, -262187, 262145, 5, -196651, 458753, 5, -131115, 458753, 5, -524330, 458753, 5, -458794, 262145, 5, -393258, 262145, 5, -327722, 262145, 5, -262186, 393217, 5, -196650, 458753, 5, -131114, 458753, 5, -589865, 262145, 5, -524329, 327681, 5, -458793, 393217, 5, -393257, 327681, 5, -327721, 327681, 5, -262185, 327681, 5, -196649, 458753, 5, -131113, 327681, 5, -655400, 327681, 5, -589864, 458753, 5, -524328, 327681, 5, -458792, 458753, 5, -393256, 262145, 5, -327720, 458753, 5, -262184, 393217, 5, -196648, 327681, 5, -131112, 393217, 5, -720935, 262145, 5, -655399, 262145, 5, -589863, 458753, 5, -524327, 393217, 5, -458791, 262145, 5, -393255, 393217, 5, -327719, 393217, 5, -262183, 262145, 5, -196647, 393217, 5, -131111, 393217, 5, -786470, 262145, 5, -720934, 262145, 5, -655398, 458753, 5, -589862, 327681, 5, -524326, 262145, 5, -458790, 262145, 5, -393254, 458753, 5, -327718, 262145, 5, -262182, 393217, 5, -196646, 262145, 5, -131110, 458753, 5, -852005, 393217, 5, -786469, 458753, 5, -720933, 393217, 5, -655397, 393217, 5, -589861, 458753, 5, -524325, 393217, 5, -458789, 262145, 5, -393253, 458753, 5, -327717, 458753, 5, -262181, 393217, 5, -196645, 393217, 5, -131109, 262145, 5, 1179693, 458753, 5, 1245229, 458753, 5, 1310765, 262145, 5, 1376301, 327681, 5, 1179694, 393217, 5, 1179695, 458753, 5, 1179696, 262145, 5, 1179697, 458753, 5, 786473, 458753, 5, 852009, 262145, 5, 327722, 262145, 5, 393258, 458753, 5, 458794, 458753, 5, 524330, 458753, 5, 589866, 262145, 5, 655402, 393217, 5, 720938, 327681, 5, 786474, 262145, 5, 852010, 262145, 5, 327723, 393217, 5, 393259, 262145, 5, 458795, 327681, 5, 524331, 262145, 5, 589867, 458753, 5, 655403, 393217, 5, 720939, 393217, 5, 786475, 393217, 5, 852011, 262145, 5, 327724, 393217, 5, 393260, 327681, 5, 458796, 458753, 5, 524332, 393217, 5, 589868, 327681, 5, 655404, 458753, 5, 720940, 327681, 5, 786476, 262145, 5, 852012, 262145, 5, 327725, 393217, 5, 393261, 458753, 5, 458797, 393217, 5, 524333, 262145, 5, 589869, 262145, 5, 655405, 327681, 5, 720941, 327681, 5, 786477, 327681, 5, 852013, 393217, 5, 327726, 262145, 5, 393262, 393217, 5, 458798, 458753, 5, 524334, 393217, 5, 589870, 327681, 5, 655406, 262145, 5, 720942, 327681, 5, 786478, 262145, 5, 852014, 327681, 5, 327727, 327681, 5, 393263, 327681, 5, 458799, 458753, 5, 524335, 458753, 5, 589871, 327681, 5, 655407, 327681, 5, 720943, 262145, 5, 786479, 393217, 5, 852015, 458753, 5, 327728, 393217, 5, 393264, 262145, 5, 458800, 327681, 5, 524336, 458753, 5, 589872, 458753, 5, 655408, 262145, 5, 720944, 327681, 5, 786480, 262145, 5, 852016, 458753, 5, 327729, 458753, 5, 393265, 327681, 5, 458801, 458753, 5, 524337, 327681, 5, 589873, 393217, 5, 655409, 393217, 5, 720945, 262145, 5, 786481, 393217, 5, 852017, 458753, 5, 327730, 262145, 5, 393266, 262145, 5, 458802, 458753, 5, 524338, 458753, 5, 589874, 262145, 5, 655410, 458753, 5, 720946, 393217, 5, 786482, 393217, 5, 852018, 458753, 5, 327731, 327681, 5, 393267, 393217, 5, 458803, 458753, 5, 524339, 262145, 5, 589875, 458753, 5, 655411, 458753, 5, 720947, 458753, 5, 786483, 393217, 5, 852019, 327681, 5, 327732, 458753, 5, 393268, 327681, 5, 458804, 262145, 5, 524340, 393217, 5, 589876, 458753, 5, 655412, 393217, 5, 720948, 458753, 5, 786484, 458753, 5, 852020, 327681, 5, 327733, 458753, 5, 393269, 262145, 5, 458805, 458753, 5, 524341, 327681, 5, 589877, 262145, 5, 655413, 458753, 5, 720949, 327681, 5, 786485, 327681, 5, 852021, 262145, 5, 327734, 262145, 5, 393270, 458753, 5, 458806, 458753, 5, 524342, 458753, 5, 589878, 393217, 5, 655414, 458753, 5, 720950, 393217, 5, 786486, 262145, 5, 327735, 262145, 5, 393271, 262145, 5, 458807, 327681, 5, 524343, 458753, 5, 589879, 262145, 5, 655415, 458753, 5, 720951, 458753, 5, 786487, 262145, 5, 327736, 327681, 5, 393272, 393217, 5, 458808, 393217, 5, 524344, 393217, 5, 589880, 458753, 5, 655416, 458753, 5, 720952, 327681, 5, 786488, 327681, 5, 327737, 458753, 5, 393273, 458753, 5, 458809, 393217, 5, 327738, 262145, 5, 393274, 458753, 5, 458810, 393217, 5, -524251, 262145, 5, -458715, 458753, 5, -393179, 393217, 5, -524250, 262145, 5, -458714, 458753, 5, -393178, 262145, 5, -524249, 327681, 5, -458713, 393217, 5, -393177, 393217, 5, -524248, 327681, 5, -458712, 327681, 5, -393176, 393217, 5, -524247, 393217, 5, -458711, 327681, 5, -393175, 262145, 5, -524246, 262145, 5, -458710, 458753, 5, -393174, 393217, 5, -327638, 262145, 5, -262102, 458753, 5, -196566, 327681, 5, -131030, 262145, 5, -65494, 393217, 5, 42, 393217, 5, 65578, 393217, 5, 131114, 458753, 5, 196650, 458753, 5, 262186, 327681, 5, -524245, 458753, 5, -458709, 458753, 5, -393173, 393217, 5, -327637, 458753, 5, -262101, 458753, 5, -196565, 458753, 5, -131029, 393217, 5, -65493, 458753, 5, 43, 327681, 5, 65579, 393217, 5, 131115, 327681, 5, 196651, 327681, 5, 262187, 458753, 5, -524244, 327681, 5, -458708, 393217, 5, -393172, 262145, 5, -327636, 262145, 5, -262100, 393217, 5, -196564, 458753, 5, -131028, 327681, 5, -65492, 393217, 5, 44, 262145, 5, 65580, 393217, 5, 131116, 262145, 5, 196652, 262145, 5, 262188, 327681, 5, -524243, 262145, 5, -458707, 262145, 5, -393171, 458753, 5, -327635, 327681, 5, -262099, 458753, 5, -196563, 393217, 5, -131027, 262145, 5, -65491, 393217, 5, 45, 458753, 5, 65581, 458753, 5, 131117, 458753, 5, 196653, 458753, 5, 262189, 393217, 5, -524242, 393217, 5, -458706, 393217, 5, -393170, 327681, 5, -327634, 458753, 5, -262098, 262145, 5, -196562, 393217, 5, -131026, 327681, 5, -65490, 262145, 5, 46, 262145, 5, 65582, 262145, 5, 131118, 393217, 5, 196654, 393217, 5, 262190, 393217, 5, -524241, 327681, 5, -458705, 393217, 5, -393169, 458753, 5, -327633, 327681, 5, -262097, 393217, 5, -196561, 393217, 5, -131025, 393217, 5, -65489, 262145, 5, 47, 262145, 5, 65583, 393217, 5, 131119, 458753, 5, 196655, 393217, 5, 262191, 393217, 5, -524240, 393217, 5, -458704, 262145, 5, -393168, 393217, 5, -327632, 262145, 5, -262096, 393217, 5, -196560, 327681, 5, -131024, 393217, 5, -65488, 327681, 5, 48, 327681, 5, 65584, 393217, 5, 131120, 458753, 5, 196656, 327681, 5, 262192, 393217, 5, -524239, 262145, 5, -458703, 458753, 5, -393167, 262145, 5, -327631, 458753, 5, -262095, 393217, 5, -196559, 262145, 5, -131023, 327681, 5, -65487, 458753, 5, 49, 393217, 5, 65585, 393217, 5, 131121, 458753, 5, 196657, 458753, 5, 262193, 393217, 5, -393166, 327681, 5, -327630, 327681, 5, -262094, 458753, 5, -196558, 327681, 5, -131022, 393217, 5, -65486, 393217, 5, 50, 393217, 5, 65586, 262145, 5, 131122, 393217, 5, 196658, 393217, 5, 262194, 327681, 5, -327629, 262145, 5, -262093, 393217, 5, -196557, 327681, 5, -131021, 327681, 5, -65485, 327681, 5, 51, 327681, 5, 65587, 393217, 5, 131123, 327681, 5, 196659, 327681, 5, 262195, 327681, 5, -262092, 327681, 5, -196556, 458753, 5, -131020, 262145, 5, -65484, 393217, 5, 52, 458753, 5, 65588, 458753, 5, 131124, 327681, 5, 196660, 262145, 5, 262196, 327681, 5, -262091, 458753, 5, -196555, 262145, 5, -131019, 393217, 5, -65483, 393217, 5, 53, 327681, 5, 65589, 393217, 5, 131125, 458753, 5, 196661, 262145, 5, 262197, 393217, 5, -131018, 327681, 5, -65482, 393217, 5, 54, 458753, 5, 65590, 393217, 5, 131126, 327681, 5, 196662, 262145, 5, 262198, 327681, 5, -65481, 458753, 5, 55, 393217, 5, 65591, 458753, 5, 131127, 458753, 5, 196663, 393217, 5, 262199, 327681, 5, 65592, 327681, 5, 131128, 327681, 5, 196664, 458753, 5, 262200, 393217, 5, 131129, 458753, 5, 196665, 393217, 5, 262201, 393217, 5, 196666, 458753, 5, 262202, 262145, 5, 196667, 458753, 5, 262203, 262145, 5, 327739, 262145, 5, 393275, 327681, 5, 458811, 327681, 5, 196668, 393217, 5, -851931, 458753, 5, -786395, 458753, 5, -720859, 327681, 5, -655323, 327681, 5, -589787, 458753, 5, -851930, 393217, 5, -786394, 393217, 5, -720858, 262145, 5, -655322, 458753, 5, -589786, 393217, 5, -851929, 327681, 5, -786393, 393217, 5, -720857, 393217, 5, -655321, 393217, 5, -589785, 458753, 5, -851928, 262145, 5, -786392, 262145, 5, -720856, 393217, 5, -655320, 393217, 5, -589784, 393217, 5, -851927, 458753, 5, -786391, 327681, 5, -720855, 458753, 5, -655319, 458753, 5, -589783, 458753, 5, -851926, 458753, 5, -786390, 262145, 5, -720854, 393217, 5, -655318, 262145, 5, -589782, 327681, 5, -851925, 262145, 5, -786389, 393217, 5, -720853, 262145, 5, -655317, 458753, 5, -589781, 458753, 5, -786388, 458753, 5, -720852, 327681, 5, -655316, 262145, 5, -589780, 393217, 5, -786387, 458753, 5, -720851, 327681, 5, -655315, 262145, 5, -589779, 458753, 5, -720850, 327681, 5, -655314, 262145, 5, -589778, 393217, 5, -655313, 393217, 5, -589777, 458753, 5, -589776, 327681, 5, -1179611, 262145, 5, -1114075, 327681, 5, -1048539, 327681, 5, -983003, 393217, 5, -917467, 327681, 5, -1179610, 262145, 5, -1114074, 262145, 5, -1048538, 393217, 5, -983002, 393217, 5, -917466, 327681, 5, -1114073, 393217, 5, -1048537, 458753, 5, -983001, 262145, 5, -917465, 458753, 5, -1048536, 262145, 5, -983000, 327681, 5, -917464, 327681, 5, -982999, 327681, 5, -917463, 393217, 5, -982998, 458753, 5, -917462, 458753, 5, 2097181, 262145, 5, 2162717, 262145, 5, 2228253, 327681, 5, 2293789, 458753, 5, 2359325, 393217, 5, 2424861, 327681, 5, 2490397, 262145, 5, 2555933, 458753, 5, 2097182, 458753, 5, 2162718, 458753, 5, 2228254, 393217, 5, 2293790, 327681, 5, 2359326, 262145, 5, 2424862, 458753, 5, 2490398, 327681, 5, 2555934, 458753, 5, 2097183, 262145, 5, 2162719, 262145, 5, 2228255, 327681, 5, 2293791, 458753, 5, 2359327, 262145, 5, 2424863, 458753, 5, 2490399, 262145, 5, 2555935, 262145, 5, 2097184, 458753, 5, 2162720, 458753, 5, 2228256, 458753, 5, 1441821, 458753, 5, 1507357, 393217, 5, 1572893, 262145, 5, 1638429, 393217, 5, 1703965, 458753, 5, 1769501, 327681, 5, 1835037, 262145, 5, 1900573, 393217, 5, 1966109, 262145, 5, 2031645, 393217, 5, 1441822, 393217, 5, 1507358, 393217, 5, 1572894, 327681, 5, 1638430, 327681, 5, 1703966, 327681, 5, 1769502, 458753, 5, 1835038, 393217, 5, 1900574, 393217, 5, 1966110, 262145, 5, 2031646, 393217, 5, 1441823, 262145, 5, 1507359, 458753, 5, 1572895, 393217, 5, 1638431, 262145, 5, 1703967, 327681, 5, 1769503, 327681, 5, 1835039, 262145, 5, 1900575, 393217, 5, 1966111, 393217, 5, 2031647, 393217, 5, 1441824, 458753, 5, 1507360, 393217, 5, 1572896, 458753, 5, 1638432, 393217, 5, 1703968, 393217, 5, 1769504, 327681, 5, 1835040, 327681, 5, 1900576, 393217, 5, 1966112, 327681, 5, 2031648, 393217, 5, -2686981, 327681, 5, -2621445, 458753, 5, -2555909, 327681, 5, -2490373, 327681, 5, -2686980, 262145, 5, -2621444, 327681, 5, -2555908, 393217, 5, -2490372, 262145, 5, -2686979, 262145, 5, -2621443, 327681, 5, -2555907, 327681, 5, -2490371, 393217, 5, -2686978, 327681, 5, -2621442, 393217, 5, -2555906, 327681, 5, -2490370, 393217, 5, -2686977, 327681, 5, -2621441, 327681, 5, -2555905, 458753, 5, -2490369, 393217, 5, -2752512, 393217, 5, -2686976, 327681, 5, -2621440, 262145, 5, -2555904, 327681, 5, -2752511, 262145, 5, -2686975, 393217, 5, -2621439, 327681, 5, -2555903, 458753, 5, -2490375, 262145, 5, -2490374, 327681, 5, -2555910, 393217, 5, -2883584, 393217, 5, -2818048, 327681, 5, -2883583, 393217, 5, -2818047, 458753, 5, -2883582, 393217, 5, -2818046, 262145, 5, -2752510, 393217, 5, -2686974, 327681, 5, -2621438, 393217, 5, -2555902, 262145, 5, -2883581, 458753, 5, -2818045, 458753, 5, -2752509, 393217, 5, -2686973, 262145, 5, -2621437, 262145, 5, -2555901, 262145, 5, -2883580, 393217, 5, -2818044, 458753, 5, -2752508, 458753, 5, -2686972, 327681, 5, -2621436, 262145, 5, -2555900, 458753, 5, -2883579, 327681, 5, -2818043, 262145, 5, -2752507, 458753, 5, -2686971, 393217, 5, -2621435, 327681, 5, -2555899, 327681, 5, -2883578, 262145, 5, -2818042, 393217, 5, -2752506, 458753, 5, -2686970, 458753, 5, -2621434, 262145, 5, -2555898, 327681, 5, -2883577, 458753, 5, -2818041, 327681, 5, -2752505, 262145, 5, -2686969, 393217, 5, -2621433, 458753, 5, -2555897, 327681, 5, -2818052, 327681, 5, -2752516, 458753, 5, -2818051, 458753, 5, -2752515, 458753, 5, -2818050, 393217, 5, -2752514, 393217, 5, -2818049, 262145, 5, -2752513, 327681, 5, -3014655, 393217, 5, -2949119, 393217, 5, -3014654, 393217, 5, -2949118, 393217, 5, -3014653, 262145, 5, -2949117, 458753, 5, -3014652, 458753, 5, -2949116, 458753, 5, -3014651, 458753, 5, -2949115, 262145, 5, -3014650, 327681, 5, -2949114, 262145, 5, -3014649, 262145, 5, -2949113, 262145, 5, -3145725, 327681, 5, -3080189, 327681, 5, -3145724, 393217, 5, -3080188, 393217, 5, -3145723, 393217, 5, -3080187, 458753, 5, -3145722, 327681, 5, -3080186, 393217, 5, -3145721, 327681, 5, -3080185, 393217, 5, -3080184, 327681, 5, -3014648, 393217, 5, -2949112, 458753, 5, -3014647, 458753, 5, -2949111, 458753, 5, -2949110, 327681, 5, -3342332, 327681, 5, -3276796, 393217, 5, -3211260, 327681, 5, -3276795, 262145, 5, -3211259, 458753, 5, -3211258, 262145, 5, -2883575, 393217, 5, -2883574, 327681, 5, -2883573, 262145, 5, -2883576, 393217, 5, -2818040, 393217, 5, -2752504, 393217, 5, -2686968, 262145, 5, -2621432, 458753, 5, -2555896, 262145, 5, -2818039, 458753, 5, -2752503, 458753, 5, -2686967, 393217, 5, -2621431, 393217, 5, -2555895, 327681, 5, -2818038, 458753, 5, -2752502, 393217, 5, -2686966, 458753, 5, -2621430, 458753, 5, -2555894, 458753, 5, -2818037, 393217, 5, -2752501, 393217, 5, -2686965, 262145, 5, -2621429, 393217, 5, -2555893, 327681, 5, -2818036, 393217, 5, -2752500, 327681, 5, -2686964, 458753, 5, -2621428, 327681, 5, -2555892, 327681, 5, -2752499, 458753, 5, -2686963, 327681, 5, -2621427, 458753, 5, -2555891, 327681, 5, -2686962, 262145, 5, -2621426, 262145, 5, -2555890, 262145, 5, -2621425, 458753, 5, -2555889, 393217, 5, -2555888, 393217, 5, -1245147, 262145, 5, -1245146, 458753, 5, -1310683, 327681, 5, -1310751, 262145, 5, -1245215, 327681, 5, -1376286, 262145, 5, -1310750, 458753, 5, -1245214, 458753, 5, -1376285, 458753, 5, -1310749, 458753, 5, -1245213, 458753, 5, -1441820, 458753, 5, -1376284, 393217, 5, -1310748, 393217, 5, -1245212, 327681, 5, -1507355, 393217, 5, -1441819, 393217, 5, -1376283, 458753, 5, -1310747, 393217, 5, -1245211, 262145, 5, -1507354, 262145, 5, -1441818, 327681, 5, -1376282, 262145, 5, -1310746, 327681, 5, -1245210, 458753, 5, -1638427, 327681, 5, -1572891, 458753, 5, -1638426, 393217, 5, -1572890, 393217, 5, -1638425, 393217, 5, -1572889, 458753, 5, -1507353, 262145, 5, -1441817, 393217, 5, -1376281, 458753, 5, -1638424, 327681, 5, -1572888, 327681, 5, -1507352, 458753, 5, -1441816, 393217, 5, -1638423, 393217, 5, -1572887, 327681, 5, -1507351, 262145, 5, -1638422, 262145, 5, -1572886, 393217, 5, -1703962, 393217, 5, -1703961, 262145, 5, -1703960, 393217, 5, -1703959, 393217, 5, -1703958, 393217, 5, -1703957, 327681, 5, -1638421, 262145, 5, -1703956, 327681, 5, -1769497, 393217, 5, -1835032, 262145, 5, -1769496, 458753, 5, -1900567, 327681, 5, -1835031, 393217, 5, -1769495, 393217, 5, -1900566, 458753, 5, -1835030, 393217, 5, -1769494, 262145, 5, -1900565, 262145, 5, -1835029, 393217, 5, -1769493, 262145, 5, -1900564, 458753, 5, -1835028, 458753, 5, -1769492, 458753, 5, -1900563, 458753, 5, -1835027, 327681, 5, -1769491, 327681, 5, -1900562, 458753, 5, -1835026, 327681, 5, -1900561, 458753, 5, -1966102, 327681, 5, -2031637, 262145, 5, -1966101, 393217, 5, -2097172, 393217, 5, -2031636, 458753, 5, -1966100, 458753, 5, -2097171, 458753, 5, -2031635, 458753, 5, -1966099, 458753, 5, -2097170, 393217, 5, -2031634, 393217, 5, -1966098, 327681, 5, -2097169, 458753, 5, -2031633, 393217, 5, -1966097, 393217, 5, -2097168, 393217, 5, -2031632, 262145, 5, -1966096, 327681, 5, -2162707, 458753, 5, -2228242, 262145, 5, -2162706, 458753, 5, -2228241, 262145, 5, -2162705, 393217, 5, -2228240, 458753, 5, -2162704, 262145, 5, -2228239, 458753, 5, -2162703, 393217, 5, -2097167, 458753, 5, -2031631, 458753, 5, -2228238, 393217, 5, -2162702, 327681, 5, -2097166, 327681, 5, -2293776, 393217, 5, -2359311, 262145, 5, -2293775, 262145, 5, -2359310, 393217, 5, -2293774, 393217, 5, -2424845, 262145, 5, -2359309, 458753, 5, -2293773, 393217, 5, -2228237, 458753, 5, -2162701, 458753, 5, -2818056, 327681, 5, -2752520, 393217, 5, -2686984, 393217, 5, -2621448, 262145, 5, -2555912, 262145, 5, -2490376, 458753, 5, -2883591, 327681, 5, -2818055, 393217, 5, -2752519, 327681, 5, -2686983, 327681, 5, -2621447, 458753, 5, -2555911, 458753, 5, -2949126, 262145, 5, -2883590, 458753, 5, -2818054, 458753, 5, -2752518, 393217, 5, -2686982, 327681, 5, -2621446, 262145, 5, -2949125, 262145, 5, -2883589, 262145, 5, -2818053, 327681, 5, -2752517, 393217, 5, -3145731, 262145, 5, -3080195, 327681, 5, -3014659, 262145, 5, -2949123, 327681, 5, -2883587, 458753, 5, -3014660, 262145, 5, -2949124, 327681, 5, -2883588, 327681, 5, -3211266, 327681, 5, -3145730, 327681, 5, -3080194, 393217, 5, -3014658, 327681, 5, -2949122, 458753, 5, -2883586, 393217, 5, -3276801, 458753, 5, -3211265, 262145, 5, -3145729, 393217, 5, -3080193, 458753, 5, -3014657, 393217, 5, -2949121, 327681, 5, -2883585, 458753, 5, -3342336, 262145, 5, -3276800, 393217, 5, -3211264, 327681, 5, -3145728, 393217, 5, -3080192, 327681, 5, -3014656, 393217, 5, -2949120, 262145, 5, -3407871, 458753, 5, -3342335, 393217, 5, -3276799, 393217, 5, -3211263, 327681, 5, -3145727, 327681, 5, -3080191, 262145, 5, -3473406, 327681, 5, -3407870, 458753, 5, -3342334, 393217, 5, -3276798, 393217, 5, -3211262, 262145, 5, -3145726, 262145, 5, -3080190, 262145, 5, -3407869, 393217, 5, -3342333, 393217, 5, -3276797, 458753, 5, -3211261, 393217, 5, 983012, 458753, 5, 983013, 458753, 5, 1048549, 458753, 5, 983014, 393217, 5, 1048550, 327681, 5, 1114086, 458753, 5, 983015, 262145, 5, 1048551, 393217, 5, 1114087, 393217, 5, 1179623, 393217, 5, 983016, 262145, 5, 1048552, 262145, 5, 1114088, 327681, 5, 1179624, 262145, 5, 983017, 262145, 5, 1048553, 458753, 5, 1114089, 262145, 5, 1179625, 393217, 5, 983018, 327681, 5, 1048554, 327681, 5, 1114090, 458753, 5, 1179626, 262145, 5, 983019, 458753, 5, 1048555, 458753, 5, 1114091, 262145, 5, 1179627, 262145, 5, 983020, 458753, 5, 1048556, 458753, 5, 1114092, 327681, 5, 1179628, 393217, 5, 1507308, 393217, 5, 983021, 262145, 5, 1048557, 262145, 5, 1114093, 458753, 5, 1179629, 458753, 5, 1507309, 458753, 5, 1572845, 262145, 5, 1638381, 393217, 5, 983022, 262145, 5, 1048558, 393217, 5, 1114094, 327681, 5, 1179630, 327681, 5, 1507310, 327681, 5, 1572846, 393217, 5, 1638382, 327681, 5, 1703918, 458753, 5, 983023, 393217, 5, 1048559, 327681, 5, 1114095, 327681, 5, 1179631, 458753, 5, -65578, 458753, 5, -65577, 458753, 5, -41, 393217, 5, -65576, 262145, 5, -40, 393217, 5, 65496, 262145, 5, -65575, 458753, 5, -39, 393217, 5, 65497, 327681, 5, 131033, 458753, 5, -65574, 393217, 5, -38, 393217, 5, 65498, 327681, 5, 131034, 262145, 5, 196570, 393217, 5, -65573, 393217, 5, -37, 327681, 5, 65499, 327681, 5, 131035, 327681, 5, 196571, 393217, 5, 262107, 393217, 5, 327643, 458753, 5, -65572, 393217, 5, -36, 327681, 5, 65500, 458753, 5, 131036, 262145, 5, 196572, 393217, 5, 262108, 262145, 5, 327644, 458753, 5, 393180, 327681, 5, -65571, 327681, 5, -35, 327681, 5, 65501, 327681, 5, 131037, 458753, 5, 196573, 327681, 5, 262109, 262145, 5, 327645, 393217, 5, 393181, 262145, 5, 458717, 327681, 5, -65570, 458753, 5, -34, 393217, 5, 65502, 458753, 5, 131038, 458753, 5, 196574, 458753, 5, 262110, 262145, 5, 327646, 393217, 5, 393182, 393217, 5, 458718, 327681, 5, 524254, 262145, 5, 2359288, 262145, 5, 2359289, 393217, 5, 2359290, 393217, 5, 2424826, 327681, 5, 2359291, 393217, 5, 2424827, 262145, 5, 2490363, 262145, 5, 2359292, 262145, 5, 2424828, 458753, 5, 2490364, 262145, 5, 2555900, 393217, 5, 2359293, 393217, 5, 2424829, 327681, 5, 2490365, 327681, 5, 2555901, 393217, 5, 2359294, 262145, 5, 2424830, 458753, 5, 2490366, 327681, 5, 2555902, 327681, 5, 2359295, 262145, 5, 2424831, 393217, 5, 2490367, 262145, 5, 2555903, 327681, 5, 2621439, 327681, 5, 2686975, 458753, 5, 2752511, 262145, 5)\nlayer_3/name = \"lvl2-tall\"\nlayer_3/y_sort_enabled = true\nlayer_3/z_index = 20\nlayer_3/tile_data = PackedInt32Array(851971, 65536, 1, 851976, 196608, 1, -786448, 458761, 1, -720912, 458761, 1, -655376, 458761, 1, -589840, 327689, 4, -851984, 458761, 4, -589841, 327689, 0, -851985, 131081, 3, -851989, 9, 10, -655377, 65586, 2, -786449, 65586, 2, -1703949, 65536, 1, -1703944, 196608, 1, -1769453, 131072, 1, -1769448, 131072, 1, -1703943, 131081, 12, -1703942, 131081, 12, -1703941, 131081, 12, -1703950, 131081, 12, -1703951, 131081, 12, -1703952, 131081, 12, -1769454, 131081, 12, -1769455, 131081, 12, -1769456, 131081, 12, -1769447, 131081, 12, -1769446, 131081, 12, -1441786, 65545, 2, -1441787, 327689, 1, -1441788, 327689, 1, -1441790, 65545, 4, -1441791, 65545, 4, -1441798, 393225, 4, -1441797, 393225, 2, -1376259, 458761, 11, -1441795, 196617, 2, -1245191, 196611, 1, -1245190, 196611, 3, -1376239, 327689, 12, -1376238, 65545, 2, 1114124, 131122, 2, 1179643, 131132, 1, 1179644, 131132, 1, 1114108, 327689, 4, 1114107, 65545, 1, 1114106, 65545, 1, 1048572, 458761, 1, 983036, 196617, 3, 983035, 393225, 2, 983034, 131081, 12, 983033, 131081, 12, 1114105, 65545, 12, 655346, 60, 0, -589795, 131081, 11, -524259, 196617, 10, -524260, 65545, 10, -589796, 9, 11, -2359278, 196617, 12, -2293742, 196617, 12, -2162670, 196617, 12, -2097134, 196617, 12, -2031598, 458761, 10, -1966062, 196617, 3, -1900526, 196617, 12, 2293769, 196608, 1, 2293762, 65536, 1, 1835010, 0, 1, 1835017, 131072, 1)\n\n[node name=\"DecorationTileMap\" type=\"TileMap\" parent=\".\"]\ny_sort_enabled = true\ntile_set = ExtResource(\"12_7re5p\")\nformat = 2\nlayer_0/name = \"lvl1-flat\"\nlayer_0/y_sort_enabled = true\nlayer_0/z_index = 1\nlayer_0/tile_data = PackedInt32Array(-4521991, 262152, 0, -4653061, 393224, 0, -4784131, 262152, 65536, -4653064, 196623, 0, -4784133, 196623, 1, -4521989, 196623, 1, -4718595, 196623, 196608, -2293767, 196623, 1, -2162696, 9, 1, -1376290, 262152, 0, -1179670, 393224, 0, -1245202, 8, 0, -1376264, 393224, 65537, -1114132, 196623, 65536, -1572894, 196623, 1, -1638437, 196623, 131072, -1310744, 196623, 131072, -1245191, 196623, 65537, -1376262, 196623, 196608, -1179687, 196623, 196608, -1900551, 393224, 65536, -2031621, 262152, 65536, -3932162, 393224, 65536, -1179686, 196618, 1, -3473410, 262152, 0, -5963813, 15, 65536, -1835043, 8, 65536, -3538983, 196623, 131072, -3932200, 196623, 131072, 6422553, 131087, 0, 6357019, 131087, 0, 5701660, 131087, 65537, 5570584, 196623, 196609, 6160413, 131087, 65536, 6357015, 131087, 65537, 2686990, 131087, 196609, 2686986, 196623, 327680, 3145733, 131087, 131072, 3080172, 196623, 327680, 2752490, 131087, 196609, 1769449, 131087, 65536, 851946, 196623, 65536, 1834991, 196623, 131073, 2752502, 131087, 196609, 2686967, 196623, 65537, 2621428, 131087, 1, -3866600, 196623, 393216, -4849634, 196623, 131073, -4849640, 131087, 196608, 851996, 196618, 1, 655440, 131076, 0, -5242791, 9, 1, -5373863, 9, 65538, -4325332, 196623, 196608, -4325331, 196618, 1, -4456389, 196623, 131072, -4325315, 393224, 0, -4259777, 196623, 65536, -4390847, 8, 0, -982967, 196623, 196608, -982966, 196618, 1, -982950, 393224, 0, -917412, 196623, 65536, -1048482, 8, 0, 917574, 10, 3, 917576, 262152, 0, 1179720, 196623, 131073, 655433, 393224, 1, 1179722, 393224, 0, 852046, 393224, 65536, 3342365, 10, 3, 3014686, 196623, 196609, 3211294, 10, 3, 3342367, 262152, 0, 3604511, 196623, 131073, 3080224, 393224, 1, 3604513, 393224, 0, 3276837, 393224, 65536, -4521935, 262152, 0, -4980781, 6, 65540, -4718633, 262152, 0, -4915240, 131087, 0, -3801096, 10, 3, -4128775, 196623, 196609, -3932167, 10, 3, -3801094, 262152, 0, -3538950, 196623, 131073, -4259845, 196623, 131072, -4063237, 393224, 1, -3538948, 393224, 0, -1376200, 10, 3, -1703879, 196623, 196609, -1507271, 10, 3, -1376198, 262152, 0, -1114054, 196623, 131073, -1834949, 196623, 131072, -1638341, 393224, 1, -1114052, 393224, 0, -1114034, 8, 65536, -3604521, 262152, 0, -3407908, 262152, 0)\nlayer_1/name = \"lvl1-tall\"\nlayer_1/y_sort_enabled = true\nlayer_1/z_index = 10\nlayer_1/tile_data = PackedInt32Array(-917544, 131074, 18, -917542, 524290, 17, -4915198, 524290, 20, -3669992, 2, 65554, -983042, 17, 0, -1245224, 131089, 0, -3342344, 131089, 65536, -4784136, 17, 65536, -3473383, 65553, 65538, -4849633, 393218, 16, 1245160, 2, 18, 1441768, 393218, 16, 1114088, 2, 0, 2883560, 131074, 65554, 3211241, 458754, 0, 6094872, 2, 65554, 6225943, 458754, 10, 5898264, 458754, 0, -3669991, 17, 2, -4915168, 65553, 0, -4784097, 17, 65538, 1245162, 17, 65538, 1507306, 17, 2, 983018, 65553, 0, 3211244, 131089, 65536, 2818025, 65553, 65536, 5767194, 65553, 65536, 6094874, 17, 0, 5963803, 17, 65536, 6619161, 17, 2, 5111833, 17, 0, 2686988, 65553, 2, 524292, 131100, 0, 2555914, 28, 0, -2621417, 65568, 0, -2162665, 65568, 1, 2555912, 65568, 0, 2555917, 262176, 0, 2555916, 327712, 0, 2293734, 22, 1, -1048625, 65554, 131074, -1376301, 131090, 131072, -1703979, 16, 1, -1507371, 65552, 1, 1114144, 65553, 65536, -1179614, 524290, 17, 589904, 262146, 8, 1572937, 9, 1, 720975, 16, 0, -1048542, 65553, 2, -4849599, 131089, 0, -4784063, 65553, 0, -1179587, 196623, 1, -5373864, 65553, 2, -1048520, 131074, 18, -917448, 458766, 1, -1179591, 65552, 1, -1048519, 65553, 0, 4718615, 22, 0)\nlayer_2/name = \"lvl2-flat\"\nlayer_2/y_sort_enabled = true\nlayer_2/y_sort_origin = 128\nlayer_2/z_index = 11\nlayer_2/tile_data = PackedInt32Array(-4063301, 196623, 131072, -4194371, 196618, 65537, -4522048, 10, 0, -3932224, 131087, 196608, -4653119, 196623, 1, -4915262, 196618, 1, -4784190, 196623, 1, -4259902, 131087, 196608, -4194366, 196623, 131072, -4980795, 196623, 131072, -4128826, 131087, 196608, -4653112, 131087, 196608, -7077833, 15, 0, -6946765, 196623, 1, -6619077, 131072, 1, -6488016, 65536, 0, -5898258, 196623, 1, -5046324, 196623, 1, -5439537, 196623, 0, -4718619, 131087, 0, -4915222, 196623, 1, -5046202, 15, 0, -4915123, 131087, 0, -4980660, 16, 0, -6815682, 65552, 0, -524203, 131087, 0, -458665, 196623, 1, -4915126, 196623, 1, -4652947, 15, 0, -4980603, 15, 0)\nlayer_3/name = \"lvl2-tall\"\nlayer_3/y_sort_enabled = true\nlayer_3/z_index = 20\nlayer_3/tile_data = PackedInt32Array(-6356973, 458754, 65536, 5570634, 2, 65544, 5701708, 2, 65549, 3735642, 196640, 0, 3539035, 131104, 1, 3670108, 65568, 0, 786536, 196628, 0, 917608, 65558, 1, 1179752, 262164, 0, 1376360, 196628, 0, 1245290, 262177, 0, 2621546, 2, 65544, -1376149, 65562, 3, -786325, 65562, 3, 1572971, 65562, 3, -1048468, 65553, 65536, 1048684, 65562, 3, 2752620, 2, 65549, -1572755, 327700, 0, -982931, 65553, 0, -1507218, 196628, 0, 786542, 65558, 0, -917392, 65553, 2, -1245071, 65553, 65536, -1048463, 65553, 65536, 983153, 17, 0, -917389, 65553, 65536, -851853, 65553, 0, -786317, 65564, 0, 1572979, 65562, 3, 983156, 65564, 65536, -1048459, 65553, 2, 786550, 262168, 1, -720777, 131096, 1, 1704055, 196632, 2, 1376379, 65564, 0, 1638523, 65564, 0, 983164, 131100, 65536, 1376381, 17, 2, 786559, 327704, 1, 1441919, 393218, 16, 1310848, 17, 2, 1310849, 65553, 2, 1441921, 17, 0, 1376387, 65553, 2, 1441923, 65553, 2, 1507459, 65553, 2, 1572995, 65564, 0, 983172, 65564, 0, 786567, 196632, 2, 983179, 65562, 3, -2031690, 11, 0, -4587587, 65553, 65536, -4587586, 458763, 65536, -4128834, 65553, 65536, -4259905, 65553, 2, -4194369, 65553, 65536, -4128833, 131074, 18, -4063296, 65553, 2, -4128831, 17, 2, -3997759, 65553, 65536, -4849725, 65553, 2, -4718653, 524290, 20, -4849724, 65553, 0, -4259892, 393224, 65536, 655472, 131100, 0, 1245300, 65553, 2, 917621, 458763, 0, 1310837, 65553, 0, 1310838, 17, 65536, 1179767, 65553, 2, 1310840, 65553, 0, 917625, 65553, 65538, 852090, 65553, 0, 1048698, 65553, 0, 786555, 131100, 0, 1048699, 17, 65538, 1441930, 524290, 65553, -2818121, 131074, 18, -7077835, 458754, 0, -6946761, 131089, 0, -7208907, 14, 0, -5963782, 16, 0, -5701637, 65552, 0, -5701638, 65553, 2, -5832709, 327693, 1, -5767187, 131089, 0, -262179, 458754, 65546, -131107, 65553, 0, -4980627, 262157, 2, -851858, 458763, 0, -5832571, 196622, 0, -5177207, 11, 0)\n\n[node name=\"BuildableAreaParent\" type=\"Node2D\" parent=\".\"]\nposition = Vector2(0, -32)\n\n[node name=\"BuildableArea0\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\ntile_map_data = PackedByteArray(\"AADy/97/AAADAAAAAADy/9//AAADAAAAAADy/+D/AAADAAAAAADy/+H/AAADAAAAAADy/+L/AAADAAAAAADy/+P/AAADAAAAAADy/+T/AAADAAAAAADy/+X/AAADAAAAAADy/+b/AAADAAAAAADy/+f/AAADAAAAAADy/+j/AAADAAAAAADy/+n/AAADAAAAAADy/+r/AAADAAAAAADy/+v/AAADAAAAAADy/+z/AAADAAAAAADy/+3/AAADAAAAAADy/+7/AAADAAAAAADy/+//AAADAAAAAADy//D/AAADAAAAAADz/97/AAADAAAAAADz/9//AAADAAAAAADz/+D/AAADAAAAAADz/+H/AAADAAAAAADz/+L/AAADAAAAAADz/+P/AAADAAAAAADz/+T/AAADAAAAAADz/+X/AAADAAAAAADz/+b/AAADAAAAAADz/+f/AAADAAAAAADz/+j/AAADAAAAAADz/+n/AAADAAAAAADz/+r/AAADAAAAAADz/+v/AAADAAAAAADz/+z/AAADAAAAAADz/+3/AAADAAAAAADz/+7/AAADAAAAAADz/+//AAADAAAAAADz//D/AAADAAAAAAD0/97/AAADAAAAAAD0/9//AAADAAAAAAD0/+D/AAADAAAAAAD0/+H/AAADAAAAAAD0/+L/AAADAAAAAAD0/+P/AAADAAAAAAD0/+T/AAADAAAAAAD0/+X/AAADAAAAAAD0/+b/AAADAAAAAAD0/+f/AAADAAAAAAD0/+j/AAADAAAAAAD0/+n/AAADAAAAAAD0/+r/AAADAAAAAAD0/+v/AAADAAAAAAD0/+z/AAADAAAAAAD0/+3/AAADAAAAAAD0/+7/AAADAAAAAAD0/+//AAADAAAAAAD0//D/AAADAAAAAAD1/97/AAADAAAAAAD1/9//AAADAAAAAAD1/+D/AAADAAAAAAD1/+H/AAADAAAAAAD1/+L/AAADAAAAAAD1/+P/AAADAAAAAAD1/+T/AAADAAAAAAD1/+X/AAADAAAAAAD1/+b/AAADAAAAAAD1/+f/AAADAAAAAAD1/+j/AAADAAAAAAD1/+n/AAADAAAAAAD1/+r/AAADAAAAAAD1/+v/AAADAAAAAAD1/+z/AAADAAAAAAD1/+3/AAADAAAAAAD1/+7/AAADAAAAAAD1/+//AAADAAAAAAD1//D/AAADAAAAAAD2/97/AAADAAAAAAD2/9//AAADAAAAAAD2/+D/AAADAAAAAAD2/+H/AAADAAAAAAD2/+L/AAADAAAAAAD2/+P/AAADAAAAAAD2/+T/AAADAAAAAAD2/+X/AAADAAAAAAD2/+b/AAADAAAAAAD2/+f/AAADAAAAAAD2/+j/AAADAAAAAAD2/+n/AAADAAAAAAD2/+r/AAADAAAAAAD2/+v/AAADAAAAAAD2/+z/AAADAAAAAAD2/+3/AAADAAAAAAD2/+7/AAADAAAAAAD2/+//AAADAAAAAAD2//D/AAADAAAAAAD3/97/AAADAAAAAAD3/9//AAADAAAAAAD3/+D/AAADAAAAAAD3/+H/AAADAAAAAAD3/+L/AAADAAAAAAD3/+P/AAADAAAAAAD3/+T/AAADAAAAAAD3/+X/AAADAAAAAAD3/+b/AAADAAAAAAD3/+f/AAADAAAAAAD3/+j/AAADAAAAAAD3/+n/AAADAAAAAAD3/+r/AAADAAAAAAD3/+v/AAADAAAAAAD3/+z/AAADAAAAAAD3/+3/AAADAAAAAAD3/+7/AAADAAAAAAD3/+//AAADAAAAAAD3//D/AAADAAAAAADx//v/AAADAAAAAADx//z/AAADAAAAAADx//3/AAADAAAAAADx//7/AAADAAAAAADx////AAADAAAAAADx/wAAAAADAAAAAADy//v/AAADAAAAAADy//z/AAADAAAAAADy//3/AAADAAAAAADy//7/AAADAAAAAADy////AAADAAAAAADy/wAAAAADAAAAAADz//v/AAADAAAAAADz//z/AAADAAAAAADz//3/AAADAAAAAADz//7/AAADAAAAAADz////AAADAAAAAADz/wAAAAADAAAAAAD0//v/AAADAAAAAAD0//z/AAADAAAAAAD0//3/AAADAAAAAAD0//7/AAADAAAAAAD0////AAADAAAAAAD0/wAAAAADAAAAAAD1//v/AAADAAAAAAD1//z/AAADAAAAAAD1//3/AAADAAAAAAD1//7/AAADAAAAAAD1////AAADAAAAAAD1/wAAAAADAAAAAAD2//v/AAADAAAAAAD2//z/AAADAAAAAAD2//3/AAADAAAAAAD2//7/AAADAAAAAAD2////AAADAAAAAAD2/wAAAAADAAAAAAD3//v/AAADAAAAAAD3//z/AAADAAAAAAD3//3/AAADAAAAAAD3//7/AAADAAAAAAD3////AAADAAAAAAD3/wAAAAADAAAAAAD4//v/AAADAAAAAAD4//z/AAADAAAAAAD4//3/AAADAAAAAAD4//7/AAADAAAAAAD4////AAADAAAAAAD4/wAAAAADAAAAAAD5//v/AAADAAAAAAD5//z/AAADAAAAAAD5//3/AAADAAAAAAD5//7/AAADAAAAAAD5////AAADAAAAAAD5/wAAAAADAAAAAAD6//v/AAADAAAAAAD6//z/AAADAAAAAAD6//3/AAADAAAAAAD6//7/AAADAAAAAAD6////AAADAAAAAAD6/wAAAAADAAAAAAD7//v/AAADAAAAAAD7//z/AAADAAAAAAD7//3/AAADAAAAAAD7//7/AAADAAAAAAD7////AAADAAAAAAD7/wAAAAADAAAAAAD8//v/AAADAAAAAAD8//z/AAADAAAAAAD8//3/AAADAAAAAAD8//7/AAADAAAAAAD8////AAADAAAAAAD8/wAAAAADAAAAAAD9//v/AAADAAAAAAD9//z/AAADAAAAAAD9//3/AAADAAAAAAD9//7/AAADAAAAAAD9////AAADAAAAAAD9/wAAAAADAAAAAAD+//v/AAADAAAAAAD+//z/AAADAAAAAAD+//3/AAADAAAAAAD+//7/AAADAAAAAAD+////AAADAAAAAAD+/wAAAAADAAAAAAD///v/AAADAAAAAAD///z/AAADAAAAAAD///3/AAADAAAAAAD///7/AAADAAAAAAD/////AAADAAAAAAD//wAAAAADAAAAAAAAAPv/AAADAAAAAAAAAPz/AAADAAAAAAAAAP3/AAADAAAAAAAAAP7/AAADAAAAAAAAAP//AAADAAAAAAAAAAAAAAADAAAAAAABAPv/AAADAAAAAAABAPz/AAADAAAAAAABAP3/AAADAAAAAAABAP7/AAADAAAAAAABAP//AAADAAAAAAABAAAAAAADAAAAAAACAPv/AAADAAAAAAACAPz/AAADAAAAAAACAP3/AAADAAAAAAACAP7/AAADAAAAAAACAP//AAADAAAAAAACAAAAAAADAAAAAAADAPv/AAADAAAAAAADAPz/AAADAAAAAAADAP3/AAADAAAAAAADAP7/AAADAAAAAAADAP//AAADAAAAAAADAAAAAAADAAAAAAAEAPv/AAADAAAAAAAEAPz/AAADAAAAAAAEAP3/AAADAAAAAAAEAP7/AAADAAAAAAAEAP//AAADAAAAAAAEAAAAAAADAAAAAAAFAPv/AAADAAAAAAAFAPz/AAADAAAAAAAFAP3/AAADAAAAAAAFAP7/AAADAAAAAAAFAP//AAADAAAAAAAFAAAAAAADAAAAAAAGAPv/AAADAAAAAAAGAPz/AAADAAAAAAAGAP3/AAADAAAAAAAGAP7/AAADAAAAAAAGAP//AAADAAAAAAAGAAAAAAADAAAAAAAHAPv/AAADAAAAAAAHAPz/AAADAAAAAAAHAP3/AAADAAAAAAAHAP7/AAADAAAAAAAHAP//AAADAAAAAAAHAAAAAAADAAAAAAACAOH/AAADAAAAAAACAOL/AAADAAAAAAACAOP/AAADAAAAAAACAOT/AAADAAAAAAACAOX/AAADAAAAAAACAOb/AAADAAAAAAACAOf/AAADAAAAAAACAOj/AAADAAAAAAACAOn/AAADAAAAAAACAOr/AAADAAAAAAACAOv/AAADAAAAAAACAOz/AAADAAAAAAACAO3/AAADAAAAAAACAO7/AAADAAAAAAACAO//AAADAAAAAAACAPD/AAADAAAAAAACAPH/AAADAAAAAAACAPL/AAADAAAAAAACAPP/AAADAAAAAAACAPT/AAADAAAAAAACAPX/AAADAAAAAAACAPb/AAADAAAAAAACAPf/AAADAAAAAAACAPj/AAADAAAAAAACAPn/AAADAAAAAAACAPr/AAADAAAAAAADAOH/AAADAAAAAAADAOL/AAADAAAAAAADAOP/AAADAAAAAAADAOT/AAADAAAAAAADAOX/AAADAAAAAAADAOb/AAADAAAAAAADAOf/AAADAAAAAAADAOj/AAADAAAAAAADAOn/AAADAAAAAAADAOr/AAADAAAAAAADAOv/AAADAAAAAAADAOz/AAADAAAAAAADAO3/AAADAAAAAAADAO7/AAADAAAAAAADAO//AAADAAAAAAADAPD/AAADAAAAAAADAPH/AAADAAAAAAADAPL/AAADAAAAAAADAPP/AAADAAAAAAADAPT/AAADAAAAAAADAPX/AAADAAAAAAADAPb/AAADAAAAAAADAPf/AAADAAAAAAADAPj/AAADAAAAAAADAPn/AAADAAAAAAADAPr/AAADAAAAAAAEAOH/AAADAAAAAAAEAOL/AAADAAAAAAAEAOP/AAADAAAAAAAEAOT/AAADAAAAAAAEAOX/AAADAAAAAAAEAOb/AAADAAAAAAAEAOf/AAADAAAAAAAEAOj/AAADAAAAAAAEAOn/AAADAAAAAAAEAOr/AAADAAAAAAAEAOv/AAADAAAAAAAEAOz/AAADAAAAAAAEAO3/AAADAAAAAAAEAO7/AAADAAAAAAAEAO//AAADAAAAAAAEAPD/AAADAAAAAAAEAPH/AAADAAAAAAAEAPL/AAADAAAAAAAEAPP/AAADAAAAAAAEAPT/AAADAAAAAAAEAPX/AAADAAAAAAAEAPb/AAADAAAAAAAEAPf/AAADAAAAAAAEAPj/AAADAAAAAAAEAPn/AAADAAAAAAAEAPr/AAADAAAAAAAFAOH/AAADAAAAAAAFAOL/AAADAAAAAAAFAOP/AAADAAAAAAAFAOT/AAADAAAAAAAFAOX/AAADAAAAAAAFAOb/AAADAAAAAAAFAOf/AAADAAAAAAAFAOj/AAADAAAAAAAFAOn/AAADAAAAAAAFAOr/AAADAAAAAAAFAOv/AAADAAAAAAAFAOz/AAADAAAAAAAFAO3/AAADAAAAAAAFAO7/AAADAAAAAAAFAO//AAADAAAAAAAFAPD/AAADAAAAAAAFAPH/AAADAAAAAAAFAPL/AAADAAAAAAAFAPP/AAADAAAAAAAFAPT/AAADAAAAAAAFAPX/AAADAAAAAAAFAPb/AAADAAAAAAAFAPf/AAADAAAAAAAFAPj/AAADAAAAAAAFAPn/AAADAAAAAAAFAPr/AAADAAAAAAAGAOH/AAADAAAAAAAGAOL/AAADAAAAAAAGAOP/AAADAAAAAAAGAOT/AAADAAAAAAAGAOX/AAADAAAAAAAGAOb/AAADAAAAAAAGAOf/AAADAAAAAAAGAOj/AAADAAAAAAAGAOn/AAADAAAAAAAGAOr/AAADAAAAAAAGAOv/AAADAAAAAAAGAOz/AAADAAAAAAAGAO3/AAADAAAAAAAGAO7/AAADAAAAAAAGAO//AAADAAAAAAAGAPD/AAADAAAAAAAGAPH/AAADAAAAAAAGAPL/AAADAAAAAAAGAPP/AAADAAAAAAAGAPT/AAADAAAAAAAGAPX/AAADAAAAAAAGAPb/AAADAAAAAAAGAPf/AAADAAAAAAAGAPj/AAADAAAAAAAGAPn/AAADAAAAAAAGAPr/AAADAAAAAAAHAOH/AAADAAAAAAAHAOL/AAADAAAAAAAHAOP/AAADAAAAAAAHAOT/AAADAAAAAAAHAOX/AAADAAAAAAAHAOb/AAADAAAAAAAHAOf/AAADAAAAAAAHAOj/AAADAAAAAAAHAOn/AAADAAAAAAAHAOr/AAADAAAAAAAHAOv/AAADAAAAAAAHAOz/AAADAAAAAAAHAO3/AAADAAAAAAAHAO7/AAADAAAAAAAHAO//AAADAAAAAAAHAPD/AAADAAAAAAAHAPH/AAADAAAAAAAHAPL/AAADAAAAAAAHAPP/AAADAAAAAAAHAPT/AAADAAAAAAAHAPX/AAADAAAAAAAHAPb/AAADAAAAAAAHAPf/AAADAAAAAAAHAPj/AAADAAAAAAAHAPn/AAADAAAAAAAHAPr/AAADAAAAAAD6/wsAAAADAAAAAAD6/wwAAAADAAAAAAD6/w0AAAADAAAAAAD6/w4AAAADAAAAAAD6/w8AAAADAAAAAAD6/xAAAAADAAAAAAD7/wsAAAADAAAAAAD7/wwAAAADAAAAAAD7/w0AAAADAAAAAAD7/w4AAAADAAAAAAD7/w8AAAADAAAAAAD7/xAAAAADAAAAAAD8/wsAAAADAAAAAAD8/wwAAAADAAAAAAD8/w0AAAADAAAAAAD8/w4AAAADAAAAAAD8/w8AAAADAAAAAAD8/xAAAAADAAAAAAD9/wsAAAADAAAAAAD9/wwAAAADAAAAAAD9/w0AAAADAAAAAAD9/w4AAAADAAAAAAD9/w8AAAADAAAAAAD9/xAAAAADAAAAAAD+/wsAAAADAAAAAAD+/wwAAAADAAAAAAD+/w0AAAADAAAAAAD+/w4AAAADAAAAAAD+/w8AAAADAAAAAAD+/xAAAAADAAAAAAD//wsAAAADAAAAAAD//wwAAAADAAAAAAD//w0AAAADAAAAAAD//w4AAAADAAAAAAD//w8AAAADAAAAAAD//xAAAAADAAAAAAAAAAsAAAADAAAAAAAAAAwAAAADAAAAAAAAAA0AAAADAAAAAAAAAA4AAAADAAAAAAAAAA8AAAADAAAAAAAAABAAAAADAAAAAAABAAsAAAADAAAAAAABAAwAAAADAAAAAAABAA0AAAADAAAAAAABAA4AAAADAAAAAAABAA8AAAADAAAAAAABABAAAAADAAAAAAACAAsAAAADAAAAAAACAAwAAAADAAAAAAACAA0AAAADAAAAAAACAA4AAAADAAAAAAACAA8AAAADAAAAAAACABAAAAADAAAAAAADAAsAAAADAAAAAAADAAwAAAADAAAAAAADAA0AAAADAAAAAAADAA4AAAADAAAAAAADAA8AAAADAAAAAAADABAAAAADAAAAAAAEAAsAAAADAAAAAAAEAAwAAAADAAAAAAAEAA0AAAADAAAAAAAEAA4AAAADAAAAAAAEAA8AAAADAAAAAAAEABAAAAADAAAAAAAFAAsAAAADAAAAAAAFAAwAAAADAAAAAAAFAA0AAAADAAAAAAAFAA4AAAADAAAAAAAFAA8AAAADAAAAAAAFABAAAAADAAAAAAAGAAsAAAADAAAAAAAGAAwAAAADAAAAAAAGAA0AAAADAAAAAAAGAA4AAAADAAAAAAAGAA8AAAADAAAAAAAGABAAAAADAAAAAAAHAAsAAAADAAAAAAAHAAwAAAADAAAAAAAHAA0AAAADAAAAAAAHAA4AAAADAAAAAAAHAA8AAAADAAAAAAAHABAAAAADAAAAAAAIAAsAAAADAAAAAAAIAAwAAAADAAAAAAAIAA0AAAADAAAAAAAIAA4AAAADAAAAAAAIAA8AAAADAAAAAAAIABAAAAADAAAAAAAJAAsAAAADAAAAAAAJAAwAAAADAAAAAAAJAA0AAAADAAAAAAAJAA4AAAADAAAAAAAJAA8AAAADAAAAAAAJABAAAAADAAAAAAAKAAsAAAADAAAAAAAKAAwAAAADAAAAAAAKAA0AAAADAAAAAAAKAA4AAAADAAAAAAAKAA8AAAADAAAAAAAKABAAAAADAAAAAAALAAsAAAADAAAAAAALAAwAAAADAAAAAAALAA0AAAADAAAAAAALAA4AAAADAAAAAAALAA8AAAADAAAAAAALABAAAAADAAAAAAAMAAsAAAADAAAAAAAMAAwAAAADAAAAAAAMAA0AAAADAAAAAAAMAA4AAAADAAAAAAAMAA8AAAADAAAAAAAMABAAAAADAAAAAAA=\")\n\n[node name=\"BuildableArea1\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(0, 0.25, 1, 0.211765)\ntile_map_data = PackedByteArray(\"AAASAOH/AAADAAAAAAASAOL/AAADAAAAAAASAOP/AAADAAAAAAASAOT/AAADAAAAAAASAOX/AAADAAAAAAASAOb/AAADAAAAAAASAOf/AAADAAAAAAASAOj/AAADAAAAAAASAOn/AAADAAAAAAASAOr/AAADAAAAAAASAOv/AAADAAAAAAASAOz/AAADAAAAAAASAO3/AAADAAAAAAASAO7/AAADAAAAAAASAO//AAADAAAAAAASAPD/AAADAAAAAAASAPH/AAADAAAAAAASAPL/AAADAAAAAAASAPP/AAADAAAAAAASAPT/AAADAAAAAAASAPX/AAADAAAAAAASAPb/AAADAAAAAAASAPf/AAADAAAAAAASAPj/AAADAAAAAAASAPn/AAADAAAAAAASAPr/AAADAAAAAAASAPv/AAADAAAAAAASAPz/AAADAAAAAAASAP3/AAADAAAAAAASAP7/AAADAAAAAAASAP//AAADAAAAAAASAAAAAAADAAAAAAATAOH/AAADAAAAAAATAOL/AAADAAAAAAATAOP/AAADAAAAAAATAOT/AAADAAAAAAATAOX/AAADAAAAAAATAOb/AAADAAAAAAATAOf/AAADAAAAAAATAOj/AAADAAAAAAATAOn/AAADAAAAAAATAOr/AAADAAAAAAATAOv/AAADAAAAAAATAOz/AAADAAAAAAATAO3/AAADAAAAAAATAO7/AAADAAAAAAATAO//AAADAAAAAAATAPD/AAADAAAAAAATAPH/AAADAAAAAAATAPL/AAADAAAAAAATAPP/AAADAAAAAAATAPT/AAADAAAAAAATAPX/AAADAAAAAAATAPb/AAADAAAAAAATAPf/AAADAAAAAAATAPj/AAADAAAAAAATAPn/AAADAAAAAAATAPr/AAADAAAAAAATAPv/AAADAAAAAAATAPz/AAADAAAAAAATAP3/AAADAAAAAAATAP7/AAADAAAAAAATAP//AAADAAAAAAATAAAAAAADAAAAAAAUAOH/AAADAAAAAAAUAOL/AAADAAAAAAAUAOP/AAADAAAAAAAUAOT/AAADAAAAAAAUAOX/AAADAAAAAAAUAOb/AAADAAAAAAAUAOf/AAADAAAAAAAUAOj/AAADAAAAAAAUAOn/AAADAAAAAAAUAOr/AAADAAAAAAAUAOv/AAADAAAAAAAUAOz/AAADAAAAAAAUAO3/AAADAAAAAAAUAO7/AAADAAAAAAAUAO//AAADAAAAAAAUAPD/AAADAAAAAAAUAPH/AAADAAAAAAAUAPL/AAADAAAAAAAUAPP/AAADAAAAAAAUAPT/AAADAAAAAAAUAPX/AAADAAAAAAAUAPb/AAADAAAAAAAUAPf/AAADAAAAAAAUAPj/AAADAAAAAAAUAPn/AAADAAAAAAAUAPr/AAADAAAAAAAUAPv/AAADAAAAAAAUAPz/AAADAAAAAAAUAP3/AAADAAAAAAAUAP7/AAADAAAAAAAUAP//AAADAAAAAAAUAAAAAAADAAAAAAAVAOH/AAADAAAAAAAVAOL/AAADAAAAAAAVAOP/AAADAAAAAAAVAOT/AAADAAAAAAAVAOX/AAADAAAAAAAVAOb/AAADAAAAAAAVAOf/AAADAAAAAAAVAOj/AAADAAAAAAAVAOn/AAADAAAAAAAVAOr/AAADAAAAAAAVAOv/AAADAAAAAAAVAOz/AAADAAAAAAAVAO3/AAADAAAAAAAVAO7/AAADAAAAAAAVAO//AAADAAAAAAAVAPD/AAADAAAAAAAVAPH/AAADAAAAAAAVAPL/AAADAAAAAAAVAPP/AAADAAAAAAAVAPT/AAADAAAAAAAVAPX/AAADAAAAAAAVAPb/AAADAAAAAAAVAPf/AAADAAAAAAAVAPj/AAADAAAAAAAVAPn/AAADAAAAAAAVAPr/AAADAAAAAAAVAPv/AAADAAAAAAAVAPz/AAADAAAAAAAVAP3/AAADAAAAAAAVAP7/AAADAAAAAAAVAP//AAADAAAAAAAVAAAAAAADAAAAAAAWAOH/AAADAAAAAAAWAOL/AAADAAAAAAAWAOP/AAADAAAAAAAWAOT/AAADAAAAAAAWAOX/AAADAAAAAAAWAOb/AAADAAAAAAAWAOf/AAADAAAAAAAWAOj/AAADAAAAAAAWAOn/AAADAAAAAAAWAOr/AAADAAAAAAAWAOv/AAADAAAAAAAWAOz/AAADAAAAAAAWAO3/AAADAAAAAAAWAO7/AAADAAAAAAAWAO//AAADAAAAAAAWAPD/AAADAAAAAAAWAPH/AAADAAAAAAAWAPL/AAADAAAAAAAWAPP/AAADAAAAAAAWAPT/AAADAAAAAAAWAPX/AAADAAAAAAAWAPb/AAADAAAAAAAWAPf/AAADAAAAAAAWAPj/AAADAAAAAAAWAPn/AAADAAAAAAAWAPr/AAADAAAAAAAWAPv/AAADAAAAAAAWAPz/AAADAAAAAAAWAP3/AAADAAAAAAAWAP7/AAADAAAAAAAWAP//AAADAAAAAAAWAAAAAAADAAAAAAAXAOH/AAADAAAAAAAXAOL/AAADAAAAAAAXAOP/AAADAAAAAAAXAOT/AAADAAAAAAAXAOX/AAADAAAAAAAXAOb/AAADAAAAAAAXAOf/AAADAAAAAAAXAOj/AAADAAAAAAAXAOn/AAADAAAAAAAXAOr/AAADAAAAAAAXAOv/AAADAAAAAAAXAOz/AAADAAAAAAAXAO3/AAADAAAAAAAXAO7/AAADAAAAAAAXAO//AAADAAAAAAAXAPD/AAADAAAAAAAXAPH/AAADAAAAAAAXAPL/AAADAAAAAAAXAPP/AAADAAAAAAAXAPT/AAADAAAAAAAXAPX/AAADAAAAAAAXAPb/AAADAAAAAAAXAPf/AAADAAAAAAAXAPj/AAADAAAAAAAXAPn/AAADAAAAAAAXAPr/AAADAAAAAAAXAPv/AAADAAAAAAAXAPz/AAADAAAAAAAXAP3/AAADAAAAAAAXAP7/AAADAAAAAAAXAP//AAADAAAAAAAXAAAAAAADAAAAAAAiAN7/AAADAAAAAAAiAN//AAADAAAAAAAiAOD/AAADAAAAAAAiAOH/AAADAAAAAAAiAOL/AAADAAAAAAAiAOP/AAADAAAAAAAiAOT/AAADAAAAAAAiAOX/AAADAAAAAAAiAOb/AAADAAAAAAAiAOf/AAADAAAAAAAiAOj/AAADAAAAAAAiAOn/AAADAAAAAAAiAOr/AAADAAAAAAAiAOv/AAADAAAAAAAiAOz/AAADAAAAAAAiAO3/AAADAAAAAAAiAO7/AAADAAAAAAAiAO//AAADAAAAAAAiAPD/AAADAAAAAAAjAN7/AAADAAAAAAAjAN//AAADAAAAAAAjAOD/AAADAAAAAAAjAOH/AAADAAAAAAAjAOL/AAADAAAAAAAjAOP/AAADAAAAAAAjAOT/AAADAAAAAAAjAOX/AAADAAAAAAAjAOb/AAADAAAAAAAjAOf/AAADAAAAAAAjAOj/AAADAAAAAAAjAOn/AAADAAAAAAAjAOr/AAADAAAAAAAjAOv/AAADAAAAAAAjAOz/AAADAAAAAAAjAO3/AAADAAAAAAAjAO7/AAADAAAAAAAjAO//AAADAAAAAAAjAPD/AAADAAAAAAAkAN7/AAADAAAAAAAkAN//AAADAAAAAAAkAOD/AAADAAAAAAAkAOH/AAADAAAAAAAkAOL/AAADAAAAAAAkAOP/AAADAAAAAAAkAOT/AAADAAAAAAAkAOX/AAADAAAAAAAkAOb/AAADAAAAAAAkAOf/AAADAAAAAAAkAOj/AAADAAAAAAAkAOn/AAADAAAAAAAkAOr/AAADAAAAAAAkAOv/AAADAAAAAAAkAOz/AAADAAAAAAAkAO3/AAADAAAAAAAkAO7/AAADAAAAAAAkAO//AAADAAAAAAAkAPD/AAADAAAAAAAlAN7/AAADAAAAAAAlAN//AAADAAAAAAAlAOD/AAADAAAAAAAlAOH/AAADAAAAAAAlAOL/AAADAAAAAAAlAOP/AAADAAAAAAAlAOT/AAADAAAAAAAlAOX/AAADAAAAAAAlAOb/AAADAAAAAAAlAOf/AAADAAAAAAAlAOj/AAADAAAAAAAlAOn/AAADAAAAAAAlAOr/AAADAAAAAAAlAOv/AAADAAAAAAAlAOz/AAADAAAAAAAlAO3/AAADAAAAAAAlAO7/AAADAAAAAAAlAO//AAADAAAAAAAlAPD/AAADAAAAAAAmAN7/AAADAAAAAAAmAN//AAADAAAAAAAmAOD/AAADAAAAAAAmAOH/AAADAAAAAAAmAOL/AAADAAAAAAAmAOP/AAADAAAAAAAmAOT/AAADAAAAAAAmAOX/AAADAAAAAAAmAOb/AAADAAAAAAAmAOf/AAADAAAAAAAmAOj/AAADAAAAAAAmAOn/AAADAAAAAAAmAOr/AAADAAAAAAAmAOv/AAADAAAAAAAmAOz/AAADAAAAAAAmAO3/AAADAAAAAAAmAO7/AAADAAAAAAAmAO//AAADAAAAAAAmAPD/AAADAAAAAAAnAN7/AAADAAAAAAAnAN//AAADAAAAAAAnAOD/AAADAAAAAAAnAOH/AAADAAAAAAAnAOL/AAADAAAAAAAnAOP/AAADAAAAAAAnAOT/AAADAAAAAAAnAOX/AAADAAAAAAAnAOb/AAADAAAAAAAnAOf/AAADAAAAAAAnAOj/AAADAAAAAAAnAOn/AAADAAAAAAAnAOr/AAADAAAAAAAnAOv/AAADAAAAAAAnAOz/AAADAAAAAAAnAO3/AAADAAAAAAAnAO7/AAADAAAAAAAnAO//AAADAAAAAAAnAPD/AAADAAAAAAAYAPv/AAADAAAAAAAYAPz/AAADAAAAAAAYAP3/AAADAAAAAAAYAP7/AAADAAAAAAAYAP//AAADAAAAAAAYAAAAAAADAAAAAAAZAPv/AAADAAAAAAAZAPz/AAADAAAAAAAZAP3/AAADAAAAAAAZAP7/AAADAAAAAAAZAP//AAADAAAAAAAZAAAAAAADAAAAAAAaAPv/AAADAAAAAAAaAPz/AAADAAAAAAAaAP3/AAADAAAAAAAaAP7/AAADAAAAAAAaAP//AAADAAAAAAAaAAAAAAADAAAAAAAbAPv/AAADAAAAAAAbAPz/AAADAAAAAAAbAP3/AAADAAAAAAAbAP7/AAADAAAAAAAbAP//AAADAAAAAAAbAAAAAAADAAAAAAAcAPv/AAADAAAAAAAcAPz/AAADAAAAAAAcAP3/AAADAAAAAAAcAP7/AAADAAAAAAAcAP//AAADAAAAAAAcAAAAAAADAAAAAAAdAPv/AAADAAAAAAAdAPz/AAADAAAAAAAdAP3/AAADAAAAAAAdAP7/AAADAAAAAAAdAP//AAADAAAAAAAdAAAAAAADAAAAAAAeAPv/AAADAAAAAAAeAPz/AAADAAAAAAAeAP3/AAADAAAAAAAeAP7/AAADAAAAAAAeAP//AAADAAAAAAAeAAAAAAADAAAAAAAfAPv/AAADAAAAAAAfAPz/AAADAAAAAAAfAP3/AAADAAAAAAAfAP7/AAADAAAAAAAfAP//AAADAAAAAAAfAAAAAAADAAAAAAAgAPv/AAADAAAAAAAgAPz/AAADAAAAAAAgAP3/AAADAAAAAAAgAP7/AAADAAAAAAAgAP//AAADAAAAAAAgAAAAAAADAAAAAAAhAPv/AAADAAAAAAAhAPz/AAADAAAAAAAhAP3/AAADAAAAAAAhAP7/AAADAAAAAAAhAP//AAADAAAAAAAhAAAAAAADAAAAAAAiAPv/AAADAAAAAAAiAPz/AAADAAAAAAAiAP3/AAADAAAAAAAiAP7/AAADAAAAAAAiAP//AAADAAAAAAAiAAAAAAADAAAAAAAjAPv/AAADAAAAAAAjAPz/AAADAAAAAAAjAP3/AAADAAAAAAAjAP7/AAADAAAAAAAjAP//AAADAAAAAAAjAAAAAAADAAAAAAAkAPv/AAADAAAAAAAkAPz/AAADAAAAAAAkAP3/AAADAAAAAAAkAP7/AAADAAAAAAAkAP//AAADAAAAAAAkAAAAAAADAAAAAAAlAPv/AAADAAAAAAAlAPz/AAADAAAAAAAlAP3/AAADAAAAAAAlAP7/AAADAAAAAAAlAP//AAADAAAAAAAlAAAAAAADAAAAAAAmAPv/AAADAAAAAAAmAPz/AAADAAAAAAAmAP3/AAADAAAAAAAmAP7/AAADAAAAAAAmAP//AAADAAAAAAAmAAAAAAADAAAAAAAnAPv/AAADAAAAAAAnAPz/AAADAAAAAAAnAP3/AAADAAAAAAAnAP7/AAADAAAAAAAnAP//AAADAAAAAAAnAAAAAAADAAAAAAAoAPv/AAADAAAAAAAoAPz/AAADAAAAAAAoAP3/AAADAAAAAAAoAP7/AAADAAAAAAAoAP//AAADAAAAAAAoAAAAAAADAAAAAAANAAsAAAADAAAAAAANAAwAAAADAAAAAAANAA0AAAADAAAAAAANAA4AAAADAAAAAAANAA8AAAADAAAAAAANABAAAAADAAAAAAAOAAsAAAADAAAAAAAOAAwAAAADAAAAAAAOAA0AAAADAAAAAAAOAA4AAAADAAAAAAAOAA8AAAADAAAAAAAOABAAAAADAAAAAAAPAAsAAAADAAAAAAAPAAwAAAADAAAAAAAPAA0AAAADAAAAAAAPAA4AAAADAAAAAAAPAA8AAAADAAAAAAAPABAAAAADAAAAAAAQAAsAAAADAAAAAAAQAAwAAAADAAAAAAAQAA0AAAADAAAAAAAQAA4AAAADAAAAAAAQAA8AAAADAAAAAAAQABAAAAADAAAAAAARAAsAAAADAAAAAAARAAwAAAADAAAAAAARAA0AAAADAAAAAAARAA4AAAADAAAAAAARAA8AAAADAAAAAAARABAAAAADAAAAAAASAAsAAAADAAAAAAASAAwAAAADAAAAAAASAA0AAAADAAAAAAASAA4AAAADAAAAAAASAA8AAAADAAAAAAASABAAAAADAAAAAAATAAsAAAADAAAAAAATAAwAAAADAAAAAAATAA0AAAADAAAAAAATAA4AAAADAAAAAAATAA8AAAADAAAAAAATABAAAAADAAAAAAAUAAsAAAADAAAAAAAUAAwAAAADAAAAAAAUAA0AAAADAAAAAAAUAA4AAAADAAAAAAAUAA8AAAADAAAAAAAUABAAAAADAAAAAAAVAAsAAAADAAAAAAAVAAwAAAADAAAAAAAVAA0AAAADAAAAAAAVAA4AAAADAAAAAAAVAA8AAAADAAAAAAAVABAAAAADAAAAAAAWAAsAAAADAAAAAAAWAAwAAAADAAAAAAAWAA0AAAADAAAAAAAWAA4AAAADAAAAAAAWAA8AAAADAAAAAAAWABAAAAADAAAAAAAXAAsAAAADAAAAAAAXAAwAAAADAAAAAAAXAA0AAAADAAAAAAAXAA4AAAADAAAAAAAXAA8AAAADAAAAAAAXABAAAAADAAAAAAAYAAsAAAADAAAAAAAYAAwAAAADAAAAAAAYAA0AAAADAAAAAAAYAA4AAAADAAAAAAAYAA8AAAADAAAAAAAYABAAAAADAAAAAAAZAAsAAAADAAAAAAAZAAwAAAADAAAAAAAZAA0AAAADAAAAAAAZAA4AAAADAAAAAAAZAA8AAAADAAAAAAAZABAAAAADAAAAAAAaAAsAAAADAAAAAAAaAAwAAAADAAAAAAAaAA0AAAADAAAAAAAaAA4AAAADAAAAAAAaAA8AAAADAAAAAAAaABAAAAADAAAAAAAbAAsAAAADAAAAAAAbAAwAAAADAAAAAAAbAA0AAAADAAAAAAAbAA4AAAADAAAAAAAbAA8AAAADAAAAAAAbABAAAAADAAAAAAAcAAsAAAADAAAAAAAcAAwAAAADAAAAAAAcAA0AAAADAAAAAAAcAA4AAAADAAAAAAAcAA8AAAADAAAAAAAcABAAAAADAAAAAAAdAAsAAAADAAAAAAAdAAwAAAADAAAAAAAdAA0AAAADAAAAAAAdAA4AAAADAAAAAAAdAA8AAAADAAAAAAAdABAAAAADAAAAAAAeAAsAAAADAAAAAAAeAAwAAAADAAAAAAAeAA0AAAADAAAAAAAeAA4AAAADAAAAAAAeAA8AAAADAAAAAAAeABAAAAADAAAAAAAfAAsAAAADAAAAAAAfAAwAAAADAAAAAAAfAA0AAAADAAAAAAAfAA4AAAADAAAAAAAfAA8AAAADAAAAAAAfABAAAAADAAAAAAA=\")\nplayer_id = 1\n\n[node name=\"BuildableArea2\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(0.916667, 0, 1, 0.211765)\ntile_map_data = PackedByteArray(\"AABcADUAAAADAAAAAABcADYAAAADAAAAAABcADcAAAADAAAAAABcADgAAAADAAAAAABcADkAAAADAAAAAABcADoAAAADAAAAAABdADUAAAADAAAAAABdADYAAAADAAAAAABdADcAAAADAAAAAABdADgAAAADAAAAAABdADkAAAADAAAAAABdADoAAAADAAAAAABeADUAAAADAAAAAABeADYAAAADAAAAAABeADcAAAADAAAAAABeADgAAAADAAAAAABeADkAAAADAAAAAABeADoAAAADAAAAAABfADUAAAADAAAAAABfADYAAAADAAAAAABfADcAAAADAAAAAABfADgAAAADAAAAAABfADkAAAADAAAAAABfADoAAAADAAAAAABgADUAAAADAAAAAABgADYAAAADAAAAAABgADcAAAADAAAAAABgADgAAAADAAAAAABgADkAAAADAAAAAABgADoAAAADAAAAAABhADUAAAADAAAAAABhADYAAAADAAAAAABhADcAAAADAAAAAABhADgAAAADAAAAAABhADkAAAADAAAAAABhADoAAAADAAAAAABiADUAAAADAAAAAABiADYAAAADAAAAAABiADcAAAADAAAAAABiADgAAAADAAAAAABiADkAAAADAAAAAABiADoAAAADAAAAAABjADUAAAADAAAAAABjADYAAAADAAAAAABjADcAAAADAAAAAABjADgAAAADAAAAAABjADkAAAADAAAAAABjADoAAAADAAAAAABkADUAAAADAAAAAABkADYAAAADAAAAAABkADcAAAADAAAAAABkADgAAAADAAAAAABkADkAAAADAAAAAABkADoAAAADAAAAAABlADUAAAADAAAAAABlADYAAAADAAAAAABlADcAAAADAAAAAABlADgAAAADAAAAAABlADkAAAADAAAAAABlADoAAAADAAAAAABmADUAAAADAAAAAABmADYAAAADAAAAAABmADcAAAADAAAAAABmADgAAAADAAAAAABmADkAAAADAAAAAABmADoAAAADAAAAAABnADUAAAADAAAAAABnADYAAAADAAAAAABnADcAAAADAAAAAABnADgAAAADAAAAAABnADkAAAADAAAAAABnADoAAAADAAAAAABoADUAAAADAAAAAABoADYAAAADAAAAAABoADcAAAADAAAAAABoADgAAAADAAAAAABoADkAAAADAAAAAABoADoAAAADAAAAAABpADUAAAADAAAAAABpADYAAAADAAAAAABpADcAAAADAAAAAABpADgAAAADAAAAAABpADkAAAADAAAAAABpADoAAAADAAAAAABMADUAAAADAAAAAABMADYAAAADAAAAAABMADcAAAADAAAAAABMADgAAAADAAAAAABMADkAAAADAAAAAABMADoAAAADAAAAAABNADUAAAADAAAAAABNADYAAAADAAAAAABNADcAAAADAAAAAABNADgAAAADAAAAAABNADkAAAADAAAAAABNADoAAAADAAAAAABOADUAAAADAAAAAABOADYAAAADAAAAAABOADcAAAADAAAAAABOADgAAAADAAAAAABOADkAAAADAAAAAABOADoAAAADAAAAAABPADUAAAADAAAAAABPADYAAAADAAAAAABPADcAAAADAAAAAABPADgAAAADAAAAAABPADkAAAADAAAAAABPADoAAAADAAAAAABQADUAAAADAAAAAABQADYAAAADAAAAAABQADcAAAADAAAAAABQADgAAAADAAAAAABQADkAAAADAAAAAABQADoAAAADAAAAAABRADUAAAADAAAAAABRADYAAAADAAAAAABRADcAAAADAAAAAABRADgAAAADAAAAAABRADkAAAADAAAAAABRADoAAAADAAAAAABSADUAAAADAAAAAABSADYAAAADAAAAAABSADcAAAADAAAAAABSADgAAAADAAAAAABSADkAAAADAAAAAABSADoAAAADAAAAAABTADUAAAADAAAAAABTADYAAAADAAAAAABTADcAAAADAAAAAABTADgAAAADAAAAAABTADkAAAADAAAAAABTADoAAAADAAAAAABUADUAAAADAAAAAABUADYAAAADAAAAAABUADcAAAADAAAAAABUADgAAAADAAAAAABUADkAAAADAAAAAABUADoAAAADAAAAAABVADUAAAADAAAAAABVADYAAAADAAAAAABVADcAAAADAAAAAABVADgAAAADAAAAAABVADkAAAADAAAAAABVADoAAAADAAAAAABWADUAAAADAAAAAABWADYAAAADAAAAAABWADcAAAADAAAAAABWADgAAAADAAAAAABWADkAAAADAAAAAABWADoAAAADAAAAAABXADUAAAADAAAAAABXADYAAAADAAAAAABXADcAAAADAAAAAABXADgAAAADAAAAAABXADkAAAADAAAAAABXADoAAAADAAAAAABYADUAAAADAAAAAABYADYAAAADAAAAAABYADcAAAADAAAAAABYADgAAAADAAAAAABYADkAAAADAAAAAABYADoAAAADAAAAAABZADUAAAADAAAAAABZADYAAAADAAAAAABZADcAAAADAAAAAABZADgAAAADAAAAAABZADkAAAADAAAAAABZADoAAAADAAAAAABaADUAAAADAAAAAABaADYAAAADAAAAAABaADcAAAADAAAAAABaADgAAAADAAAAAABaADkAAAADAAAAAABaADoAAAADAAAAAABbADUAAAADAAAAAABbADYAAAADAAAAAABbADcAAAADAAAAAABbADgAAAADAAAAAABbADkAAAADAAAAAABbADoAAAADAAAAAABMACQAAAADAAAAAABMACUAAAADAAAAAABMACYAAAADAAAAAABMACcAAAADAAAAAABMACgAAAADAAAAAABMACkAAAADAAAAAABMACoAAAADAAAAAABMACsAAAADAAAAAABMACwAAAADAAAAAABMAC0AAAADAAAAAABMAC4AAAADAAAAAABMAC8AAAADAAAAAABMADAAAAADAAAAAABMADEAAAADAAAAAABMADIAAAADAAAAAABMADMAAAADAAAAAABMADQAAAADAAAAAABNACQAAAADAAAAAABNACUAAAADAAAAAABNACYAAAADAAAAAABNACcAAAADAAAAAABNACgAAAADAAAAAABNACkAAAADAAAAAABNACoAAAADAAAAAABNACsAAAADAAAAAABNACwAAAADAAAAAABNAC0AAAADAAAAAABNAC4AAAADAAAAAABNAC8AAAADAAAAAABNADAAAAADAAAAAABNADEAAAADAAAAAABNADIAAAADAAAAAABNADMAAAADAAAAAABNADQAAAADAAAAAABOACQAAAADAAAAAABOACUAAAADAAAAAABOACYAAAADAAAAAABOACcAAAADAAAAAABOACgAAAADAAAAAABOACkAAAADAAAAAABOACoAAAADAAAAAABOACsAAAADAAAAAABOACwAAAADAAAAAABOAC0AAAADAAAAAABOAC4AAAADAAAAAABOAC8AAAADAAAAAABOADAAAAADAAAAAABOADEAAAADAAAAAABOADIAAAADAAAAAABOADMAAAADAAAAAABOADQAAAADAAAAAABPACQAAAADAAAAAABPACUAAAADAAAAAABPACYAAAADAAAAAABPACcAAAADAAAAAABPACgAAAADAAAAAABPACkAAAADAAAAAABPACoAAAADAAAAAABPACsAAAADAAAAAABPACwAAAADAAAAAABPAC0AAAADAAAAAABPAC4AAAADAAAAAABPAC8AAAADAAAAAABPADAAAAADAAAAAABPADEAAAADAAAAAABPADIAAAADAAAAAABPADMAAAADAAAAAABPADQAAAADAAAAAABQACQAAAADAAAAAABQACUAAAADAAAAAABQACYAAAADAAAAAABQACcAAAADAAAAAABQACgAAAADAAAAAABQACkAAAADAAAAAABQACoAAAADAAAAAABQACsAAAADAAAAAABQACwAAAADAAAAAABQAC0AAAADAAAAAABQAC4AAAADAAAAAABQAC8AAAADAAAAAABQADAAAAADAAAAAABQADEAAAADAAAAAABQADIAAAADAAAAAABQADMAAAADAAAAAABQADQAAAADAAAAAABRACQAAAADAAAAAABRACUAAAADAAAAAABRACYAAAADAAAAAABRACcAAAADAAAAAABRACgAAAADAAAAAABRACkAAAADAAAAAABRACoAAAADAAAAAABRACsAAAADAAAAAABRACwAAAADAAAAAABRAC0AAAADAAAAAABRAC4AAAADAAAAAABRAC8AAAADAAAAAABRADAAAAADAAAAAABRADEAAAADAAAAAABRADIAAAADAAAAAABRADMAAAADAAAAAABRADQAAAADAAAAAAA8AC0AAAADAAAAAAA8AC4AAAADAAAAAAA8AC8AAAADAAAAAAA8ADAAAAADAAAAAAA8ADEAAAADAAAAAAA8ADIAAAADAAAAAAA8ADMAAAADAAAAAAA8ADQAAAADAAAAAAA8ADUAAAADAAAAAAA8ADYAAAADAAAAAAA8ADcAAAADAAAAAAA8ADgAAAADAAAAAAA8ADkAAAADAAAAAAA8ADoAAAADAAAAAAA8ADsAAAADAAAAAAA8ADwAAAADAAAAAAA8AD0AAAADAAAAAAA8AD4AAAADAAAAAAA8AD8AAAADAAAAAAA9AC0AAAADAAAAAAA9AC4AAAADAAAAAAA9AC8AAAADAAAAAAA9ADAAAAADAAAAAAA9ADEAAAADAAAAAAA9ADIAAAADAAAAAAA9ADMAAAADAAAAAAA9ADQAAAADAAAAAAA9ADUAAAADAAAAAAA9ADYAAAADAAAAAAA9ADcAAAADAAAAAAA9ADgAAAADAAAAAAA9ADkAAAADAAAAAAA9ADoAAAADAAAAAAA9ADsAAAADAAAAAAA9ADwAAAADAAAAAAA9AD0AAAADAAAAAAA9AD4AAAADAAAAAAA9AD8AAAADAAAAAAA+AC0AAAADAAAAAAA+AC4AAAADAAAAAAA+AC8AAAADAAAAAAA+ADAAAAADAAAAAAA+ADEAAAADAAAAAAA+ADIAAAADAAAAAAA+ADMAAAADAAAAAAA+ADQAAAADAAAAAAA+ADUAAAADAAAAAAA+ADYAAAADAAAAAAA+ADcAAAADAAAAAAA+ADgAAAADAAAAAAA+ADkAAAADAAAAAAA+ADoAAAADAAAAAAA+ADsAAAADAAAAAAA+ADwAAAADAAAAAAA+AD0AAAADAAAAAAA+AD4AAAADAAAAAAA+AD8AAAADAAAAAAA/AC0AAAADAAAAAAA/AC4AAAADAAAAAAA/AC8AAAADAAAAAAA/ADAAAAADAAAAAAA/ADEAAAADAAAAAAA/ADIAAAADAAAAAAA/ADMAAAADAAAAAAA/ADQAAAADAAAAAAA/ADUAAAADAAAAAAA/ADYAAAADAAAAAAA/ADcAAAADAAAAAAA/ADgAAAADAAAAAAA/ADkAAAADAAAAAAA/ADoAAAADAAAAAAA/ADsAAAADAAAAAAA/ADwAAAADAAAAAAA/AD0AAAADAAAAAAA/AD4AAAADAAAAAAA/AD8AAAADAAAAAABAAC0AAAADAAAAAABAAC4AAAADAAAAAABAAC8AAAADAAAAAABAADAAAAADAAAAAABAADEAAAADAAAAAABAADIAAAADAAAAAABAADMAAAADAAAAAABAADQAAAADAAAAAABAADUAAAADAAAAAABAADYAAAADAAAAAABAADcAAAADAAAAAABAADgAAAADAAAAAABAADkAAAADAAAAAABAADoAAAADAAAAAABAADsAAAADAAAAAABAADwAAAADAAAAAABAAD0AAAADAAAAAABAAD4AAAADAAAAAABAAD8AAAADAAAAAABBAC0AAAADAAAAAABBAC4AAAADAAAAAABBAC8AAAADAAAAAABBADAAAAADAAAAAABBADEAAAADAAAAAABBADIAAAADAAAAAABBADMAAAADAAAAAABBADQAAAADAAAAAABBADUAAAADAAAAAABBADYAAAADAAAAAABBADcAAAADAAAAAABBADgAAAADAAAAAABBADkAAAADAAAAAABBADoAAAADAAAAAABBADsAAAADAAAAAABBADwAAAADAAAAAABBAD0AAAADAAAAAABBAD4AAAADAAAAAABBAD8AAAADAAAAAABcACUAAAADAAAAAABcACYAAAADAAAAAABcACcAAAADAAAAAABcACgAAAADAAAAAABcACkAAAADAAAAAABcACoAAAADAAAAAABdACUAAAADAAAAAABdACYAAAADAAAAAABdACcAAAADAAAAAABdACgAAAADAAAAAABdACkAAAADAAAAAABdACoAAAADAAAAAABeACUAAAADAAAAAABeACYAAAADAAAAAABeACcAAAADAAAAAABeACgAAAADAAAAAABeACkAAAADAAAAAABeACoAAAADAAAAAABfACUAAAADAAAAAABfACYAAAADAAAAAABfACcAAAADAAAAAABfACgAAAADAAAAAABfACkAAAADAAAAAABfACoAAAADAAAAAABgACUAAAADAAAAAABgACYAAAADAAAAAABgACcAAAADAAAAAABgACgAAAADAAAAAABgACkAAAADAAAAAABgACoAAAADAAAAAABhACUAAAADAAAAAABhACYAAAADAAAAAABhACcAAAADAAAAAABhACgAAAADAAAAAABhACkAAAADAAAAAABhACoAAAADAAAAAABiACUAAAADAAAAAABiACYAAAADAAAAAABiACcAAAADAAAAAABiACgAAAADAAAAAABiACkAAAADAAAAAABiACoAAAADAAAAAABjACUAAAADAAAAAABjACYAAAADAAAAAABjACcAAAADAAAAAABjACgAAAADAAAAAABjACkAAAADAAAAAABjACoAAAADAAAAAABkACUAAAADAAAAAABkACYAAAADAAAAAABkACcAAAADAAAAAABkACgAAAADAAAAAABkACkAAAADAAAAAABkACoAAAADAAAAAABlACUAAAADAAAAAABlACYAAAADAAAAAABlACcAAAADAAAAAABlACgAAAADAAAAAABlACkAAAADAAAAAABlACoAAAADAAAAAABmACUAAAADAAAAAABmACYAAAADAAAAAABmACcAAAADAAAAAABmACgAAAADAAAAAABmACkAAAADAAAAAABmACoAAAADAAAAAABnACUAAAADAAAAAABnACYAAAADAAAAAABnACcAAAADAAAAAABnACgAAAADAAAAAABnACkAAAADAAAAAABnACoAAAADAAAAAABoACUAAAADAAAAAABoACYAAAADAAAAAABoACcAAAADAAAAAABoACgAAAADAAAAAABoACkAAAADAAAAAABoACoAAAADAAAAAABpACUAAAADAAAAAABpACYAAAADAAAAAABpACcAAAADAAAAAABpACgAAAADAAAAAABpACkAAAADAAAAAABpACoAAAADAAAAAABqACUAAAADAAAAAABqACYAAAADAAAAAABqACcAAAADAAAAAABqACgAAAADAAAAAABqACkAAAADAAAAAABqACoAAAADAAAAAABrACUAAAADAAAAAABrACYAAAADAAAAAABrACcAAAADAAAAAABrACgAAAADAAAAAABrACkAAAADAAAAAABrACoAAAADAAAAAABsACUAAAADAAAAAABsACYAAAADAAAAAABsACcAAAADAAAAAABsACgAAAADAAAAAABsACkAAAADAAAAAABsACoAAAADAAAAAABtACUAAAADAAAAAABtACYAAAADAAAAAABtACcAAAADAAAAAABtACgAAAADAAAAAABtACkAAAADAAAAAABtACoAAAADAAAAAABuACUAAAADAAAAAABuACYAAAADAAAAAABuACcAAAADAAAAAABuACgAAAADAAAAAABuACkAAAADAAAAAABuACoAAAADAAAAAAA=\")\nplayer_id = 2\n\n[node name=\"BuildableArea3\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(1, 0, 0.216667, 0.211765)\ntile_map_data = PackedByteArray(\"AAA8AEAAAAADAAAAAAA8AEEAAAADAAAAAAA8AEIAAAADAAAAAAA8AEMAAAADAAAAAAA8AEQAAAADAAAAAAA8AEUAAAADAAAAAAA8AEYAAAADAAAAAAA8AEcAAAADAAAAAAA8AEgAAAADAAAAAAA8AEkAAAADAAAAAAA8AEoAAAADAAAAAAA8AEsAAAADAAAAAAA8AEwAAAADAAAAAAA8AE0AAAADAAAAAAA8AE4AAAADAAAAAAA8AE8AAAADAAAAAAA8AFAAAAADAAAAAAA8AFEAAAADAAAAAAA8AFIAAAADAAAAAAA9AEAAAAADAAAAAAA9AEEAAAADAAAAAAA9AEIAAAADAAAAAAA9AEMAAAADAAAAAAA9AEQAAAADAAAAAAA9AEUAAAADAAAAAAA9AEYAAAADAAAAAAA9AEcAAAADAAAAAAA9AEgAAAADAAAAAAA9AEkAAAADAAAAAAA9AEoAAAADAAAAAAA9AEsAAAADAAAAAAA9AEwAAAADAAAAAAA9AE0AAAADAAAAAAA9AE4AAAADAAAAAAA9AE8AAAADAAAAAAA9AFAAAAADAAAAAAA9AFEAAAADAAAAAAA9AFIAAAADAAAAAAA+AEAAAAADAAAAAAA+AEEAAAADAAAAAAA+AEIAAAADAAAAAAA+AEMAAAADAAAAAAA+AEQAAAADAAAAAAA+AEUAAAADAAAAAAA+AEYAAAADAAAAAAA+AEcAAAADAAAAAAA+AEgAAAADAAAAAAA+AEkAAAADAAAAAAA+AEoAAAADAAAAAAA+AEsAAAADAAAAAAA+AEwAAAADAAAAAAA+AE0AAAADAAAAAAA+AE4AAAADAAAAAAA+AE8AAAADAAAAAAA+AFAAAAADAAAAAAA+AFEAAAADAAAAAAA+AFIAAAADAAAAAAA/AEAAAAADAAAAAAA/AEEAAAADAAAAAAA/AEIAAAADAAAAAAA/AEMAAAADAAAAAAA/AEQAAAADAAAAAAA/AEUAAAADAAAAAAA/AEYAAAADAAAAAAA/AEcAAAADAAAAAAA/AEgAAAADAAAAAAA/AEkAAAADAAAAAAA/AEoAAAADAAAAAAA/AEsAAAADAAAAAAA/AEwAAAADAAAAAAA/AE0AAAADAAAAAAA/AE4AAAADAAAAAAA/AE8AAAADAAAAAAA/AFAAAAADAAAAAAA/AFEAAAADAAAAAAA/AFIAAAADAAAAAABAAEAAAAADAAAAAABAAEEAAAADAAAAAABAAEIAAAADAAAAAABAAEMAAAADAAAAAABAAEQAAAADAAAAAABAAEUAAAADAAAAAABAAEYAAAADAAAAAABAAEcAAAADAAAAAABAAEgAAAADAAAAAABAAEkAAAADAAAAAABAAEoAAAADAAAAAABAAEsAAAADAAAAAABAAEwAAAADAAAAAABAAE0AAAADAAAAAABAAE4AAAADAAAAAABAAE8AAAADAAAAAABAAFAAAAADAAAAAABAAFEAAAADAAAAAABAAFIAAAADAAAAAABBAEAAAAADAAAAAABBAEEAAAADAAAAAABBAEIAAAADAAAAAABBAEMAAAADAAAAAABBAEQAAAADAAAAAABBAEUAAAADAAAAAABBAEYAAAADAAAAAABBAEcAAAADAAAAAABBAEgAAAADAAAAAABBAEkAAAADAAAAAABBAEoAAAADAAAAAABBAEsAAAADAAAAAABBAEwAAAADAAAAAABBAE0AAAADAAAAAABBAE4AAAADAAAAAABBAE8AAAADAAAAAABBAFAAAAADAAAAAABBAFEAAAADAAAAAABBAFIAAAADAAAAAABMAEUAAAADAAAAAABMAEYAAAADAAAAAABMAEcAAAADAAAAAABMAEgAAAADAAAAAABMAEkAAAADAAAAAABMAEoAAAADAAAAAABNAEUAAAADAAAAAABNAEYAAAADAAAAAABNAEcAAAADAAAAAABNAEgAAAADAAAAAABNAEkAAAADAAAAAABNAEoAAAADAAAAAABOAEUAAAADAAAAAABOAEYAAAADAAAAAABOAEcAAAADAAAAAABOAEgAAAADAAAAAABOAEkAAAADAAAAAABOAEoAAAADAAAAAABPAEUAAAADAAAAAABPAEYAAAADAAAAAABPAEcAAAADAAAAAABPAEgAAAADAAAAAABPAEkAAAADAAAAAABPAEoAAAADAAAAAABQAEUAAAADAAAAAABQAEYAAAADAAAAAABQAEcAAAADAAAAAABQAEgAAAADAAAAAABQAEkAAAADAAAAAABQAEoAAAADAAAAAABRAEUAAAADAAAAAABRAEYAAAADAAAAAABRAEcAAAADAAAAAABRAEgAAAADAAAAAABRAEkAAAADAAAAAABRAEoAAAADAAAAAABSAEUAAAADAAAAAABSAEYAAAADAAAAAABSAEcAAAADAAAAAABSAEgAAAADAAAAAABSAEkAAAADAAAAAABSAEoAAAADAAAAAABTAEUAAAADAAAAAABTAEYAAAADAAAAAABTAEcAAAADAAAAAABTAEgAAAADAAAAAABTAEkAAAADAAAAAABTAEoAAAADAAAAAABUAEUAAAADAAAAAABUAEYAAAADAAAAAABUAEcAAAADAAAAAABUAEgAAAADAAAAAABUAEkAAAADAAAAAABUAEoAAAADAAAAAABVAEUAAAADAAAAAABVAEYAAAADAAAAAABVAEcAAAADAAAAAABVAEgAAAADAAAAAABVAEkAAAADAAAAAABVAEoAAAADAAAAAABWAEUAAAADAAAAAABWAEYAAAADAAAAAABWAEcAAAADAAAAAABWAEgAAAADAAAAAABWAEkAAAADAAAAAABWAEoAAAADAAAAAABXAEUAAAADAAAAAABXAEYAAAADAAAAAABXAEcAAAADAAAAAABXAEgAAAADAAAAAABXAEkAAAADAAAAAABXAEoAAAADAAAAAABYAEUAAAADAAAAAABYAEYAAAADAAAAAABYAEcAAAADAAAAAABYAEgAAAADAAAAAABYAEkAAAADAAAAAABYAEoAAAADAAAAAABZAEUAAAADAAAAAABZAEYAAAADAAAAAABZAEcAAAADAAAAAABZAEgAAAADAAAAAABZAEkAAAADAAAAAABZAEoAAAADAAAAAABaAEUAAAADAAAAAABaAEYAAAADAAAAAABaAEcAAAADAAAAAABaAEgAAAADAAAAAABaAEkAAAADAAAAAABaAEoAAAADAAAAAABbAEUAAAADAAAAAABbAEYAAAADAAAAAABbAEcAAAADAAAAAABbAEgAAAADAAAAAABbAEkAAAADAAAAAABbAEoAAAADAAAAAABcAEUAAAADAAAAAABcAEYAAAADAAAAAABcAEcAAAADAAAAAABcAEgAAAADAAAAAABcAEkAAAADAAAAAABcAEoAAAADAAAAAABdAEUAAAADAAAAAABdAEYAAAADAAAAAABdAEcAAAADAAAAAABdAEgAAAADAAAAAABdAEkAAAADAAAAAABdAEoAAAADAAAAAABeAEUAAAADAAAAAABeAEYAAAADAAAAAABeAEcAAAADAAAAAABeAEgAAAADAAAAAABeAEkAAAADAAAAAABeAEoAAAADAAAAAABfAEUAAAADAAAAAABfAEYAAAADAAAAAABfAEcAAAADAAAAAABfAEgAAAADAAAAAABfAEkAAAADAAAAAABfAEoAAAADAAAAAABgAEUAAAADAAAAAABgAEYAAAADAAAAAABgAEcAAAADAAAAAABgAEgAAAADAAAAAABgAEkAAAADAAAAAABgAEoAAAADAAAAAABhAEUAAAADAAAAAABhAEYAAAADAAAAAABhAEcAAAADAAAAAABhAEgAAAADAAAAAABhAEkAAAADAAAAAABhAEoAAAADAAAAAABiAEUAAAADAAAAAABiAEYAAAADAAAAAABiAEcAAAADAAAAAABiAEgAAAADAAAAAABiAEkAAAADAAAAAABiAEoAAAADAAAAAABjAEUAAAADAAAAAABjAEYAAAADAAAAAABjAEcAAAADAAAAAABjAEgAAAADAAAAAABjAEkAAAADAAAAAABjAEoAAAADAAAAAABkAEUAAAADAAAAAABkAEYAAAADAAAAAABkAEcAAAADAAAAAABkAEgAAAADAAAAAABkAEkAAAADAAAAAABkAEoAAAADAAAAAABlAEUAAAADAAAAAABlAEYAAAADAAAAAABlAEcAAAADAAAAAABlAEgAAAADAAAAAABlAEkAAAADAAAAAABlAEoAAAADAAAAAABmAEUAAAADAAAAAABmAEYAAAADAAAAAABmAEcAAAADAAAAAABmAEgAAAADAAAAAABmAEkAAAADAAAAAABmAEoAAAADAAAAAABnAEUAAAADAAAAAABnAEYAAAADAAAAAABnAEcAAAADAAAAAABnAEgAAAADAAAAAABnAEkAAAADAAAAAABnAEoAAAADAAAAAABoAEUAAAADAAAAAABoAEYAAAADAAAAAABoAEcAAAADAAAAAABoAEgAAAADAAAAAABoAEkAAAADAAAAAABoAEoAAAADAAAAAABpAEUAAAADAAAAAABpAEYAAAADAAAAAABpAEcAAAADAAAAAABpAEgAAAADAAAAAABpAEkAAAADAAAAAABpAEoAAAADAAAAAABMAEsAAAADAAAAAABMAEwAAAADAAAAAABMAE0AAAADAAAAAABMAE4AAAADAAAAAABMAE8AAAADAAAAAABMAFAAAAADAAAAAABMAFEAAAADAAAAAABMAFIAAAADAAAAAABMAFMAAAADAAAAAABMAFQAAAADAAAAAABMAFUAAAADAAAAAABMAFYAAAADAAAAAABMAFcAAAADAAAAAABMAFgAAAADAAAAAABMAFkAAAADAAAAAABMAFoAAAADAAAAAABMAFsAAAADAAAAAABNAEsAAAADAAAAAABNAEwAAAADAAAAAABNAE0AAAADAAAAAABNAE4AAAADAAAAAABNAE8AAAADAAAAAABNAFAAAAADAAAAAABNAFEAAAADAAAAAABNAFIAAAADAAAAAABNAFMAAAADAAAAAABNAFQAAAADAAAAAABNAFUAAAADAAAAAABNAFYAAAADAAAAAABNAFcAAAADAAAAAABNAFgAAAADAAAAAABNAFkAAAADAAAAAABNAFoAAAADAAAAAABNAFsAAAADAAAAAABOAEsAAAADAAAAAABOAEwAAAADAAAAAABOAE0AAAADAAAAAABOAE4AAAADAAAAAABOAE8AAAADAAAAAABOAFAAAAADAAAAAABOAFEAAAADAAAAAABOAFIAAAADAAAAAABOAFMAAAADAAAAAABOAFQAAAADAAAAAABOAFUAAAADAAAAAABOAFYAAAADAAAAAABOAFcAAAADAAAAAABOAFgAAAADAAAAAABOAFkAAAADAAAAAABOAFoAAAADAAAAAABOAFsAAAADAAAAAABPAEsAAAADAAAAAABPAEwAAAADAAAAAABPAE0AAAADAAAAAABPAE4AAAADAAAAAABPAE8AAAADAAAAAABPAFAAAAADAAAAAABPAFEAAAADAAAAAABPAFIAAAADAAAAAABPAFMAAAADAAAAAABPAFQAAAADAAAAAABPAFUAAAADAAAAAABPAFYAAAADAAAAAABPAFcAAAADAAAAAABPAFgAAAADAAAAAABPAFkAAAADAAAAAABPAFoAAAADAAAAAABPAFsAAAADAAAAAABQAEsAAAADAAAAAABQAEwAAAADAAAAAABQAE0AAAADAAAAAABQAE4AAAADAAAAAABQAE8AAAADAAAAAABQAFAAAAADAAAAAABQAFEAAAADAAAAAABQAFIAAAADAAAAAABQAFMAAAADAAAAAABQAFQAAAADAAAAAABQAFUAAAADAAAAAABQAFYAAAADAAAAAABQAFcAAAADAAAAAABQAFgAAAADAAAAAABQAFkAAAADAAAAAABQAFoAAAADAAAAAABQAFsAAAADAAAAAABRAEsAAAADAAAAAABRAEwAAAADAAAAAABRAE0AAAADAAAAAABRAE4AAAADAAAAAABRAE8AAAADAAAAAABRAFAAAAADAAAAAABRAFEAAAADAAAAAABRAFIAAAADAAAAAABRAFMAAAADAAAAAABRAFQAAAADAAAAAABRAFUAAAADAAAAAABRAFYAAAADAAAAAABRAFcAAAADAAAAAABRAFgAAAADAAAAAABRAFkAAAADAAAAAABRAFoAAAADAAAAAABRAFsAAAADAAAAAABcAFUAAAADAAAAAABcAFYAAAADAAAAAABcAFcAAAADAAAAAABcAFgAAAADAAAAAABcAFkAAAADAAAAAABcAFoAAAADAAAAAABdAFUAAAADAAAAAABdAFYAAAADAAAAAABdAFcAAAADAAAAAABdAFgAAAADAAAAAABdAFkAAAADAAAAAABdAFoAAAADAAAAAABeAFUAAAADAAAAAABeAFYAAAADAAAAAABeAFcAAAADAAAAAABeAFgAAAADAAAAAABeAFkAAAADAAAAAABeAFoAAAADAAAAAABfAFUAAAADAAAAAABfAFYAAAADAAAAAABfAFcAAAADAAAAAABfAFgAAAADAAAAAABfAFkAAAADAAAAAABfAFoAAAADAAAAAABgAFUAAAADAAAAAABgAFYAAAADAAAAAABgAFcAAAADAAAAAABgAFgAAAADAAAAAABgAFkAAAADAAAAAABgAFoAAAADAAAAAABhAFUAAAADAAAAAABhAFYAAAADAAAAAABhAFcAAAADAAAAAABhAFgAAAADAAAAAABhAFkAAAADAAAAAABhAFoAAAADAAAAAABiAFUAAAADAAAAAABiAFYAAAADAAAAAABiAFcAAAADAAAAAABiAFgAAAADAAAAAABiAFkAAAADAAAAAABiAFoAAAADAAAAAABjAFUAAAADAAAAAABjAFYAAAADAAAAAABjAFcAAAADAAAAAABjAFgAAAADAAAAAABjAFkAAAADAAAAAABjAFoAAAADAAAAAABkAFUAAAADAAAAAABkAFYAAAADAAAAAABkAFcAAAADAAAAAABkAFgAAAADAAAAAABkAFkAAAADAAAAAABkAFoAAAADAAAAAABlAFUAAAADAAAAAABlAFYAAAADAAAAAABlAFcAAAADAAAAAABlAFgAAAADAAAAAABlAFkAAAADAAAAAABlAFoAAAADAAAAAABmAFUAAAADAAAAAABmAFYAAAADAAAAAABmAFcAAAADAAAAAABmAFgAAAADAAAAAABmAFkAAAADAAAAAABmAFoAAAADAAAAAABnAFUAAAADAAAAAABnAFYAAAADAAAAAABnAFcAAAADAAAAAABnAFgAAAADAAAAAABnAFkAAAADAAAAAABnAFoAAAADAAAAAABoAFUAAAADAAAAAABoAFYAAAADAAAAAABoAFcAAAADAAAAAABoAFgAAAADAAAAAABoAFkAAAADAAAAAABoAFoAAAADAAAAAABpAFUAAAADAAAAAABpAFYAAAADAAAAAABpAFcAAAADAAAAAABpAFgAAAADAAAAAABpAFkAAAADAAAAAABpAFoAAAADAAAAAABqAFUAAAADAAAAAABqAFYAAAADAAAAAABqAFcAAAADAAAAAABqAFgAAAADAAAAAABqAFkAAAADAAAAAABqAFoAAAADAAAAAABrAFUAAAADAAAAAABrAFYAAAADAAAAAABrAFcAAAADAAAAAABrAFgAAAADAAAAAABrAFkAAAADAAAAAABrAFoAAAADAAAAAABsAFUAAAADAAAAAABsAFYAAAADAAAAAABsAFcAAAADAAAAAABsAFgAAAADAAAAAABsAFkAAAADAAAAAABsAFoAAAADAAAAAABtAFUAAAADAAAAAABtAFYAAAADAAAAAABtAFcAAAADAAAAAABtAFgAAAADAAAAAABtAFkAAAADAAAAAABtAFoAAAADAAAAAABuAFUAAAADAAAAAABuAFYAAAADAAAAAABuAFcAAAADAAAAAABuAFgAAAADAAAAAABuAFkAAAADAAAAAABuAFoAAAADAAAAAAA=\")\nplayer_id = 3\n\n[node name=\"BuildableArea4\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(1, 0.483333, 0, 0.211765)\ntile_map_data = PackedByteArray(\"AAAiAI8AAAADAAAAAAAiAJAAAAADAAAAAAAiAJEAAAADAAAAAAAiAJIAAAADAAAAAAAiAJMAAAADAAAAAAAiAJQAAAADAAAAAAAiAJUAAAADAAAAAAAiAJYAAAADAAAAAAAiAJcAAAADAAAAAAAiAJgAAAADAAAAAAAiAJkAAAADAAAAAAAiAJoAAAADAAAAAAAiAJsAAAADAAAAAAAiAJwAAAADAAAAAAAiAJ0AAAADAAAAAAAiAJ4AAAADAAAAAAAiAJ8AAAADAAAAAAAiAKAAAAADAAAAAAAiAKEAAAADAAAAAAAjAI8AAAADAAAAAAAjAJAAAAADAAAAAAAjAJEAAAADAAAAAAAjAJIAAAADAAAAAAAjAJMAAAADAAAAAAAjAJQAAAADAAAAAAAjAJUAAAADAAAAAAAjAJYAAAADAAAAAAAjAJcAAAADAAAAAAAjAJgAAAADAAAAAAAjAJkAAAADAAAAAAAjAJoAAAADAAAAAAAjAJsAAAADAAAAAAAjAJwAAAADAAAAAAAjAJ0AAAADAAAAAAAjAJ4AAAADAAAAAAAjAJ8AAAADAAAAAAAjAKAAAAADAAAAAAAjAKEAAAADAAAAAAAkAI8AAAADAAAAAAAkAJAAAAADAAAAAAAkAJEAAAADAAAAAAAkAJIAAAADAAAAAAAkAJMAAAADAAAAAAAkAJQAAAADAAAAAAAkAJUAAAADAAAAAAAkAJYAAAADAAAAAAAkAJcAAAADAAAAAAAkAJgAAAADAAAAAAAkAJkAAAADAAAAAAAkAJoAAAADAAAAAAAkAJsAAAADAAAAAAAkAJwAAAADAAAAAAAkAJ0AAAADAAAAAAAkAJ4AAAADAAAAAAAkAJ8AAAADAAAAAAAkAKAAAAADAAAAAAAkAKEAAAADAAAAAAAlAI8AAAADAAAAAAAlAJAAAAADAAAAAAAlAJEAAAADAAAAAAAlAJIAAAADAAAAAAAlAJMAAAADAAAAAAAlAJQAAAADAAAAAAAlAJUAAAADAAAAAAAlAJYAAAADAAAAAAAlAJcAAAADAAAAAAAlAJgAAAADAAAAAAAlAJkAAAADAAAAAAAlAJoAAAADAAAAAAAlAJsAAAADAAAAAAAlAJwAAAADAAAAAAAlAJ0AAAADAAAAAAAlAJ4AAAADAAAAAAAlAJ8AAAADAAAAAAAlAKAAAAADAAAAAAAlAKEAAAADAAAAAAAmAI8AAAADAAAAAAAmAJAAAAADAAAAAAAmAJEAAAADAAAAAAAmAJIAAAADAAAAAAAmAJMAAAADAAAAAAAmAJQAAAADAAAAAAAmAJUAAAADAAAAAAAmAJYAAAADAAAAAAAmAJcAAAADAAAAAAAmAJgAAAADAAAAAAAmAJkAAAADAAAAAAAmAJoAAAADAAAAAAAmAJsAAAADAAAAAAAmAJwAAAADAAAAAAAmAJ0AAAADAAAAAAAmAJ4AAAADAAAAAAAmAJ8AAAADAAAAAAAmAKAAAAADAAAAAAAmAKEAAAADAAAAAAAnAI8AAAADAAAAAAAnAJAAAAADAAAAAAAnAJEAAAADAAAAAAAnAJIAAAADAAAAAAAnAJMAAAADAAAAAAAnAJQAAAADAAAAAAAnAJUAAAADAAAAAAAnAJYAAAADAAAAAAAnAJcAAAADAAAAAAAnAJgAAAADAAAAAAAnAJkAAAADAAAAAAAnAJoAAAADAAAAAAAnAJsAAAADAAAAAAAnAJwAAAADAAAAAAAnAJ0AAAADAAAAAAAnAJ4AAAADAAAAAAAnAJ8AAAADAAAAAAAnAKAAAAADAAAAAAAnAKEAAAADAAAAAAASAH8AAAADAAAAAAASAIAAAAADAAAAAAASAIEAAAADAAAAAAASAIIAAAADAAAAAAASAIMAAAADAAAAAAASAIQAAAADAAAAAAASAIUAAAADAAAAAAASAIYAAAADAAAAAAASAIcAAAADAAAAAAASAIgAAAADAAAAAAASAIkAAAADAAAAAAASAIoAAAADAAAAAAASAIsAAAADAAAAAAASAIwAAAADAAAAAAASAI0AAAADAAAAAAASAI4AAAADAAAAAAASAI8AAAADAAAAAAASAJAAAAADAAAAAAASAJEAAAADAAAAAAASAJIAAAADAAAAAAASAJMAAAADAAAAAAASAJQAAAADAAAAAAASAJUAAAADAAAAAAASAJYAAAADAAAAAAASAJcAAAADAAAAAAASAJgAAAADAAAAAAASAJkAAAADAAAAAAASAJoAAAADAAAAAAASAJsAAAADAAAAAAASAJwAAAADAAAAAAASAJ0AAAADAAAAAAASAJ4AAAADAAAAAAATAH8AAAADAAAAAAATAIAAAAADAAAAAAATAIEAAAADAAAAAAATAIIAAAADAAAAAAATAIMAAAADAAAAAAATAIQAAAADAAAAAAATAIUAAAADAAAAAAATAIYAAAADAAAAAAATAIcAAAADAAAAAAATAIgAAAADAAAAAAATAIkAAAADAAAAAAATAIoAAAADAAAAAAATAIsAAAADAAAAAAATAIwAAAADAAAAAAATAI0AAAADAAAAAAATAI4AAAADAAAAAAATAI8AAAADAAAAAAATAJAAAAADAAAAAAATAJEAAAADAAAAAAATAJIAAAADAAAAAAATAJMAAAADAAAAAAATAJQAAAADAAAAAAATAJUAAAADAAAAAAATAJYAAAADAAAAAAATAJcAAAADAAAAAAATAJgAAAADAAAAAAATAJkAAAADAAAAAAATAJoAAAADAAAAAAATAJsAAAADAAAAAAATAJwAAAADAAAAAAATAJ0AAAADAAAAAAATAJ4AAAADAAAAAAAUAH8AAAADAAAAAAAUAIAAAAADAAAAAAAUAIEAAAADAAAAAAAUAIIAAAADAAAAAAAUAIMAAAADAAAAAAAUAIQAAAADAAAAAAAUAIUAAAADAAAAAAAUAIYAAAADAAAAAAAUAIcAAAADAAAAAAAUAIgAAAADAAAAAAAUAIkAAAADAAAAAAAUAIoAAAADAAAAAAAUAIsAAAADAAAAAAAUAIwAAAADAAAAAAAUAI0AAAADAAAAAAAUAI4AAAADAAAAAAAUAI8AAAADAAAAAAAUAJAAAAADAAAAAAAUAJEAAAADAAAAAAAUAJIAAAADAAAAAAAUAJMAAAADAAAAAAAUAJQAAAADAAAAAAAUAJUAAAADAAAAAAAUAJYAAAADAAAAAAAUAJcAAAADAAAAAAAUAJgAAAADAAAAAAAUAJkAAAADAAAAAAAUAJoAAAADAAAAAAAUAJsAAAADAAAAAAAUAJwAAAADAAAAAAAUAJ0AAAADAAAAAAAUAJ4AAAADAAAAAAAVAH8AAAADAAAAAAAVAIAAAAADAAAAAAAVAIEAAAADAAAAAAAVAIIAAAADAAAAAAAVAIMAAAADAAAAAAAVAIQAAAADAAAAAAAVAIUAAAADAAAAAAAVAIYAAAADAAAAAAAVAIcAAAADAAAAAAAVAIgAAAADAAAAAAAVAIkAAAADAAAAAAAVAIoAAAADAAAAAAAVAIsAAAADAAAAAAAVAIwAAAADAAAAAAAVAI0AAAADAAAAAAAVAI4AAAADAAAAAAAVAI8AAAADAAAAAAAVAJAAAAADAAAAAAAVAJEAAAADAAAAAAAVAJIAAAADAAAAAAAVAJMAAAADAAAAAAAVAJQAAAADAAAAAAAVAJUAAAADAAAAAAAVAJYAAAADAAAAAAAVAJcAAAADAAAAAAAVAJgAAAADAAAAAAAVAJkAAAADAAAAAAAVAJoAAAADAAAAAAAVAJsAAAADAAAAAAAVAJwAAAADAAAAAAAVAJ0AAAADAAAAAAAVAJ4AAAADAAAAAAAWAH8AAAADAAAAAAAWAIAAAAADAAAAAAAWAIEAAAADAAAAAAAWAIIAAAADAAAAAAAWAIMAAAADAAAAAAAWAIQAAAADAAAAAAAWAIUAAAADAAAAAAAWAIYAAAADAAAAAAAWAIcAAAADAAAAAAAWAIgAAAADAAAAAAAWAIkAAAADAAAAAAAWAIoAAAADAAAAAAAWAIsAAAADAAAAAAAWAIwAAAADAAAAAAAWAI0AAAADAAAAAAAWAI4AAAADAAAAAAAWAI8AAAADAAAAAAAWAJAAAAADAAAAAAAWAJEAAAADAAAAAAAWAJIAAAADAAAAAAAWAJMAAAADAAAAAAAWAJQAAAADAAAAAAAWAJUAAAADAAAAAAAWAJYAAAADAAAAAAAWAJcAAAADAAAAAAAWAJgAAAADAAAAAAAWAJkAAAADAAAAAAAWAJoAAAADAAAAAAAWAJsAAAADAAAAAAAWAJwAAAADAAAAAAAWAJ0AAAADAAAAAAAWAJ4AAAADAAAAAAAXAH8AAAADAAAAAAAXAIAAAAADAAAAAAAXAIEAAAADAAAAAAAXAIIAAAADAAAAAAAXAIMAAAADAAAAAAAXAIQAAAADAAAAAAAXAIUAAAADAAAAAAAXAIYAAAADAAAAAAAXAIcAAAADAAAAAAAXAIgAAAADAAAAAAAXAIkAAAADAAAAAAAXAIoAAAADAAAAAAAXAIsAAAADAAAAAAAXAIwAAAADAAAAAAAXAI0AAAADAAAAAAAXAI4AAAADAAAAAAAXAI8AAAADAAAAAAAXAJAAAAADAAAAAAAXAJEAAAADAAAAAAAXAJIAAAADAAAAAAAXAJMAAAADAAAAAAAXAJQAAAADAAAAAAAXAJUAAAADAAAAAAAXAJYAAAADAAAAAAAXAJcAAAADAAAAAAAXAJgAAAADAAAAAAAXAJkAAAADAAAAAAAXAJoAAAADAAAAAAAXAJsAAAADAAAAAAAXAJwAAAADAAAAAAAXAJ0AAAADAAAAAAAXAJ4AAAADAAAAAAAYAH8AAAADAAAAAAAYAIAAAAADAAAAAAAYAIEAAAADAAAAAAAYAIIAAAADAAAAAAAYAIMAAAADAAAAAAAYAIQAAAADAAAAAAAZAH8AAAADAAAAAAAZAIAAAAADAAAAAAAZAIEAAAADAAAAAAAZAIIAAAADAAAAAAAZAIMAAAADAAAAAAAZAIQAAAADAAAAAAAaAH8AAAADAAAAAAAaAIAAAAADAAAAAAAaAIEAAAADAAAAAAAaAIIAAAADAAAAAAAaAIMAAAADAAAAAAAaAIQAAAADAAAAAAAbAH8AAAADAAAAAAAbAIAAAAADAAAAAAAbAIEAAAADAAAAAAAbAIIAAAADAAAAAAAbAIMAAAADAAAAAAAbAIQAAAADAAAAAAAcAH8AAAADAAAAAAAcAIAAAAADAAAAAAAcAIEAAAADAAAAAAAcAIIAAAADAAAAAAAcAIMAAAADAAAAAAAcAIQAAAADAAAAAAAdAH8AAAADAAAAAAAdAIAAAAADAAAAAAAdAIEAAAADAAAAAAAdAIIAAAADAAAAAAAdAIMAAAADAAAAAAAdAIQAAAADAAAAAAAeAH8AAAADAAAAAAAeAIAAAAADAAAAAAAeAIEAAAADAAAAAAAeAIIAAAADAAAAAAAeAIMAAAADAAAAAAAeAIQAAAADAAAAAAAfAH8AAAADAAAAAAAfAIAAAAADAAAAAAAfAIEAAAADAAAAAAAfAIIAAAADAAAAAAAfAIMAAAADAAAAAAAfAIQAAAADAAAAAAAgAH8AAAADAAAAAAAgAIAAAAADAAAAAAAgAIEAAAADAAAAAAAgAIIAAAADAAAAAAAgAIMAAAADAAAAAAAgAIQAAAADAAAAAAAhAH8AAAADAAAAAAAhAIAAAAADAAAAAAAhAIEAAAADAAAAAAAhAIIAAAADAAAAAAAhAIMAAAADAAAAAAAhAIQAAAADAAAAAAAiAH8AAAADAAAAAAAiAIAAAAADAAAAAAAiAIEAAAADAAAAAAAiAIIAAAADAAAAAAAiAIMAAAADAAAAAAAiAIQAAAADAAAAAAAjAH8AAAADAAAAAAAjAIAAAAADAAAAAAAjAIEAAAADAAAAAAAjAIIAAAADAAAAAAAjAIMAAAADAAAAAAAjAIQAAAADAAAAAAAkAH8AAAADAAAAAAAkAIAAAAADAAAAAAAkAIEAAAADAAAAAAAkAIIAAAADAAAAAAAkAIMAAAADAAAAAAAkAIQAAAADAAAAAAAlAH8AAAADAAAAAAAlAIAAAAADAAAAAAAlAIEAAAADAAAAAAAlAIIAAAADAAAAAAAlAIMAAAADAAAAAAAlAIQAAAADAAAAAAAmAH8AAAADAAAAAAAmAIAAAAADAAAAAAAmAIEAAAADAAAAAAAmAIIAAAADAAAAAAAmAIMAAAADAAAAAAAmAIQAAAADAAAAAAAnAH8AAAADAAAAAAAnAIAAAAADAAAAAAAnAIEAAAADAAAAAAAnAIIAAAADAAAAAAAnAIMAAAADAAAAAAAnAIQAAAADAAAAAAAoAH8AAAADAAAAAAAoAIAAAAADAAAAAAAoAIEAAAADAAAAAAAoAIIAAAADAAAAAAAoAIMAAAADAAAAAAAoAIQAAAADAAAAAAApAH8AAAADAAAAAAApAIAAAAADAAAAAAApAIEAAAADAAAAAAApAIIAAAADAAAAAAApAIMAAAADAAAAAAApAIQAAAADAAAAAAANAG8AAAADAAAAAAANAHAAAAADAAAAAAANAHEAAAADAAAAAAANAHIAAAADAAAAAAANAHMAAAADAAAAAAANAHQAAAADAAAAAAAOAG8AAAADAAAAAAAOAHAAAAADAAAAAAAOAHEAAAADAAAAAAAOAHIAAAADAAAAAAAOAHMAAAADAAAAAAAOAHQAAAADAAAAAAAPAG8AAAADAAAAAAAPAHAAAAADAAAAAAAPAHEAAAADAAAAAAAPAHIAAAADAAAAAAAPAHMAAAADAAAAAAAPAHQAAAADAAAAAAAQAG8AAAADAAAAAAAQAHAAAAADAAAAAAAQAHEAAAADAAAAAAAQAHIAAAADAAAAAAAQAHMAAAADAAAAAAAQAHQAAAADAAAAAAARAG8AAAADAAAAAAARAHAAAAADAAAAAAARAHEAAAADAAAAAAARAHIAAAADAAAAAAARAHMAAAADAAAAAAARAHQAAAADAAAAAAASAG8AAAADAAAAAAASAHAAAAADAAAAAAASAHEAAAADAAAAAAASAHIAAAADAAAAAAASAHMAAAADAAAAAAASAHQAAAADAAAAAAATAG8AAAADAAAAAAATAHAAAAADAAAAAAATAHEAAAADAAAAAAATAHIAAAADAAAAAAATAHMAAAADAAAAAAATAHQAAAADAAAAAAAUAG8AAAADAAAAAAAUAHAAAAADAAAAAAAUAHEAAAADAAAAAAAUAHIAAAADAAAAAAAUAHMAAAADAAAAAAAUAHQAAAADAAAAAAAVAG8AAAADAAAAAAAVAHAAAAADAAAAAAAVAHEAAAADAAAAAAAVAHIAAAADAAAAAAAVAHMAAAADAAAAAAAVAHQAAAADAAAAAAAWAG8AAAADAAAAAAAWAHAAAAADAAAAAAAWAHEAAAADAAAAAAAWAHIAAAADAAAAAAAWAHMAAAADAAAAAAAWAHQAAAADAAAAAAAXAG8AAAADAAAAAAAXAHAAAAADAAAAAAAXAHEAAAADAAAAAAAXAHIAAAADAAAAAAAXAHMAAAADAAAAAAAXAHQAAAADAAAAAAAYAG8AAAADAAAAAAAYAHAAAAADAAAAAAAYAHEAAAADAAAAAAAYAHIAAAADAAAAAAAYAHMAAAADAAAAAAAYAHQAAAADAAAAAAAZAG8AAAADAAAAAAAZAHAAAAADAAAAAAAZAHEAAAADAAAAAAAZAHIAAAADAAAAAAAZAHMAAAADAAAAAAAZAHQAAAADAAAAAAAaAG8AAAADAAAAAAAaAHAAAAADAAAAAAAaAHEAAAADAAAAAAAaAHIAAAADAAAAAAAaAHMAAAADAAAAAAAaAHQAAAADAAAAAAAbAG8AAAADAAAAAAAbAHAAAAADAAAAAAAbAHEAAAADAAAAAAAbAHIAAAADAAAAAAAbAHMAAAADAAAAAAAbAHQAAAADAAAAAAAcAG8AAAADAAAAAAAcAHAAAAADAAAAAAAcAHEAAAADAAAAAAAcAHIAAAADAAAAAAAcAHMAAAADAAAAAAAcAHQAAAADAAAAAAAdAG8AAAADAAAAAAAdAHAAAAADAAAAAAAdAHEAAAADAAAAAAAdAHIAAAADAAAAAAAdAHMAAAADAAAAAAAdAHQAAAADAAAAAAAeAG8AAAADAAAAAAAeAHAAAAADAAAAAAAeAHEAAAADAAAAAAAeAHIAAAADAAAAAAAeAHMAAAADAAAAAAAeAHQAAAADAAAAAAAfAG8AAAADAAAAAAAfAHAAAAADAAAAAAAfAHEAAAADAAAAAAAfAHIAAAADAAAAAAAfAHMAAAADAAAAAAAfAHQAAAADAAAAAAA=\")\nplayer_id = 4\n\n[node name=\"BuildableArea5\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(0.933333, 1, 0, 0.211765)\ntile_map_data = PackedByteArray(\"AAD9/3EAAAADAAAAAAD9/3IAAAADAAAAAAD9/3MAAAADAAAAAAD9/3QAAAADAAAAAAD+/3EAAAADAAAAAAD+/3IAAAADAAAAAAD+/3MAAAADAAAAAAD+/3QAAAADAAAAAAD//3EAAAADAAAAAAD//3IAAAADAAAAAAD//3MAAAADAAAAAAD//3QAAAADAAAAAAAAAHEAAAADAAAAAAAAAHIAAAADAAAAAAAAAHMAAAADAAAAAAAAAHQAAAADAAAAAAABAHEAAAADAAAAAAABAHIAAAADAAAAAAABAHMAAAADAAAAAAABAHQAAAADAAAAAAACAHEAAAADAAAAAAACAHIAAAADAAAAAAACAHMAAAADAAAAAAACAHQAAAADAAAAAAADAHEAAAADAAAAAAADAHIAAAADAAAAAAADAHMAAAADAAAAAAADAHQAAAADAAAAAAAEAHEAAAADAAAAAAAEAHIAAAADAAAAAAAEAHMAAAADAAAAAAAEAHQAAAADAAAAAAAFAHEAAAADAAAAAAAFAHIAAAADAAAAAAAFAHMAAAADAAAAAAAFAHQAAAADAAAAAAAGAHEAAAADAAAAAAAGAHIAAAADAAAAAAAGAHMAAAADAAAAAAAGAHQAAAADAAAAAAAHAHEAAAADAAAAAAAHAHIAAAADAAAAAAAHAHMAAAADAAAAAAAHAHQAAAADAAAAAAAIAHEAAAADAAAAAAAIAHIAAAADAAAAAAAIAHMAAAADAAAAAAAIAHQAAAADAAAAAAAJAHEAAAADAAAAAAAJAHIAAAADAAAAAAAJAHMAAAADAAAAAAAJAHQAAAADAAAAAAAKAHEAAAADAAAAAAAKAHIAAAADAAAAAAAKAHMAAAADAAAAAAAKAHQAAAADAAAAAAALAHEAAAADAAAAAAALAHIAAAADAAAAAAALAHMAAAADAAAAAAALAHQAAAADAAAAAAAMAHEAAAADAAAAAAAMAHIAAAADAAAAAAAMAHMAAAADAAAAAAAMAHQAAAADAAAAAAD6/28AAAADAAAAAAD6/3AAAAADAAAAAAD6/3EAAAADAAAAAAD6/3IAAAADAAAAAAD6/3MAAAADAAAAAAD6/3QAAAADAAAAAAD7/28AAAADAAAAAAD7/3AAAAADAAAAAAD7/3EAAAADAAAAAAD7/3IAAAADAAAAAAD7/3MAAAADAAAAAAD7/3QAAAADAAAAAAD8/28AAAADAAAAAAD8/3AAAAADAAAAAAD8/3EAAAADAAAAAAD8/3IAAAADAAAAAAD8/3MAAAADAAAAAAD8/3QAAAADAAAAAAD9/28AAAADAAAAAAD9/3AAAAADAAAAAAD+/28AAAADAAAAAAD+/3AAAAADAAAAAAD//28AAAADAAAAAAD//3AAAAADAAAAAAAAAG8AAAADAAAAAAAAAHAAAAADAAAAAAABAG8AAAADAAAAAAABAHAAAAADAAAAAAACAG8AAAADAAAAAAACAHAAAAADAAAAAAADAG8AAAADAAAAAAADAHAAAAADAAAAAAAEAG8AAAADAAAAAAAEAHAAAAADAAAAAAAFAG8AAAADAAAAAAAFAHAAAAADAAAAAAAGAG8AAAADAAAAAAAGAHAAAAADAAAAAAAHAG8AAAADAAAAAAAHAHAAAAADAAAAAAAIAG8AAAADAAAAAAAIAHAAAAADAAAAAAAJAG8AAAADAAAAAAAJAHAAAAADAAAAAAAKAG8AAAADAAAAAAAKAHAAAAADAAAAAAALAG8AAAADAAAAAAALAHAAAAADAAAAAAAMAG8AAAADAAAAAAAMAHAAAAADAAAAAAACAH8AAAADAAAAAAACAIAAAAADAAAAAAACAIEAAAADAAAAAAACAIIAAAADAAAAAAACAIMAAAADAAAAAAACAIQAAAADAAAAAAACAIUAAAADAAAAAAACAIYAAAADAAAAAAACAIcAAAADAAAAAAACAIgAAAADAAAAAAACAIkAAAADAAAAAAACAIoAAAADAAAAAAACAIsAAAADAAAAAAACAIwAAAADAAAAAAACAI0AAAADAAAAAAACAI4AAAADAAAAAAACAI8AAAADAAAAAAACAJAAAAADAAAAAAACAJEAAAADAAAAAAACAJIAAAADAAAAAAACAJMAAAADAAAAAAACAJQAAAADAAAAAAACAJUAAAADAAAAAAACAJYAAAADAAAAAAACAJcAAAADAAAAAAACAJgAAAADAAAAAAACAJkAAAADAAAAAAACAJoAAAADAAAAAAACAJsAAAADAAAAAAACAJwAAAADAAAAAAACAJ0AAAADAAAAAAACAJ4AAAADAAAAAAADAH8AAAADAAAAAAADAIAAAAADAAAAAAADAIEAAAADAAAAAAADAIIAAAADAAAAAAADAIMAAAADAAAAAAADAIQAAAADAAAAAAADAIUAAAADAAAAAAADAIYAAAADAAAAAAADAIcAAAADAAAAAAADAIgAAAADAAAAAAADAIkAAAADAAAAAAADAIoAAAADAAAAAAADAIsAAAADAAAAAAADAIwAAAADAAAAAAADAI0AAAADAAAAAAADAI4AAAADAAAAAAADAI8AAAADAAAAAAADAJAAAAADAAAAAAADAJEAAAADAAAAAAADAJIAAAADAAAAAAADAJMAAAADAAAAAAADAJQAAAADAAAAAAADAJUAAAADAAAAAAADAJYAAAADAAAAAAADAJcAAAADAAAAAAADAJgAAAADAAAAAAADAJkAAAADAAAAAAADAJoAAAADAAAAAAADAJsAAAADAAAAAAADAJwAAAADAAAAAAADAJ0AAAADAAAAAAADAJ4AAAADAAAAAAAEAH8AAAADAAAAAAAEAIAAAAADAAAAAAAEAIEAAAADAAAAAAAEAIIAAAADAAAAAAAEAIMAAAADAAAAAAAEAIQAAAADAAAAAAAEAIUAAAADAAAAAAAEAIYAAAADAAAAAAAEAIcAAAADAAAAAAAEAIgAAAADAAAAAAAEAIkAAAADAAAAAAAEAIoAAAADAAAAAAAEAIsAAAADAAAAAAAEAIwAAAADAAAAAAAEAI0AAAADAAAAAAAEAI4AAAADAAAAAAAEAI8AAAADAAAAAAAEAJAAAAADAAAAAAAEAJEAAAADAAAAAAAEAJIAAAADAAAAAAAEAJMAAAADAAAAAAAEAJQAAAADAAAAAAAEAJUAAAADAAAAAAAEAJYAAAADAAAAAAAEAJcAAAADAAAAAAAEAJgAAAADAAAAAAAEAJkAAAADAAAAAAAEAJoAAAADAAAAAAAEAJsAAAADAAAAAAAEAJwAAAADAAAAAAAEAJ0AAAADAAAAAAAEAJ4AAAADAAAAAAAFAH8AAAADAAAAAAAFAIAAAAADAAAAAAAFAIEAAAADAAAAAAAFAIIAAAADAAAAAAAFAIMAAAADAAAAAAAFAIQAAAADAAAAAAAFAIUAAAADAAAAAAAFAIYAAAADAAAAAAAFAIcAAAADAAAAAAAFAIgAAAADAAAAAAAFAIkAAAADAAAAAAAFAIoAAAADAAAAAAAFAIsAAAADAAAAAAAFAIwAAAADAAAAAAAFAI0AAAADAAAAAAAFAI4AAAADAAAAAAAFAI8AAAADAAAAAAAFAJAAAAADAAAAAAAFAJEAAAADAAAAAAAFAJIAAAADAAAAAAAFAJMAAAADAAAAAAAFAJQAAAADAAAAAAAFAJUAAAADAAAAAAAFAJYAAAADAAAAAAAFAJcAAAADAAAAAAAFAJgAAAADAAAAAAAFAJkAAAADAAAAAAAFAJoAAAADAAAAAAAFAJsAAAADAAAAAAAFAJwAAAADAAAAAAAFAJ0AAAADAAAAAAAFAJ4AAAADAAAAAAAGAH8AAAADAAAAAAAGAIAAAAADAAAAAAAGAIEAAAADAAAAAAAGAIIAAAADAAAAAAAGAIMAAAADAAAAAAAGAIQAAAADAAAAAAAGAIUAAAADAAAAAAAGAIYAAAADAAAAAAAGAIcAAAADAAAAAAAGAIgAAAADAAAAAAAGAIkAAAADAAAAAAAGAIoAAAADAAAAAAAGAIsAAAADAAAAAAAGAIwAAAADAAAAAAAGAI0AAAADAAAAAAAGAI4AAAADAAAAAAAGAI8AAAADAAAAAAAGAJAAAAADAAAAAAAGAJEAAAADAAAAAAAGAJIAAAADAAAAAAAGAJMAAAADAAAAAAAGAJQAAAADAAAAAAAGAJUAAAADAAAAAAAGAJYAAAADAAAAAAAGAJcAAAADAAAAAAAGAJgAAAADAAAAAAAGAJkAAAADAAAAAAAGAJoAAAADAAAAAAAGAJsAAAADAAAAAAAGAJwAAAADAAAAAAAGAJ0AAAADAAAAAAAGAJ4AAAADAAAAAAAHAH8AAAADAAAAAAAHAIAAAAADAAAAAAAHAIEAAAADAAAAAAAHAIIAAAADAAAAAAAHAIMAAAADAAAAAAAHAIQAAAADAAAAAAAHAIUAAAADAAAAAAAHAIYAAAADAAAAAAAHAIcAAAADAAAAAAAHAIgAAAADAAAAAAAHAIkAAAADAAAAAAAHAIoAAAADAAAAAAAHAIsAAAADAAAAAAAHAIwAAAADAAAAAAAHAI0AAAADAAAAAAAHAI4AAAADAAAAAAAHAI8AAAADAAAAAAAHAJAAAAADAAAAAAAHAJEAAAADAAAAAAAHAJIAAAADAAAAAAAHAJMAAAADAAAAAAAHAJQAAAADAAAAAAAHAJUAAAADAAAAAAAHAJYAAAADAAAAAAAHAJcAAAADAAAAAAAHAJgAAAADAAAAAAAHAJkAAAADAAAAAAAHAJoAAAADAAAAAAAHAJsAAAADAAAAAAAHAJwAAAADAAAAAAAHAJ0AAAADAAAAAAAHAJ4AAAADAAAAAADx/38AAAADAAAAAADx/4AAAAADAAAAAADx/4EAAAADAAAAAADx/4IAAAADAAAAAADx/4MAAAADAAAAAADx/4QAAAADAAAAAADy/38AAAADAAAAAADy/4AAAAADAAAAAADy/4EAAAADAAAAAADy/4IAAAADAAAAAADy/4MAAAADAAAAAADy/4QAAAADAAAAAADz/38AAAADAAAAAADz/4AAAAADAAAAAADz/4EAAAADAAAAAADz/4IAAAADAAAAAADz/4MAAAADAAAAAADz/4QAAAADAAAAAAD0/38AAAADAAAAAAD0/4AAAAADAAAAAAD0/4EAAAADAAAAAAD0/4IAAAADAAAAAAD0/4MAAAADAAAAAAD0/4QAAAADAAAAAAD1/38AAAADAAAAAAD1/4AAAAADAAAAAAD1/4EAAAADAAAAAAD1/4IAAAADAAAAAAD1/4MAAAADAAAAAAD1/4QAAAADAAAAAAD2/38AAAADAAAAAAD2/4AAAAADAAAAAAD2/4EAAAADAAAAAAD2/4IAAAADAAAAAAD2/4MAAAADAAAAAAD2/4QAAAADAAAAAAD3/38AAAADAAAAAAD3/4AAAAADAAAAAAD3/4EAAAADAAAAAAD3/4IAAAADAAAAAAD3/4MAAAADAAAAAAD3/4QAAAADAAAAAAD4/38AAAADAAAAAAD4/4AAAAADAAAAAAD4/4EAAAADAAAAAAD4/4IAAAADAAAAAAD4/4MAAAADAAAAAAD4/4QAAAADAAAAAAD5/38AAAADAAAAAAD5/4AAAAADAAAAAAD5/4EAAAADAAAAAAD5/4IAAAADAAAAAAD5/4MAAAADAAAAAAD5/4QAAAADAAAAAAD6/38AAAADAAAAAAD6/4AAAAADAAAAAAD6/4EAAAADAAAAAAD6/4IAAAADAAAAAAD6/4MAAAADAAAAAAD6/4QAAAADAAAAAAD7/38AAAADAAAAAAD7/4AAAAADAAAAAAD7/4EAAAADAAAAAAD7/4IAAAADAAAAAAD7/4MAAAADAAAAAAD7/4QAAAADAAAAAAD8/38AAAADAAAAAAD8/4AAAAADAAAAAAD8/4EAAAADAAAAAAD8/4IAAAADAAAAAAD8/4MAAAADAAAAAAD8/4QAAAADAAAAAAD9/38AAAADAAAAAAD9/4AAAAADAAAAAAD9/4EAAAADAAAAAAD9/4IAAAADAAAAAAD9/4MAAAADAAAAAAD9/4QAAAADAAAAAAD+/38AAAADAAAAAAD+/4AAAAADAAAAAAD+/4EAAAADAAAAAAD+/4IAAAADAAAAAAD+/4MAAAADAAAAAAD+/4QAAAADAAAAAAD//38AAAADAAAAAAD//4AAAAADAAAAAAD//4EAAAADAAAAAAD//4IAAAADAAAAAAD//4MAAAADAAAAAAD//4QAAAADAAAAAAAAAH8AAAADAAAAAAAAAIAAAAADAAAAAAAAAIEAAAADAAAAAAAAAIIAAAADAAAAAAAAAIMAAAADAAAAAAAAAIQAAAADAAAAAAABAH8AAAADAAAAAAABAIAAAAADAAAAAAABAIEAAAADAAAAAAABAIIAAAADAAAAAAABAIMAAAADAAAAAAABAIQAAAADAAAAAADy/48AAAADAAAAAADy/5AAAAADAAAAAADy/5EAAAADAAAAAADy/5IAAAADAAAAAADy/5MAAAADAAAAAADy/5QAAAADAAAAAADy/5UAAAADAAAAAADy/5YAAAADAAAAAADy/5cAAAADAAAAAADy/5gAAAADAAAAAADy/5kAAAADAAAAAADy/5oAAAADAAAAAADy/5sAAAADAAAAAADy/5wAAAADAAAAAADy/50AAAADAAAAAADy/54AAAADAAAAAADy/58AAAADAAAAAADy/6AAAAADAAAAAADy/6EAAAADAAAAAADz/48AAAADAAAAAADz/5AAAAADAAAAAADz/5EAAAADAAAAAADz/5IAAAADAAAAAADz/5MAAAADAAAAAADz/5QAAAADAAAAAADz/5UAAAADAAAAAADz/5YAAAADAAAAAADz/5cAAAADAAAAAADz/5gAAAADAAAAAADz/5kAAAADAAAAAADz/5oAAAADAAAAAADz/5sAAAADAAAAAADz/5wAAAADAAAAAADz/50AAAADAAAAAADz/54AAAADAAAAAADz/58AAAADAAAAAADz/6AAAAADAAAAAADz/6EAAAADAAAAAAD0/48AAAADAAAAAAD0/5AAAAADAAAAAAD0/5EAAAADAAAAAAD0/5IAAAADAAAAAAD0/5MAAAADAAAAAAD0/5QAAAADAAAAAAD0/5UAAAADAAAAAAD0/5YAAAADAAAAAAD0/5cAAAADAAAAAAD0/5gAAAADAAAAAAD0/5kAAAADAAAAAAD0/5oAAAADAAAAAAD0/5sAAAADAAAAAAD0/5wAAAADAAAAAAD0/50AAAADAAAAAAD0/54AAAADAAAAAAD0/58AAAADAAAAAAD0/6AAAAADAAAAAAD0/6EAAAADAAAAAAD1/48AAAADAAAAAAD1/5AAAAADAAAAAAD1/5EAAAADAAAAAAD1/5IAAAADAAAAAAD1/5MAAAADAAAAAAD1/5QAAAADAAAAAAD1/5UAAAADAAAAAAD1/5YAAAADAAAAAAD1/5cAAAADAAAAAAD1/5gAAAADAAAAAAD1/5kAAAADAAAAAAD1/5oAAAADAAAAAAD1/5sAAAADAAAAAAD1/5wAAAADAAAAAAD1/50AAAADAAAAAAD1/54AAAADAAAAAAD1/58AAAADAAAAAAD1/6AAAAADAAAAAAD1/6EAAAADAAAAAAD2/48AAAADAAAAAAD2/5AAAAADAAAAAAD2/5EAAAADAAAAAAD2/5IAAAADAAAAAAD2/5MAAAADAAAAAAD2/5QAAAADAAAAAAD2/5UAAAADAAAAAAD2/5YAAAADAAAAAAD2/5cAAAADAAAAAAD2/5gAAAADAAAAAAD2/5kAAAADAAAAAAD2/5oAAAADAAAAAAD2/5sAAAADAAAAAAD2/5wAAAADAAAAAAD2/50AAAADAAAAAAD2/54AAAADAAAAAAD2/58AAAADAAAAAAD2/6AAAAADAAAAAAD2/6EAAAADAAAAAAD3/48AAAADAAAAAAD3/5AAAAADAAAAAAD3/5EAAAADAAAAAAD3/5IAAAADAAAAAAD3/5MAAAADAAAAAAD3/5QAAAADAAAAAAD3/5UAAAADAAAAAAD3/5YAAAADAAAAAAD3/5cAAAADAAAAAAD3/5gAAAADAAAAAAD3/5kAAAADAAAAAAD3/5oAAAADAAAAAAD3/5sAAAADAAAAAAD3/5wAAAADAAAAAAD3/50AAAADAAAAAAD3/54AAAADAAAAAAD3/58AAAADAAAAAAD3/6AAAAADAAAAAAD3/6EAAAADAAAAAAA=\")\nplayer_id = 5\n\n[node name=\"BuildableArea6\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(0.35, 1, 0, 0.211765)\ntile_map_data = PackedByteArray(\"AACr/1UAAAADAAAAAACr/1YAAAADAAAAAACr/1cAAAADAAAAAACr/1gAAAADAAAAAACr/1kAAAADAAAAAACr/1oAAAADAAAAAACs/1UAAAADAAAAAACs/1YAAAADAAAAAACs/1cAAAADAAAAAACs/1gAAAADAAAAAACs/1kAAAADAAAAAACs/1oAAAADAAAAAACt/1UAAAADAAAAAACt/1YAAAADAAAAAACt/1cAAAADAAAAAACt/1gAAAADAAAAAACt/1kAAAADAAAAAACt/1oAAAADAAAAAACu/1UAAAADAAAAAACu/1YAAAADAAAAAACu/1cAAAADAAAAAACu/1gAAAADAAAAAACu/1kAAAADAAAAAACu/1oAAAADAAAAAACv/1UAAAADAAAAAACv/1YAAAADAAAAAACv/1cAAAADAAAAAACv/1gAAAADAAAAAACv/1kAAAADAAAAAACv/1oAAAADAAAAAACw/1UAAAADAAAAAACw/1YAAAADAAAAAACw/1cAAAADAAAAAACw/1gAAAADAAAAAACw/1kAAAADAAAAAACw/1oAAAADAAAAAACx/1UAAAADAAAAAACx/1YAAAADAAAAAACx/1cAAAADAAAAAACx/1gAAAADAAAAAACx/1kAAAADAAAAAACx/1oAAAADAAAAAACy/1UAAAADAAAAAACy/1YAAAADAAAAAACy/1cAAAADAAAAAACy/1gAAAADAAAAAACy/1kAAAADAAAAAACy/1oAAAADAAAAAACz/1UAAAADAAAAAACz/1YAAAADAAAAAACz/1cAAAADAAAAAACz/1gAAAADAAAAAACz/1kAAAADAAAAAACz/1oAAAADAAAAAAC0/1UAAAADAAAAAAC0/1YAAAADAAAAAAC0/1cAAAADAAAAAAC0/1gAAAADAAAAAAC0/1kAAAADAAAAAAC0/1oAAAADAAAAAAC1/1UAAAADAAAAAAC1/1YAAAADAAAAAAC1/1cAAAADAAAAAAC1/1gAAAADAAAAAAC1/1kAAAADAAAAAAC1/1oAAAADAAAAAAC2/1UAAAADAAAAAAC2/1YAAAADAAAAAAC2/1cAAAADAAAAAAC2/1gAAAADAAAAAAC2/1kAAAADAAAAAAC2/1oAAAADAAAAAAC3/1UAAAADAAAAAAC3/1YAAAADAAAAAAC3/1cAAAADAAAAAAC3/1gAAAADAAAAAAC3/1kAAAADAAAAAAC3/1oAAAADAAAAAAC4/1UAAAADAAAAAAC4/1YAAAADAAAAAAC4/1cAAAADAAAAAAC4/1gAAAADAAAAAAC4/1kAAAADAAAAAAC4/1oAAAADAAAAAAC5/1UAAAADAAAAAAC5/1YAAAADAAAAAAC5/1cAAAADAAAAAAC5/1gAAAADAAAAAAC5/1kAAAADAAAAAAC5/1oAAAADAAAAAAC6/1UAAAADAAAAAAC6/1YAAAADAAAAAAC6/1cAAAADAAAAAAC6/1gAAAADAAAAAAC6/1kAAAADAAAAAAC6/1oAAAADAAAAAAC7/1UAAAADAAAAAAC7/1YAAAADAAAAAAC7/1cAAAADAAAAAAC7/1gAAAADAAAAAAC7/1kAAAADAAAAAAC7/1oAAAADAAAAAAC8/1UAAAADAAAAAAC8/1YAAAADAAAAAAC8/1cAAAADAAAAAAC8/1gAAAADAAAAAAC8/1kAAAADAAAAAAC8/1oAAAADAAAAAAC9/1UAAAADAAAAAAC9/1YAAAADAAAAAAC9/1cAAAADAAAAAAC9/1gAAAADAAAAAAC9/1kAAAADAAAAAAC9/1oAAAADAAAAAACw/0UAAAADAAAAAACw/0YAAAADAAAAAACw/0cAAAADAAAAAACw/0gAAAADAAAAAACw/0kAAAADAAAAAACw/0oAAAADAAAAAACx/0UAAAADAAAAAACx/0YAAAADAAAAAACx/0cAAAADAAAAAACx/0gAAAADAAAAAACx/0kAAAADAAAAAACx/0oAAAADAAAAAACy/0UAAAADAAAAAACy/0YAAAADAAAAAACy/0cAAAADAAAAAACy/0gAAAADAAAAAACy/0kAAAADAAAAAACy/0oAAAADAAAAAACz/0UAAAADAAAAAACz/0YAAAADAAAAAACz/0cAAAADAAAAAACz/0gAAAADAAAAAACz/0kAAAADAAAAAACz/0oAAAADAAAAAAC0/0UAAAADAAAAAAC0/0YAAAADAAAAAAC0/0cAAAADAAAAAAC0/0gAAAADAAAAAAC0/0kAAAADAAAAAAC0/0oAAAADAAAAAAC1/0UAAAADAAAAAAC1/0YAAAADAAAAAAC1/0cAAAADAAAAAAC1/0gAAAADAAAAAAC1/0kAAAADAAAAAAC1/0oAAAADAAAAAAC2/0UAAAADAAAAAAC2/0YAAAADAAAAAAC2/0cAAAADAAAAAAC2/0gAAAADAAAAAAC2/0kAAAADAAAAAAC2/0oAAAADAAAAAAC3/0UAAAADAAAAAAC3/0YAAAADAAAAAAC3/0cAAAADAAAAAAC3/0gAAAADAAAAAAC3/0kAAAADAAAAAAC3/0oAAAADAAAAAAC4/0UAAAADAAAAAAC4/0YAAAADAAAAAAC4/0cAAAADAAAAAAC4/0gAAAADAAAAAAC4/0kAAAADAAAAAAC4/0oAAAADAAAAAAC5/0UAAAADAAAAAAC5/0YAAAADAAAAAAC5/0cAAAADAAAAAAC5/0gAAAADAAAAAAC5/0kAAAADAAAAAAC5/0oAAAADAAAAAAC6/0UAAAADAAAAAAC6/0YAAAADAAAAAAC6/0cAAAADAAAAAAC6/0gAAAADAAAAAAC6/0kAAAADAAAAAAC6/0oAAAADAAAAAAC7/0UAAAADAAAAAAC7/0YAAAADAAAAAAC7/0cAAAADAAAAAAC7/0gAAAADAAAAAAC7/0kAAAADAAAAAAC7/0oAAAADAAAAAAC8/0UAAAADAAAAAAC8/0YAAAADAAAAAAC8/0cAAAADAAAAAAC8/0gAAAADAAAAAAC8/0kAAAADAAAAAAC8/0oAAAADAAAAAAC9/0UAAAADAAAAAAC9/0YAAAADAAAAAAC9/0cAAAADAAAAAAC9/0gAAAADAAAAAAC9/0kAAAADAAAAAAC9/0oAAAADAAAAAAC+/0UAAAADAAAAAAC+/0YAAAADAAAAAAC+/0cAAAADAAAAAAC+/0gAAAADAAAAAAC+/0kAAAADAAAAAAC+/0oAAAADAAAAAAC//0UAAAADAAAAAAC//0YAAAADAAAAAAC//0cAAAADAAAAAAC//0gAAAADAAAAAAC//0kAAAADAAAAAAC//0oAAAADAAAAAADA/0UAAAADAAAAAADA/0YAAAADAAAAAADA/0cAAAADAAAAAADA/0gAAAADAAAAAADA/0kAAAADAAAAAADA/0oAAAADAAAAAADB/0UAAAADAAAAAADB/0YAAAADAAAAAADB/0cAAAADAAAAAADB/0gAAAADAAAAAADB/0kAAAADAAAAAADB/0oAAAADAAAAAADC/0UAAAADAAAAAADC/0YAAAADAAAAAADC/0cAAAADAAAAAADC/0gAAAADAAAAAADC/0kAAAADAAAAAADC/0oAAAADAAAAAADD/0UAAAADAAAAAADD/0YAAAADAAAAAADD/0cAAAADAAAAAADD/0gAAAADAAAAAADD/0kAAAADAAAAAADD/0oAAAADAAAAAADE/0UAAAADAAAAAADE/0YAAAADAAAAAADE/0cAAAADAAAAAADE/0gAAAADAAAAAADE/0kAAAADAAAAAADE/0oAAAADAAAAAADF/0UAAAADAAAAAADF/0YAAAADAAAAAADF/0cAAAADAAAAAADF/0gAAAADAAAAAADF/0kAAAADAAAAAADF/0oAAAADAAAAAADG/0UAAAADAAAAAADG/0YAAAADAAAAAADG/0cAAAADAAAAAADG/0gAAAADAAAAAADG/0kAAAADAAAAAADG/0oAAAADAAAAAADH/0UAAAADAAAAAADH/0YAAAADAAAAAADH/0cAAAADAAAAAADH/0gAAAADAAAAAADH/0kAAAADAAAAAADH/0oAAAADAAAAAADI/0UAAAADAAAAAADI/0YAAAADAAAAAADI/0cAAAADAAAAAADI/0gAAAADAAAAAADI/0kAAAADAAAAAADI/0oAAAADAAAAAADJ/0UAAAADAAAAAADJ/0YAAAADAAAAAADJ/0cAAAADAAAAAADJ/0gAAAADAAAAAADJ/0kAAAADAAAAAADJ/0oAAAADAAAAAADK/0UAAAADAAAAAADK/0YAAAADAAAAAADK/0cAAAADAAAAAADK/0gAAAADAAAAAADK/0kAAAADAAAAAADK/0oAAAADAAAAAADL/0UAAAADAAAAAADL/0YAAAADAAAAAADL/0cAAAADAAAAAADL/0gAAAADAAAAAADL/0kAAAADAAAAAADL/0oAAAADAAAAAADM/0UAAAADAAAAAADM/0YAAAADAAAAAADM/0cAAAADAAAAAADM/0gAAAADAAAAAADM/0kAAAADAAAAAADM/0oAAAADAAAAAADN/0UAAAADAAAAAADN/0YAAAADAAAAAADN/0cAAAADAAAAAADN/0gAAAADAAAAAADN/0kAAAADAAAAAADN/0oAAAADAAAAAADI/0sAAAADAAAAAADI/0wAAAADAAAAAADI/00AAAADAAAAAADI/04AAAADAAAAAADI/08AAAADAAAAAADI/1AAAAADAAAAAADI/1EAAAADAAAAAADI/1IAAAADAAAAAADI/1MAAAADAAAAAADI/1QAAAADAAAAAADI/1UAAAADAAAAAADI/1YAAAADAAAAAADI/1cAAAADAAAAAADI/1gAAAADAAAAAADI/1kAAAADAAAAAADI/1oAAAADAAAAAADI/1sAAAADAAAAAADJ/0sAAAADAAAAAADJ/0wAAAADAAAAAADJ/00AAAADAAAAAADJ/04AAAADAAAAAADJ/08AAAADAAAAAADJ/1AAAAADAAAAAADJ/1EAAAADAAAAAADJ/1IAAAADAAAAAADJ/1MAAAADAAAAAADJ/1QAAAADAAAAAADJ/1UAAAADAAAAAADJ/1YAAAADAAAAAADJ/1cAAAADAAAAAADJ/1gAAAADAAAAAADJ/1kAAAADAAAAAADJ/1oAAAADAAAAAADJ/1sAAAADAAAAAADK/0sAAAADAAAAAADK/0wAAAADAAAAAADK/00AAAADAAAAAADK/04AAAADAAAAAADK/08AAAADAAAAAADK/1AAAAADAAAAAADK/1EAAAADAAAAAADK/1IAAAADAAAAAADK/1MAAAADAAAAAADK/1QAAAADAAAAAADK/1UAAAADAAAAAADK/1YAAAADAAAAAADK/1cAAAADAAAAAADK/1gAAAADAAAAAADK/1kAAAADAAAAAADK/1oAAAADAAAAAADK/1sAAAADAAAAAADL/0sAAAADAAAAAADL/0wAAAADAAAAAADL/00AAAADAAAAAADL/04AAAADAAAAAADL/08AAAADAAAAAADL/1AAAAADAAAAAADL/1EAAAADAAAAAADL/1IAAAADAAAAAADL/1MAAAADAAAAAADL/1QAAAADAAAAAADL/1UAAAADAAAAAADL/1YAAAADAAAAAADL/1cAAAADAAAAAADL/1gAAAADAAAAAADL/1kAAAADAAAAAADL/1oAAAADAAAAAADL/1sAAAADAAAAAADM/0sAAAADAAAAAADM/0wAAAADAAAAAADM/00AAAADAAAAAADM/04AAAADAAAAAADM/08AAAADAAAAAADM/1AAAAADAAAAAADM/1EAAAADAAAAAADM/1IAAAADAAAAAADM/1MAAAADAAAAAADM/1QAAAADAAAAAADM/1UAAAADAAAAAADM/1YAAAADAAAAAADM/1cAAAADAAAAAADM/1gAAAADAAAAAADM/1kAAAADAAAAAADM/1oAAAADAAAAAADM/1sAAAADAAAAAADN/0sAAAADAAAAAADN/0wAAAADAAAAAADN/00AAAADAAAAAADN/04AAAADAAAAAADN/08AAAADAAAAAADN/1AAAAADAAAAAADN/1EAAAADAAAAAADN/1IAAAADAAAAAADN/1MAAAADAAAAAADN/1QAAAADAAAAAADN/1UAAAADAAAAAADN/1YAAAADAAAAAADN/1cAAAADAAAAAADN/1gAAAADAAAAAADN/1kAAAADAAAAAADN/1oAAAADAAAAAADN/1sAAAADAAAAAADY/0AAAAADAAAAAADY/0EAAAADAAAAAADY/0IAAAADAAAAAADY/0MAAAADAAAAAADY/0QAAAADAAAAAADY/0UAAAADAAAAAADY/0YAAAADAAAAAADY/0cAAAADAAAAAADY/0gAAAADAAAAAADY/0kAAAADAAAAAADY/0oAAAADAAAAAADY/0sAAAADAAAAAADY/0wAAAADAAAAAADY/00AAAADAAAAAADY/04AAAADAAAAAADY/08AAAADAAAAAADY/1AAAAADAAAAAADY/1EAAAADAAAAAADY/1IAAAADAAAAAADZ/0AAAAADAAAAAADZ/0EAAAADAAAAAADZ/0IAAAADAAAAAADZ/0MAAAADAAAAAADZ/0QAAAADAAAAAADZ/0UAAAADAAAAAADZ/0YAAAADAAAAAADZ/0cAAAADAAAAAADZ/0gAAAADAAAAAADZ/0kAAAADAAAAAADZ/0oAAAADAAAAAADZ/0sAAAADAAAAAADZ/0wAAAADAAAAAADZ/00AAAADAAAAAADZ/04AAAADAAAAAADZ/08AAAADAAAAAADZ/1AAAAADAAAAAADZ/1EAAAADAAAAAADZ/1IAAAADAAAAAADa/0AAAAADAAAAAADa/0EAAAADAAAAAADa/0IAAAADAAAAAADa/0MAAAADAAAAAADa/0QAAAADAAAAAADa/0UAAAADAAAAAADa/0YAAAADAAAAAADa/0cAAAADAAAAAADa/0gAAAADAAAAAADa/0kAAAADAAAAAADa/0oAAAADAAAAAADa/0sAAAADAAAAAADa/0wAAAADAAAAAADa/00AAAADAAAAAADa/04AAAADAAAAAADa/08AAAADAAAAAADa/1AAAAADAAAAAADa/1EAAAADAAAAAADa/1IAAAADAAAAAADb/0AAAAADAAAAAADb/0EAAAADAAAAAADb/0IAAAADAAAAAADb/0MAAAADAAAAAADb/0QAAAADAAAAAADb/0UAAAADAAAAAADb/0YAAAADAAAAAADb/0cAAAADAAAAAADb/0gAAAADAAAAAADb/0kAAAADAAAAAADb/0oAAAADAAAAAADb/0sAAAADAAAAAADb/0wAAAADAAAAAADb/00AAAADAAAAAADb/04AAAADAAAAAADb/08AAAADAAAAAADb/1AAAAADAAAAAADb/1EAAAADAAAAAADb/1IAAAADAAAAAADc/0AAAAADAAAAAADc/0EAAAADAAAAAADc/0IAAAADAAAAAADc/0MAAAADAAAAAADc/0QAAAADAAAAAADc/0UAAAADAAAAAADc/0YAAAADAAAAAADc/0cAAAADAAAAAADc/0gAAAADAAAAAADc/0kAAAADAAAAAADc/0oAAAADAAAAAADc/0sAAAADAAAAAADc/0wAAAADAAAAAADc/00AAAADAAAAAADc/04AAAADAAAAAADc/08AAAADAAAAAADc/1AAAAADAAAAAADc/1EAAAADAAAAAADc/1IAAAADAAAAAADd/0AAAAADAAAAAADd/0EAAAADAAAAAADd/0IAAAADAAAAAADd/0MAAAADAAAAAADd/0QAAAADAAAAAADd/0UAAAADAAAAAADd/0YAAAADAAAAAADd/0cAAAADAAAAAADd/0gAAAADAAAAAADd/0kAAAADAAAAAADd/0oAAAADAAAAAADd/0sAAAADAAAAAADd/0wAAAADAAAAAADd/00AAAADAAAAAADd/04AAAADAAAAAADd/08AAAADAAAAAADd/1AAAAADAAAAAADd/1EAAAADAAAAAADd/1IAAAADAAAAAAA=\")\nplayer_id = 6\n\n[node name=\"BuildableArea7\" parent=\"BuildableAreaParent\" instance=ExtResource(\"13_6pgbl\")]\nvisible = false\nmodulate = Color(0, 1, 0.366667, 0.211765)\ntile_map_data = PackedByteArray(\"AADY/y0AAAADAAAAAADY/y4AAAADAAAAAADY/y8AAAADAAAAAADY/zAAAAADAAAAAADY/zEAAAADAAAAAADY/zIAAAADAAAAAADY/zMAAAADAAAAAADY/zQAAAADAAAAAADY/zUAAAADAAAAAADY/zYAAAADAAAAAADY/zcAAAADAAAAAADY/zgAAAADAAAAAADY/zkAAAADAAAAAADY/zoAAAADAAAAAADY/zsAAAADAAAAAADY/zwAAAADAAAAAADY/z0AAAADAAAAAADY/z4AAAADAAAAAADY/z8AAAADAAAAAADZ/y0AAAADAAAAAADZ/y4AAAADAAAAAADZ/y8AAAADAAAAAADZ/zAAAAADAAAAAADZ/zEAAAADAAAAAADZ/zIAAAADAAAAAADZ/zMAAAADAAAAAADZ/zQAAAADAAAAAADZ/zUAAAADAAAAAADZ/zYAAAADAAAAAADZ/zcAAAADAAAAAADZ/zgAAAADAAAAAADZ/zkAAAADAAAAAADZ/zoAAAADAAAAAADZ/zsAAAADAAAAAADZ/zwAAAADAAAAAADZ/z0AAAADAAAAAADZ/z4AAAADAAAAAADZ/z8AAAADAAAAAADa/y0AAAADAAAAAADa/y4AAAADAAAAAADa/y8AAAADAAAAAADa/zAAAAADAAAAAADa/zEAAAADAAAAAADa/zIAAAADAAAAAADa/zMAAAADAAAAAADa/zQAAAADAAAAAADa/zUAAAADAAAAAADa/zYAAAADAAAAAADa/zcAAAADAAAAAADa/zgAAAADAAAAAADa/zkAAAADAAAAAADa/zoAAAADAAAAAADa/zsAAAADAAAAAADa/zwAAAADAAAAAADa/z0AAAADAAAAAADa/z4AAAADAAAAAADa/z8AAAADAAAAAADb/y0AAAADAAAAAADb/y4AAAADAAAAAADb/y8AAAADAAAAAADb/zAAAAADAAAAAADb/zEAAAADAAAAAADb/zIAAAADAAAAAADb/zMAAAADAAAAAADb/zQAAAADAAAAAADb/zUAAAADAAAAAADb/zYAAAADAAAAAADb/zcAAAADAAAAAADb/zgAAAADAAAAAADb/zkAAAADAAAAAADb/zoAAAADAAAAAADb/zsAAAADAAAAAADb/zwAAAADAAAAAADb/z0AAAADAAAAAADb/z4AAAADAAAAAADb/z8AAAADAAAAAADc/y0AAAADAAAAAADc/y4AAAADAAAAAADc/y8AAAADAAAAAADc/zAAAAADAAAAAADc/zEAAAADAAAAAADc/zIAAAADAAAAAADc/zMAAAADAAAAAADc/zQAAAADAAAAAADc/zUAAAADAAAAAADc/zYAAAADAAAAAADc/zcAAAADAAAAAADc/zgAAAADAAAAAADc/zkAAAADAAAAAADc/zoAAAADAAAAAADc/zsAAAADAAAAAADc/zwAAAADAAAAAADc/z0AAAADAAAAAADc/z4AAAADAAAAAADc/z8AAAADAAAAAADd/y0AAAADAAAAAADd/y4AAAADAAAAAADd/y8AAAADAAAAAADd/zAAAAADAAAAAADd/zEAAAADAAAAAADd/zIAAAADAAAAAADd/zMAAAADAAAAAADd/zQAAAADAAAAAADd/zUAAAADAAAAAADd/zYAAAADAAAAAADd/zcAAAADAAAAAADd/zgAAAADAAAAAADd/zkAAAADAAAAAADd/zoAAAADAAAAAADd/zsAAAADAAAAAADd/zwAAAADAAAAAADd/z0AAAADAAAAAADd/z4AAAADAAAAAADd/z8AAAADAAAAAACw/zUAAAADAAAAAACw/zYAAAADAAAAAACw/zcAAAADAAAAAACw/zgAAAADAAAAAACw/zkAAAADAAAAAACw/zoAAAADAAAAAACx/zUAAAADAAAAAACx/zYAAAADAAAAAACx/zcAAAADAAAAAACx/zgAAAADAAAAAACx/zkAAAADAAAAAACx/zoAAAADAAAAAACy/zUAAAADAAAAAACy/zYAAAADAAAAAACy/zcAAAADAAAAAACy/zgAAAADAAAAAACy/zkAAAADAAAAAACy/zoAAAADAAAAAACz/zUAAAADAAAAAACz/zYAAAADAAAAAACz/zcAAAADAAAAAACz/zgAAAADAAAAAACz/zkAAAADAAAAAACz/zoAAAADAAAAAAC0/zUAAAADAAAAAAC0/zYAAAADAAAAAAC0/zcAAAADAAAAAAC0/zgAAAADAAAAAAC0/zkAAAADAAAAAAC0/zoAAAADAAAAAAC1/zUAAAADAAAAAAC1/zYAAAADAAAAAAC1/zcAAAADAAAAAAC1/zgAAAADAAAAAAC1/zkAAAADAAAAAAC1/zoAAAADAAAAAAC2/zUAAAADAAAAAAC2/zYAAAADAAAAAAC2/zcAAAADAAAAAAC2/zgAAAADAAAAAAC2/zkAAAADAAAAAAC2/zoAAAADAAAAAAC3/zUAAAADAAAAAAC3/zYAAAADAAAAAAC3/zcAAAADAAAAAAC3/zgAAAADAAAAAAC3/zkAAAADAAAAAAC3/zoAAAADAAAAAAC4/zUAAAADAAAAAAC4/zYAAAADAAAAAAC4/zcAAAADAAAAAAC4/zgAAAADAAAAAAC4/zkAAAADAAAAAAC4/zoAAAADAAAAAAC5/zUAAAADAAAAAAC5/zYAAAADAAAAAAC5/zcAAAADAAAAAAC5/zgAAAADAAAAAAC5/zkAAAADAAAAAAC5/zoAAAADAAAAAAC6/zUAAAADAAAAAAC6/zYAAAADAAAAAAC6/zcAAAADAAAAAAC6/zgAAAADAAAAAAC6/zkAAAADAAAAAAC6/zoAAAADAAAAAAC7/zUAAAADAAAAAAC7/zYAAAADAAAAAAC7/zcAAAADAAAAAAC7/zgAAAADAAAAAAC7/zkAAAADAAAAAAC7/zoAAAADAAAAAAC8/zUAAAADAAAAAAC8/zYAAAADAAAAAAC8/zcAAAADAAAAAAC8/zgAAAADAAAAAAC8/zkAAAADAAAAAAC8/zoAAAADAAAAAAC9/zUAAAADAAAAAAC9/zYAAAADAAAAAAC9/zcAAAADAAAAAAC9/zgAAAADAAAAAAC9/zkAAAADAAAAAAC9/zoAAAADAAAAAAC+/zUAAAADAAAAAAC+/zYAAAADAAAAAAC+/zcAAAADAAAAAAC+/zgAAAADAAAAAAC+/zkAAAADAAAAAAC+/zoAAAADAAAAAAC//zUAAAADAAAAAAC//zYAAAADAAAAAAC//zcAAAADAAAAAAC//zgAAAADAAAAAAC//zkAAAADAAAAAAC//zoAAAADAAAAAADA/zUAAAADAAAAAADA/zYAAAADAAAAAADA/zcAAAADAAAAAADA/zgAAAADAAAAAADA/zkAAAADAAAAAADA/zoAAAADAAAAAADB/zUAAAADAAAAAADB/zYAAAADAAAAAADB/zcAAAADAAAAAADB/zgAAAADAAAAAADB/zkAAAADAAAAAADB/zoAAAADAAAAAADC/zUAAAADAAAAAADC/zYAAAADAAAAAADC/zcAAAADAAAAAADC/zgAAAADAAAAAADC/zkAAAADAAAAAADC/zoAAAADAAAAAADD/zUAAAADAAAAAADD/zYAAAADAAAAAADD/zcAAAADAAAAAADD/zgAAAADAAAAAADD/zkAAAADAAAAAADD/zoAAAADAAAAAADE/zUAAAADAAAAAADE/zYAAAADAAAAAADE/zcAAAADAAAAAADE/zgAAAADAAAAAADE/zkAAAADAAAAAADE/zoAAAADAAAAAADF/zUAAAADAAAAAADF/zYAAAADAAAAAADF/zcAAAADAAAAAADF/zgAAAADAAAAAADF/zkAAAADAAAAAADF/zoAAAADAAAAAADG/zUAAAADAAAAAADG/zYAAAADAAAAAADG/zcAAAADAAAAAADG/zgAAAADAAAAAADG/zkAAAADAAAAAADG/zoAAAADAAAAAADH/zUAAAADAAAAAADH/zYAAAADAAAAAADH/zcAAAADAAAAAADH/zgAAAADAAAAAADH/zkAAAADAAAAAADH/zoAAAADAAAAAADI/zUAAAADAAAAAADI/zYAAAADAAAAAADI/zcAAAADAAAAAADI/zgAAAADAAAAAADI/zkAAAADAAAAAADI/zoAAAADAAAAAADJ/zUAAAADAAAAAADJ/zYAAAADAAAAAADJ/zcAAAADAAAAAADJ/zgAAAADAAAAAADJ/zkAAAADAAAAAADJ/zoAAAADAAAAAADK/zUAAAADAAAAAADK/zYAAAADAAAAAADK/zcAAAADAAAAAADK/zgAAAADAAAAAADK/zkAAAADAAAAAADK/zoAAAADAAAAAADL/zUAAAADAAAAAADL/zYAAAADAAAAAADL/zcAAAADAAAAAADL/zgAAAADAAAAAADL/zkAAAADAAAAAADL/zoAAAADAAAAAADM/zUAAAADAAAAAADM/zYAAAADAAAAAADM/zcAAAADAAAAAADM/zgAAAADAAAAAADM/zkAAAADAAAAAADM/zoAAAADAAAAAADN/zUAAAADAAAAAADN/zYAAAADAAAAAADN/zcAAAADAAAAAADN/zgAAAADAAAAAADN/zkAAAADAAAAAADN/zoAAAADAAAAAADI/yQAAAADAAAAAADI/yUAAAADAAAAAADI/yYAAAADAAAAAADI/ycAAAADAAAAAADI/ygAAAADAAAAAADI/ykAAAADAAAAAADI/yoAAAADAAAAAADI/ysAAAADAAAAAADI/ywAAAADAAAAAADI/y0AAAADAAAAAADI/y4AAAADAAAAAADI/y8AAAADAAAAAADI/zAAAAADAAAAAADI/zEAAAADAAAAAADI/zIAAAADAAAAAADI/zMAAAADAAAAAADI/zQAAAADAAAAAADJ/yQAAAADAAAAAADJ/yUAAAADAAAAAADJ/yYAAAADAAAAAADJ/ycAAAADAAAAAADJ/ygAAAADAAAAAADJ/ykAAAADAAAAAADJ/yoAAAADAAAAAADJ/ysAAAADAAAAAADJ/ywAAAADAAAAAADJ/y0AAAADAAAAAADJ/y4AAAADAAAAAADJ/y8AAAADAAAAAADJ/zAAAAADAAAAAADJ/zEAAAADAAAAAADJ/zIAAAADAAAAAADJ/zMAAAADAAAAAADJ/zQAAAADAAAAAADK/yQAAAADAAAAAADK/yUAAAADAAAAAADK/yYAAAADAAAAAADK/ycAAAADAAAAAADK/ygAAAADAAAAAADK/ykAAAADAAAAAADK/yoAAAADAAAAAADK/ysAAAADAAAAAADK/ywAAAADAAAAAADK/y0AAAADAAAAAADK/y4AAAADAAAAAADK/y8AAAADAAAAAADK/zAAAAADAAAAAADK/zEAAAADAAAAAADK/zIAAAADAAAAAADK/zMAAAADAAAAAADK/zQAAAADAAAAAADL/yQAAAADAAAAAADL/yUAAAADAAAAAADL/yYAAAADAAAAAADL/ycAAAADAAAAAADL/ygAAAADAAAAAADL/ykAAAADAAAAAADL/yoAAAADAAAAAADL/ysAAAADAAAAAADL/ywAAAADAAAAAADL/y0AAAADAAAAAADL/y4AAAADAAAAAADL/y8AAAADAAAAAADL/zAAAAADAAAAAADL/zEAAAADAAAAAADL/zIAAAADAAAAAADL/zMAAAADAAAAAADL/zQAAAADAAAAAADM/yQAAAADAAAAAADM/yUAAAADAAAAAADM/yYAAAADAAAAAADM/ycAAAADAAAAAADM/ygAAAADAAAAAADM/ykAAAADAAAAAADM/yoAAAADAAAAAADM/ysAAAADAAAAAADM/ywAAAADAAAAAADM/y0AAAADAAAAAADM/y4AAAADAAAAAADM/y8AAAADAAAAAADM/zAAAAADAAAAAADM/zEAAAADAAAAAADM/zIAAAADAAAAAADM/zMAAAADAAAAAADM/zQAAAADAAAAAADN/yQAAAADAAAAAADN/yUAAAADAAAAAADN/yYAAAADAAAAAADN/ycAAAADAAAAAADN/ygAAAADAAAAAADN/ykAAAADAAAAAADN/yoAAAADAAAAAADN/ysAAAADAAAAAADN/ywAAAADAAAAAADN/y0AAAADAAAAAADN/y4AAAADAAAAAADN/y8AAAADAAAAAADN/zAAAAADAAAAAADN/zEAAAADAAAAAADN/zIAAAADAAAAAADN/zMAAAADAAAAAADN/zQAAAADAAAAAACr/yUAAAADAAAAAACr/yYAAAADAAAAAACr/ycAAAADAAAAAACr/ygAAAADAAAAAACr/ykAAAADAAAAAACr/yoAAAADAAAAAACs/yUAAAADAAAAAACs/yYAAAADAAAAAACs/ycAAAADAAAAAACs/ygAAAADAAAAAACs/ykAAAADAAAAAACs/yoAAAADAAAAAACt/yUAAAADAAAAAACt/yYAAAADAAAAAACt/ycAAAADAAAAAACt/ygAAAADAAAAAACt/ykAAAADAAAAAACt/yoAAAADAAAAAACu/yUAAAADAAAAAACu/yYAAAADAAAAAACu/ycAAAADAAAAAACu/ygAAAADAAAAAACu/ykAAAADAAAAAACu/yoAAAADAAAAAACv/yUAAAADAAAAAACv/yYAAAADAAAAAACv/ycAAAADAAAAAACv/ygAAAADAAAAAACv/ykAAAADAAAAAACv/yoAAAADAAAAAACw/yUAAAADAAAAAACw/yYAAAADAAAAAACw/ycAAAADAAAAAACw/ygAAAADAAAAAACw/ykAAAADAAAAAACw/yoAAAADAAAAAACx/yUAAAADAAAAAACx/yYAAAADAAAAAACx/ycAAAADAAAAAACx/ygAAAADAAAAAACx/ykAAAADAAAAAACx/yoAAAADAAAAAACy/yUAAAADAAAAAACy/yYAAAADAAAAAACy/ycAAAADAAAAAACy/ygAAAADAAAAAACy/ykAAAADAAAAAACy/yoAAAADAAAAAACz/yUAAAADAAAAAACz/yYAAAADAAAAAACz/ycAAAADAAAAAACz/ygAAAADAAAAAACz/ykAAAADAAAAAACz/yoAAAADAAAAAAC0/yUAAAADAAAAAAC0/yYAAAADAAAAAAC0/ycAAAADAAAAAAC0/ygAAAADAAAAAAC0/ykAAAADAAAAAAC0/yoAAAADAAAAAAC1/yUAAAADAAAAAAC1/yYAAAADAAAAAAC1/ycAAAADAAAAAAC1/ygAAAADAAAAAAC1/ykAAAADAAAAAAC1/yoAAAADAAAAAAC2/yUAAAADAAAAAAC2/yYAAAADAAAAAAC2/ycAAAADAAAAAAC2/ygAAAADAAAAAAC2/ykAAAADAAAAAAC2/yoAAAADAAAAAAC3/yUAAAADAAAAAAC3/yYAAAADAAAAAAC3/ycAAAADAAAAAAC3/ygAAAADAAAAAAC3/ykAAAADAAAAAAC3/yoAAAADAAAAAAC4/yUAAAADAAAAAAC4/yYAAAADAAAAAAC4/ycAAAADAAAAAAC4/ygAAAADAAAAAAC4/ykAAAADAAAAAAC4/yoAAAADAAAAAAC5/yUAAAADAAAAAAC5/yYAAAADAAAAAAC5/ycAAAADAAAAAAC5/ygAAAADAAAAAAC5/ykAAAADAAAAAAC5/yoAAAADAAAAAAC6/yUAAAADAAAAAAC6/yYAAAADAAAAAAC6/ycAAAADAAAAAAC6/ygAAAADAAAAAAC6/ykAAAADAAAAAAC6/yoAAAADAAAAAAC7/yUAAAADAAAAAAC7/yYAAAADAAAAAAC7/ycAAAADAAAAAAC7/ygAAAADAAAAAAC7/ykAAAADAAAAAAC7/yoAAAADAAAAAAC8/yUAAAADAAAAAAC8/yYAAAADAAAAAAC8/ycAAAADAAAAAAC8/ygAAAADAAAAAAC8/ykAAAADAAAAAAC8/yoAAAADAAAAAAC9/yUAAAADAAAAAAC9/yYAAAADAAAAAAC9/ycAAAADAAAAAAC9/ygAAAADAAAAAAC9/ykAAAADAAAAAAC9/yoAAAADAAAAAAA=\")\nplayer_id = 7\n\n[node name=\"GroundIndicatorMap\" type=\"TileMap\" parent=\".\"]\nvisible = false\ny_sort_enabled = true\ntile_set = SubResource(\"TileSet_dc62b\")\nformat = 2\nlayer_0/modulate = Color(1, 0, 1, 0.392157)\nlayer_0/y_sort_enabled = true\nlayer_0/z_index = 100\nlayer_0/tile_data = PackedInt32Array(-2359305, 1, 0, -2293769, 1, 0, -2228233, 1, 0, -2162697, 1, 0, -2097161, 1, 0, -2031625, 1, 0, -1966089, 1, 0, -2293770, 1, 0, -2228234, 1, 0, -2228235, 1, 0, -2162699, 1, 0, -2097163, 1, 0, -2031627, 1, 0, -1966091, 1, 0, -1900555, 1, 0, -1835019, 1, 0, -1769483, 1, 0, -1703947, 1, 0, -1638411, 1, 0, -1572875, 1, 0, -1507339, 1, 0, -1441803, 1, 0, -1376267, 1, 0, -1310731, 1, 0, -1245195, 1, 0, -1179659, 1, 0, -1114123, 1, 0, -1048587, 1, 0, -983051, 1, 0, -917515, 1, 0, -851979, 1, 0, -786443, 1, 0, -720907, 1, 0, -655371, 1, 0, -589835, 1, 0, -524299, 1, 0, -458763, 1, 0, -393227, 1, 0, -327691, 1, 0, -262155, 1, 0, -196619, 1, 0, -2162698, 1, 0, -2097162, 1, 0, -2031626, 1, 0, -1966090, 1, 0, -1900554, 1, 0, -1835018, 1, 0, -1769482, 1, 0, -1703946, 1, 0, -1638410, 1, 0, -1572874, 1, 0, -1507338, 1, 0, -1441802, 1, 0, -1376266, 1, 0, -1310730, 1, 0, -1245194, 1, 0, -1179658, 1, 0, -1114122, 1, 0, -1048586, 1, 0, -983050, 1, 0, -917514, 1, 0, -851978, 1, 0, -786442, 1, 0, -720906, 1, 0, -655370, 1, 0, -589834, 1, 0, -524298, 1, 0, -458762, 1, 0, -393226, 1, 0, -327690, 1, 0, -262154, 1, 0, -196618, 1, 0, -1900553, 1, 0, -1835017, 1, 0, -1769481, 1, 0, -1703945, 1, 0, -1638409, 1, 0, -1572873, 1, 0, -1507337, 1, 0, -1441801, 1, 0, -1376265, 1, 0, -1310729, 1, 0, -1245193, 1, 0, -1179657, 1, 0, -1114121, 1, 0, -1048585, 1, 0, -983049, 1, 0, -917513, 1, 0, -851977, 1, 0, -786441, 1, 0, -720905, 1, 0, -655369, 1, 0, -589833, 1, 0, -524297, 1, 0, -458761, 1, 0, -393225, 1, 0, -327689, 1, 0, -262153, 1, 0, -196617, 1, 0, -327688, 1, 0, -262152, 1, 0, -196616, 1, 0, -327687, 1, 0, -262151, 1, 0, -196615, 1, 0, -327686, 1, 0, -262150, 1, 0, -196614, 1, 0, -327685, 1, 0, -262149, 1, 0, -196613, 1, 0, -327684, 1, 0, -262148, 1, 0, -196612, 1, 0, -327683, 1, 0, -262147, 1, 0, -196611, 1, 0, -327682, 1, 0, -262146, 1, 0, -196610, 1, 0, -327681, 1, 0, -262145, 1, 0, -196609, 1, 0, -1179651, 1, 0, -1114115, 1, 0, -1048579, 1, 0, -983043, 1, 0, -917507, 1, 0, -851971, 1, 0, -786435, 1, 0, -720899, 1, 0, -655363, 1, 0, -589827, 1, 0, -524291, 1, 0, -458755, 1, 0, -393219, 1, 0, -1179650, 1, 0, -1114114, 1, 0, -1048578, 1, 0, -983042, 1, 0, -917506, 1, 0, -851970, 1, 0, -786434, 1, 0, -720898, 1, 0, -655362, 1, 0, -589826, 1, 0, -524290, 1, 0, -458754, 1, 0, -393218, 1, 0, -1179649, 1, 0, -1114113, 1, 0, -1048577, 1, 0, -983041, 1, 0, -917505, 1, 0, -851969, 1, 0, -786433, 1, 0, -720897, 1, 0, -655361, 1, 0, -589825, 1, 0, -524289, 1, 0, -458753, 1, 0, -393217, 1, 0, -1245184, 1, 0, -1179648, 1, 0, -1114112, 1, 0, -1245183, 1, 0, -1179647, 1, 0, -1114111, 1, 0, -1245182, 1, 0, -1179646, 1, 0, -1114110, 1, 0, -1245181, 1, 0, -1179645, 1, 0, -1114109, 1, 0, -1245180, 1, 0, -1179644, 1, 0, -1114108, 1, 0, -1245179, 1, 0, -1179643, 1, 0, -1114107, 1, 0, -1245178, 1, 0, -1179642, 1, 0, -1114106, 1, 0, -1245177, 1, 0, -1179641, 1, 0, -1114105, 1, 0, -1048571, 1, 0, -983035, 1, 0, -917499, 1, 0, -851963, 1, 0, -786427, 1, 0, -720891, 1, 0, -655355, 1, 0, -589819, 1, 0, -524283, 1, 0, -458747, 1, 0, -393211, 1, 0, -327675, 1, 0, -262139, 1, 0, -196603, 1, 0, -131067, 1, 0, -65531, 1, 0, -1048570, 1, 0, -983034, 1, 0, -917498, 1, 0, -851962, 1, 0, -786426, 1, 0, -720890, 1, 0, -655354, 1, 0, -589818, 1, 0, -524282, 1, 0, -458746, 1, 0, -393210, 1, 0, -327674, 1, 0, -262138, 1, 0, -196602, 1, 0, -131066, 1, 0, -65530, 1, 0, -1048569, 1, 0, -983033, 1, 0, -917497, 1, 0, -851961, 1, 0, -786425, 1, 0, -720889, 1, 0, -655353, 1, 0, -589817, 1, 0, -524281, 1, 0, -458745, 1, 0, -393209, 1, 0, -327673, 1, 0, -262137, 1, 0, -196601, 1, 0, -131065, 1, 0, -65529, 1, 0, 5, 1, 0, 65541, 1, 0, 131077, 1, 0, 196613, 1, 0, 262149, 1, 0, 6, 1, 0, 65542, 1, 0, 131078, 1, 0, 196614, 1, 0, 262150, 1, 0, 7, 1, 0, 65543, 1, 0, 131079, 1, 0, 196615, 1, 0, 262151, 1, 0, 262137, 1, 0, 327673, 1, 0, 262138, 1, 0, 327674, 1, 0, 262139, 1, 0, 327675, 1, 0, 262140, 1, 0, 327676, 1, 0, 262141, 1, 0, 327677, 1, 0, 262142, 1, 0, 327678, 1, 0, 262143, 1, 0, 327679, 1, 0, 196608, 1, 0, 262144, 1, 0, 196609, 1, 0, 262145, 1, 0, 196610, 1, 0, 262146, 1, 0, 196611, 1, 0, 262147, 1, 0, 196612, 1, 0, 262148, 1, 0, 196601, 1, 0, 196602, 1, 0, 196603, 1, 0, 196604, 1, 0, 196605, 1, 0, 196606, 1, 0, 196607, 1, 0, 131072, 1, 0, 131073, 1, 0, 131074, 1, 0, 131075, 1, 0, 131076, 1, 0, 393209, 1, 0, 458745, 1, 0, 524281, 1, 0, 589817, 1, 0, 655353, 1, 0, 720889, 1, 0, 786425, 1, 0, 851961, 1, 0, 393210, 1, 0, 458746, 1, 0, 524282, 1, 0, 589818, 1, 0, 655354, 1, 0, 720890, 1, 0, 786426, 1, 0, 851962, 1, 0, 393211, 1, 0, 458747, 1, 0, 524283, 1, 0, 589819, 1, 0, 655355, 1, 0, 720891, 1, 0, 786427, 1, 0, 851963, 1, 0, 720892, 1, 0, 786428, 1, 0, 851964, 1, 0, 720893, 1, 0, 786429, 1, 0, 851965, 1, 0, 720894, 1, 0, 786430, 1, 0, 851966, 1, 0, 720895, 1, 0, 786431, 1, 0, 851967, 1, 0, 655360, 1, 0, 720896, 1, 0, 786432, 1, 0, 655361, 1, 0, 720897, 1, 0, 786433, 1, 0, 655362, 1, 0, 720898, 1, 0, 786434, 1, 0, 655363, 1, 0, 720899, 1, 0, 786435, 1, 0, 655364, 1, 0, 720900, 1, 0, 786436, 1, 0, 655365, 1, 0, 720901, 1, 0, 786437, 1, 0, 655366, 1, 0, 720902, 1, 0, 786438, 1, 0, 655367, 1, 0, 720903, 1, 0, 786439, 1, 0, 851973, 1, 0, 917509, 1, 0, 983045, 1, 0, 1048581, 1, 0, 1114117, 1, 0, 1179653, 1, 0, 1245189, 1, 0, 1310725, 1, 0, 1376261, 1, 0, 1441797, 1, 0, 1507333, 1, 0, 1572869, 1, 0, 1638405, 1, 0, 1703941, 1, 0, 1769477, 1, 0, 1835013, 1, 0, 1900549, 1, 0, 1966085, 1, 0, 2031621, 1, 0, 2097157, 1, 0, 2162693, 1, 0, 851974, 1, 0, 917510, 1, 0, 983046, 1, 0, 1048582, 1, 0, 1114118, 1, 0, 1179654, 1, 0, 1245190, 1, 0, 1310726, 1, 0, 1376262, 1, 0, 1441798, 1, 0, 1507334, 1, 0, 1572870, 1, 0, 1638406, 1, 0, 1703942, 1, 0, 1769478, 1, 0, 1835014, 1, 0, 1900550, 1, 0, 1966086, 1, 0, 2031622, 1, 0, 2097158, 1, 0, 2162694, 1, 0, 851975, 1, 0, 917511, 1, 0, 983047, 1, 0, 1048583, 1, 0, 1114119, 1, 0, 1179655, 1, 0, 1245191, 1, 0, 1310727, 1, 0, 1376263, 1, 0, 1441799, 1, 0, 1507335, 1, 0, 1572871, 1, 0, 1638407, 1, 0, 1703943, 1, 0, 1769479, 1, 0, 1835015, 1, 0, 1900551, 1, 0, 1966087, 1, 0, 2031623, 1, 0, 2097159, 1, 0, 2162695, 1, 0, -1245176, 1, 0, -1179640, 1, 0, -1114104, 1, 0, -1245175, 1, 0, -1179639, 1, 0, -1114103, 1, 0, -1245174, 1, 0, -1179638, 1, 0, -1114102, 1, 0, -1245173, 1, 0, -1179637, 1, 0, -1114101, 1, 0, -1245172, 1, 0, -1179636, 1, 0, -1114100, 1, 0, -1245171, 1, 0, -1179635, 1, 0, -1114099, 1, 0, -1245170, 1, 0, -1179634, 1, 0, -1114098, 1, 0, -1245169, 1, 0, -1179633, 1, 0, -1114097, 1, 0, -1048563, 1, 0, -983027, 1, 0, -917491, 1, 0, -851955, 1, 0, -786419, 1, 0, -720883, 1, 0, -655347, 1, 0, -589811, 1, 0, -524275, 1, 0, -458739, 1, 0, -393203, 1, 0, -327667, 1, 0, -262131, 1, 0, -1048562, 1, 0, -983026, 1, 0, -917490, 1, 0, -851954, 1, 0, -786418, 1, 0, -720882, 1, 0, -655346, 1, 0, -589810, 1, 0, -524274, 1, 0, -458738, 1, 0, -393202, 1, 0, -327666, 1, 0, -262130, 1, 0, -1048561, 1, 0, -983025, 1, 0, -917489, 1, 0, -851953, 1, 0, -786417, 1, 0, -720881, 1, 0, -655345, 1, 0, -589809, 1, 0, -524273, 1, 0, -458737, 1, 0, -393201, 1, 0, -327665, 1, 0, -262129, 1, 0, -393200, 1, 0, -327664, 1, 0, -262128, 1, 0, -393199, 1, 0, -327663, 1, 0, -262127, 1, 0, -393198, 1, 0, -327662, 1, 0, -262126, 1, 0, -393197, 1, 0, -327661, 1, 0, -262125, 1, 0, -393196, 1, 0, -327660, 1, 0, -262124, 1, 0, -458731, 1, 0, -393195, 1, 0, -327659, 1, 0, -262123, 1, 0, -458730, 1, 0, -393194, 1, 0, -327658, 1, 0, -262122, 1, 0, -458729, 1, 0, -393193, 1, 0, -327657, 1, 0, -262121, 1, 0, -1638379, 1, 0, -1572843, 1, 0, -1507307, 1, 0, -1441771, 1, 0, -1376235, 1, 0, -1310699, 1, 0, -1245163, 1, 0, -1179627, 1, 0, -1114091, 1, 0, -1048555, 1, 0, -983019, 1, 0, -917483, 1, 0, -851947, 1, 0, -786411, 1, 0, -720875, 1, 0, -655339, 1, 0, -589803, 1, 0, -524267, 1, 0, -1638378, 1, 0, -1572842, 1, 0, -1507306, 1, 0, -1441770, 1, 0, -1376234, 1, 0, -1310698, 1, 0, -1245162, 1, 0, -1179626, 1, 0, -1114090, 1, 0, -1048554, 1, 0, -983018, 1, 0, -917482, 1, 0, -851946, 1, 0, -786410, 1, 0, -720874, 1, 0, -655338, 1, 0, -589802, 1, 0, -524266, 1, 0, -1638377, 1, 0, -1572841, 1, 0, -1507305, 1, 0, -1441769, 1, 0, -1376233, 1, 0, -1310697, 1, 0, -1245161, 1, 0, -1179625, 1, 0, -1114089, 1, 0, -1048553, 1, 0, -983017, 1, 0, -917481, 1, 0, -851945, 1, 0, -786409, 1, 0, -720873, 1, 0, -655337, 1, 0, -589801, 1, 0, -524265, 1, 0, -2424811, 1, 0, -2359275, 1, 0, -2293739, 1, 0, -2228203, 1, 0, -2162667, 1, 0, -2097131, 1, 0, -2031595, 1, 0, -1966059, 1, 0, -1900523, 1, 0, -1834987, 1, 0, -1769451, 1, 0, -1703915, 1, 0, -2424810, 1, 0, -2359274, 1, 0, -2293738, 1, 0, -2228202, 1, 0, -2162666, 1, 0, -2097130, 1, 0, -2031594, 1, 0, -1966058, 1, 0, -1900522, 1, 0, -1834986, 1, 0, -1769450, 1, 0, -1703914, 1, 0, -2424809, 1, 0, -2359273, 1, 0, -2293737, 1, 0, -2228201, 1, 0, -2162665, 1, 0, -2097129, 1, 0, -2031593, 1, 0, -1966057, 1, 0, -1900521, 1, 0, -1834985, 1, 0, -1769449, 1, 0, -1703913, 1, 0, -2490347, 1, 0, -2490346, 1, 0, -2490345, 1, 0, 131080, 1, 0, 196616, 1, 0, 262152, 1, 0, 131081, 1, 0, 196617, 1, 0, 262153, 1, 0, 131082, 1, 0, 196618, 1, 0, 262154, 1, 0, 131083, 1, 0, 196619, 1, 0, 262155, 1, 0, 131084, 1, 0, 196620, 1, 0, 262156, 1, 0, 131085, 1, 0, 196621, 1, 0, 262157, 1, 0, 131086, 1, 0, 196622, 1, 0, 262158, 1, 0, 131087, 1, 0, 196623, 1, 0, 262159, 1, 0, 131088, 1, 0, 196624, 1, 0, 262160, 1, 0, 131089, 1, 0, 196625, 1, 0, 262161, 1, 0, 131090, 1, 0, 196626, 1, 0, 262162, 1, 0, 131091, 1, 0, 196627, 1, 0, 262163, 1, 0, 655376, 1, 0, 720912, 1, 0, 786448, 1, 0, 327697, 1, 0, 393233, 1, 0, 458769, 1, 0, 524305, 1, 0, 589841, 1, 0, 655377, 1, 0, 720913, 1, 0, 786449, 1, 0, 327698, 1, 0, 393234, 1, 0, 458770, 1, 0, 524306, 1, 0, 589842, 1, 0, 655378, 1, 0, 720914, 1, 0, 786450, 1, 0, 327699, 1, 0, 393235, 1, 0, 458771, 1, 0, 524307, 1, 0, 589843, 1, 0, 655379, 1, 0, 720915, 1, 0, 786451, 1, 0, 655368, 1, 0, 720904, 1, 0, 786440, 1, 0, 655369, 1, 0, 720905, 1, 0, 786441, 1, 0, 655370, 1, 0, 720906, 1, 0, 786442, 1, 0, 655371, 1, 0, 720907, 1, 0, 786443, 1, 0, 655372, 1, 0, 720908, 1, 0, 786444, 1, 0, 655373, 1, 0, 720909, 1, 0, 786445, 1, 0, 655374, 1, 0, 720910, 1, 0, 786446, 1, 0, 655375, 1, 0, 720911, 1, 0, 786447, 1, 0)\n\n[node name=\"MapBorderPoly\" type=\"Polygon2D\" parent=\".\"]\nmodulate = Color(0, 0, 0, 0.560784)\nz_index = 999\npolygon = PackedVector2Array(7000, 4000, 7000, -3000, -5000, -3000, -5000, 4000, -4000, 4000, -4000, -2000, 6000, -2000, 6000, 3000, -4000, 3000, -4000, 4000)\n\n[node name=\"CameraLimits\" type=\"Polygon2D\" parent=\".\"]\nvisible = false\nz_index = 999\ncolor = Color(0, 1, 0, 0.196078)\npolygon = PackedVector2Array(-4800, -2800, 6700, -2800, 6700, 3800, -4800, 3800)\n"
  },
  {
    "path": "src/missions/instances/mission_120_in_60min.gd",
    "content": "extends Mission\n\n\nfunc process_game_win() -> bool:\n\tvar time: float = Utils.get_time()\n\tvar completed: bool = time < 60 * 60\n\n\treturn completed\n"
  },
  {
    "path": "src/missions/instances/mission_240_in_120min.gd",
    "content": "extends Mission\n\n\nfunc process_game_win() -> bool:\n\tvar time: float = Utils.get_time()\n\tvar completed: bool = time < 120 * 60\n\n\treturn completed\n"
  },
  {
    "path": "src/missions/instances/mission_35_food_or_less.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar food: int = local_player.get_food()\n\tvar food_ok: int = food <= 35\n\t\n\tif !food_ok:\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_empty.gd",
    "content": "extends Mission\n\n\n# NOTE: this script is used for missions without any script logic\n"
  },
  {
    "path": "src/missions/instances/mission_no_items.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tvar tower_list: Array = Utils.get_tower_list()\n\t\n\tfor tower in tower_list:\n\t\tvar item_list: Array = tower.get_items()\n\t\tvar tower_has_items: bool = item_list.size() > 0\n\t\t\n\t\tif tower_has_items:\n\t\t\tmission_failed()\n\t\t\t\n\t\t\treturn\n"
  },
  {
    "path": "src/missions/instances/mission_no_oils.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tvar tower_list: Array = Utils.get_tower_list()\n\t\n\tfor tower in tower_list:\n\t\tvar oil_list: Array = tower.get_oils()\n\t\tvar tower_has_oils: bool = oil_list.size() > 0\n\t\t\n\t\tif tower_has_oils:\n\t\t\tmission_failed()\n\t\t\t\n\t\t\treturn\n"
  },
  {
    "path": "src/missions/instances/mission_only_astral_towers.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.ASTRAL):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_only_common_uncommon.gd",
    "content": "extends Mission\n\n\nconst VALID_RARITY_LIST: Array = [Rarity.enm.COMMON, Rarity.enm.UNCOMMON]\n\n\nfunc check_for_fail():\n\tvar tower_list: Array = Utils.get_tower_list()\n\t\n\tfor tower in tower_list:\n\t\tvar rarity: Rarity.enm = tower.get_rarity()\n\t\tvar rarity_match: bool = VALID_RARITY_LIST.has(rarity)\n\t\t\n\t\tif !rarity_match:\n\t\t\tmission_failed()\n\t\t\t\n\t\t\treturn\n"
  },
  {
    "path": "src/missions/instances/mission_only_darkness_towers.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.DARKNESS):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_only_fire_towers.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.FIRE):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_only_ice_towers.gd",
    "content": "class_name MissionOnlyIceTowers extends Mission\n\n\nstatic func check_for_element_fail(target_element: Element.enm) -> bool:\n\tvar tower_list: Array = Utils.get_tower_list()\n\t\n\tfor tower in tower_list:\n\t\tvar element: Element.enm = tower.get_element()\n\t\tvar element_match: bool = element == target_element\n\t\t\n\t\tif !element_match:\n\t\t\treturn false\n\t\n\treturn true\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.ICE):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_only_iron_towers.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.IRON):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_only_nature_towers.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.NATURE):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/instances/mission_only_storm_towers.gd",
    "content": "extends Mission\n\n\nfunc check_for_fail():\n\tif !MissionOnlyIceTowers.check_for_element_fail(Element.enm.STORM):\n\t\tmission_failed()\n"
  },
  {
    "path": "src/missions/mission.gd",
    "content": "class_name Mission extends Node\n\n\nsignal was_failed()\n\n\nvar _id: int\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(id: int):\n\t_id = id\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id() -> int:\n\treturn _id\n\n\n# This f-n gets called periodically to check for fail conditions.\n# Override in subclass to implement mission logic.\nfunc check_for_fail():\n\tpass\n\n\n# Override this f-n in subclasses to implement mission\n# reaction to game finish. Return true if mission was\n# completed, false if failed.\nfunc process_game_win() -> bool:\n\treturn true\n\n\n# Call in subclass to declare that mission was failed\nfunc mission_failed():\n\twas_failed.emit()\n"
  },
  {
    "path": "src/missions/mission_manager.gd",
    "content": "class_name MissionManager extends Node\n\n\n# Manages mission state during a match.\n\nvar _mission_list: Array[Mission] = []\n\n@export var _hud: HUD\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready() -> void:\n\tEventBus.player_selected_builder.connect(_on_player_selected_builder)\n\tPlayerManager.players_created.connect(_on_players_created)\n\n#\tNOTE: missions are only for singleplayer so exit early\n# \tif not in singleplayer\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tif player_mode != PlayerMode.enm.SINGLEPLAYER:\n\t\treturn\n\n\tvar id_list: Array = MissionProperties.get_id_list()\n\t\n\tfor id in id_list:\n\t\tvar already_completed: bool = MissionStatus.get_mission_is_complete(id)\n\t\tif already_completed:\n\t\t\tcontinue\n\t\t\n\t\tvar mission_script_path: String = MissionProperties.get_script_path(id)\n\t\tvar mission_script: Script = load(mission_script_path)\n\t\t\n\t\tvar mission: Mission = mission_script.new(id)\n\t\tmission.was_failed.connect(_on_mission_was_failed.bind(mission))\n\t\t_mission_list.append(mission)\n\t\tadd_child(mission)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _remove_mission(mission: Mission):\n\tvar mission_id: int = mission.get_id()\n\t_hud.set_mission_track_state(mission_id, MissionTrackIndicator.State.FAILED)\n\n\t_mission_list.erase(mission)\n\tremove_child(mission)\n\tmission.queue_free()\n\n\nfunc _mission_requirements_are_satisfied(mission_id) -> bool:\n\tvar required_wave_count: int = MissionProperties.get_wave_count(mission_id)\n\tvar required_game_mode: GameMode.enm = MissionProperties.get_game_mode(mission_id)\n\tvar required_difficulty: Difficulty.enm = MissionProperties.get_difficulty(mission_id)\n\tvar required_builder_id: int = MissionProperties.get_builder(mission_id)\n\t\n\tvar wave_count: int = Globals.get_wave_count()\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar difficulty: Difficulty.enm = Globals.get_difficulty()\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar builder: Builder = local_player.get_builder()\n\tvar builder_id: int = builder.get_id()\n\n\tvar wave_count_match: bool = wave_count == required_wave_count\n\tvar game_mode_match: bool = game_mode == required_game_mode\n\tvar difficulty_match: bool = difficulty == required_difficulty\n\n\tvar required_builder_is_any: bool = required_builder_id == MissionProperties.BUILDER_ANY_ID\n\tvar builder_match: bool = required_builder_is_any || builder_id == required_builder_id\n\n\tvar all_match: bool = wave_count_match && game_mode_match && difficulty_match && builder_match\n\n\treturn all_match\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_players_created():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_team: Team = local_player.get_team()\n\t\n\tlocal_team.game_lose.connect(_on_game_lose)\n\tlocal_team.game_win.connect(_on_game_win)\n\n\n# Some missions should be removed at the start of the game\n# if incompatible game settings or builder are selected.\nfunc _on_player_selected_builder():\n\tvar removed_mission_list: Array = []\n\n\tfor mission in _mission_list:\n\t\tvar mission_id: int = mission.get_id()\n\t\tvar requirements_ok: bool = _mission_requirements_are_satisfied(mission_id)\n\n\t\tif !requirements_ok:\n\t\t\tremoved_mission_list.append(mission)\n\n\tfor mission in removed_mission_list:\n\t\t_remove_mission(mission)\n\n\nfunc _on_game_win():\n#\tNOTE: need to check missions for fail one last time\n#\tbefore processing game win because the fail check runs\n#\tperiodically and may have missed a fail condition which\n#\thappened since last check\n\t_check_missions_for_fail()\n\n\tfor mission in _mission_list:\n\t\tvar mission_was_completed: bool = mission.process_game_win()\n\n\t\tif mission_was_completed:\n\t\t\tvar mission_id: int = mission.get_id()\n\t\t\tvar mission_description: String = MissionProperties.get_description(mission_id)\n\t\t\t\n\t\t\t_hud.set_mission_track_state(mission_id, MissionTrackIndicator.State.COMPLETED)\n\n\t\t\tMissionStatus.set_mission_is_complete(mission_id, true)\n\t\t\tMessages.add_normal(null, tr(\"MESSAGE_MISSION_COMPLETED\").format({MISSION_DESCRIPTION = mission_description}))\n\t\t\tprint_verbose(\"Mission was completed: %s\" % mission_description)\n\n\n# All in progress missions are failed on game over\nfunc _on_game_lose():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar local_team: Team = local_player.get_team()\n\tvar current_wave: int = local_team.get_level()\n\tvar lost_on_bonus_waves: bool = current_wave > Constants.WAVE_COUNT_NEVERENDING\n\n\t# NOTE: game loss on bonus waves doesn't affect mission\n\t# status. This is to avoid scenarios like:\n\t#  \n\t# \"mission is completed at wave 240, then reverts to\n\t# failure when game ends at wave 260.\"\n\tif lost_on_bonus_waves:\n\t\treturn\n\n\tvar mission_list: Array = _mission_list.duplicate()\n\t\n\tfor mission in mission_list:\n\t\t_remove_mission(mission)\n\n\nfunc _on_mission_was_failed(mission: Mission):\n\tvar mission_id: int = mission.get_id()\n\tvar mission_description: String = MissionProperties.get_description(mission_id)\n\tprint_verbose(\"Mission was failed: %s\" % mission_description)\n\n#\tNOTE: since mission was failed, remove it to stop\n#\tprocessing it\n\t_remove_mission(mission)\n\n\n# NOTE: need to duplicate because _mission_list may get modified when mission is failed and gets removed from list\nfunc _on_fail_check_timer_timeout() -> void:\n\t_check_missions_for_fail()\n\n\nfunc _check_missions_for_fail():\n\tvar mission_list: Array = _mission_list.duplicate()\n\t\n\tfor mission in mission_list:\n\t\tmission.check_for_fail()\n\n\n# NOTE: need to check fails for tracked missions more often so that there's\n# not a large visual delay between doing a fail condition and tracking turning to FAILED\nfunc _on_fast_fail_check_timer_timeout():\n\tvar mission_list: Array = _mission_list.duplicate()\n\t\n\tvar tracked_mission_list: Array = []\n\t\n\tfor mission in mission_list:\n\t\tvar mission_id: int = mission.get_id()\n\t\tvar mission_is_tracked: bool = MissionTracking.get_mission_is_tracked(mission_id)\n\t\t\n\t\tif mission_is_tracked:\n\t\t\ttracked_mission_list.append(mission)\n\t\n\tfor mission in tracked_mission_list:\n\t\tmission.check_for_fail()\n\t\n"
  },
  {
    "path": "src/missions/mission_manager.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://u567sx64fpwa\"]\n\n[ext_resource type=\"Script\" path=\"res://src/missions/mission_manager.gd\" id=\"1_itmvt\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_6cnfp\"]\n\n[node name=\"MissionManager\" type=\"Node\"]\nscript = ExtResource(\"1_itmvt\")\n\n[node name=\"FailCheckTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_6cnfp\")\nwait_time = 10.0\nautostart = true\n\n[node name=\"FastFailCheckTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_6cnfp\")\nautostart = true\n\n[connection signal=\"timeout\" from=\"FailCheckTimer\" to=\".\" method=\"_on_fail_check_timer_timeout\"]\n[connection signal=\"timeout\" from=\"FastFailCheckTimer\" to=\".\" method=\"_on_fast_fail_check_timer_timeout\"]\n"
  },
  {
    "path": "src/player/auto_oil.gd",
    "content": "class_name AutoOil\n\n\n# Class for managing autooil assignments.\n\n\nconst OIL_TYPE_MAP: Dictionary = {\n\t\"sharpness\": [1001, 1002, 1003],\n\t\"magic\": [1004, 1005, 1006],\n\t\"accuracy\": [1007, 1008, 1009],\n\t\"swiftness\": [1010, 1011, 1012],\n\t\"sorcery\": [1013, 1014, 1015],\n\t\"exuberance\": [1016, 1017],\n\t\"seeker\": [1018, 1019],\n\t\"lore\": [1020, 1021],\n\t\"tears\": [1022],\n\t\"aether\": [1023],\n\t\"wizard\": [1024],\n}\n\nconst OIL_TYPE_SYNONYMS: Dictionary = {\n\t\"sharpness\": [\"damage\", \"dmg\"],\n\t\"magic\": [\"mana\"],\n\t\"accuracy\": [\"critical\"],\n\t\"swiftness\": [\"speed\"],\n\t\"sorcery\": [\"spell\"],\n\t\"exuberance\": [\"bounty\"],\n\t\"seeker\": [\"item\"],\n\t\"lore\": [\"experience\"],\n}\n\nvar _data: Dictionary = {}\n\n\n#########################\n###       Public      ###\n#########################\n\n# Returns a string describing current autooil assignments\nfunc get_status() -> String:\n\tvar text: String = \"\"\n\t\n\tvar oil_type_list: Array = OIL_TYPE_MAP.keys()\n\toil_type_list.sort()\n\t\n\tfor oil_type in oil_type_list:\n\t\tvar oil_type_is_assigned: bool = _data.has(oil_type)\n\t\tif !oil_type_is_assigned:\n\t\t\tcontinue\n\t\t\n\t\tvar tower: Tower = _data[oil_type]\n\t\tif tower == null:\n\t\t\tcontinue\n\t\t\n\t\tvar tower_name: String = tower.get_display_name()\n\t\ttext += tr(\"AUTOOIL_STATUS\").format({OIL_TYPE = oil_type, TOWER = tower_name})\n\t\ttext += \"\\n\"\n\n\tif text.is_empty():\n\t\ttext += tr(\"AUTOOIL_STATUS_NONE\")\n\t\n\treturn text\n\n\n# Assigns tower to be autooiled by given oil type\nfunc set_tower(given_oil_type: String, tower: Tower):\n\tvar oil_type: String = AutoOil.convert_short_type_to_full(given_oil_type)\n\t\n\tvar oil_type_is_valid: bool = oil_type != \"\"\n\tif !oil_type_is_valid:\n\t\treturn\n\t\n\tvar prev_tower: Tower = _data.get(oil_type, null)\n\tif prev_tower != null:\n\t\t_disconnect_tower(tower)\n\t\n\tif tower != null && !tower.tree_exited.is_connected(_on_tower_tree_exited):\n\t\ttower.tree_exited.connect(_on_tower_tree_exited.bind(tower))\n\t\n\t_data[oil_type] = tower\n\n\n# Returns tower which is assigned to be autooiled by given oil\nfunc get_tower(oil_id: int) -> Tower:\n\tvar matching_oil_type: String = \"\"\n\n\t# NOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_oil_types: Array = OIL_TYPE_MAP.keys()\n\tsorted_oil_types.sort()\n\tfor oil_type in sorted_oil_types:\n\t\tvar oil_list: Array = OIL_TYPE_MAP[oil_type]\n\t\tvar oil_type_matches: bool = oil_list.has(oil_id)\n\n\t\tif oil_type_matches:\n\t\t\tmatching_oil_type = oil_type\n\t\n\tif matching_oil_type != \"\":\n\t\tvar tower: Tower = _data.get(matching_oil_type, null)\n\t\t\n\t\treturn tower\n\telse:\n\t\treturn null\n\n\n# Transfers autooil settings from one tower to another. Used\n# when tower is upgraded or transformed, otherwise autooil\n# assignments would be lost!\nfunc transfer_autooils(prev_tower: Tower, new_tower: Tower):\n\t# NOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_oil_types: Array = _data.keys()\n\tsorted_oil_types.sort()\n\tfor oil_type in sorted_oil_types:\n\t\tvar assigned_tower: Tower = _data[oil_type]\n\n\t\tif assigned_tower == prev_tower:\n\t\t\t_data[oil_type] = new_tower\n\n\nfunc clear_all():\n\tfor tower in _data.values():\n\t\t_disconnect_tower(tower)\n\t\n\t_data.clear()\n\n\nfunc clear_for_tower(tower: Tower):\n\t# NOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_oil_types: Array = _data.keys()\n\tsorted_oil_types.sort()\n\tfor oil_type in sorted_oil_types:\n\t\tvar assigned_tower: Tower = _data[oil_type]\n\n\t\tif assigned_tower == tower:\n\t\t\t_data[oil_type] = null\n\n\t_disconnect_tower(tower)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _disconnect_tower(tower: Tower):\n\tif !tower.tree_exited.is_connected(_on_tower_tree_exited):\n\t\treturn\n\t\n\ttower.tree_exited.disconnect(_on_tower_tree_exited)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_tower_tree_exited(tower: Tower):\n\tclear_for_tower(tower)\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func get_oil_type_list() -> Array:\n\tvar list: Array = OIL_TYPE_MAP.keys()\n\tlist.sort()\n\t\n\treturn list\n\n\nstatic func get_oil_type_is_valid(given_oil_type: String) -> bool:\n\tvar oil_type: String = AutoOil.convert_short_type_to_full(given_oil_type)\n\tvar is_valid: bool = oil_type != \"\"\n\t\n\treturn is_valid\n\n\n# Returns empty string if conversion is not possible\nstatic func convert_short_type_to_full(short_oil_type: String) -> String:\n\tif short_oil_type in OIL_TYPE_MAP:\n\t\treturn short_oil_type\n\t\n\tvar matching_type_count: int = 0\n\tvar matching_oil_type: String = \"\"\n\t\n\tvar oil_type_list: Array = OIL_TYPE_MAP.keys()\n\t\n\tfor oil_type in oil_type_list:\n\t\tvar matches: bool = oil_type.begins_with(short_oil_type)\n\t\t\n\t\tif not matches and oil_type in OIL_TYPE_SYNONYMS:\n\t\t\tfor synonym in OIL_TYPE_SYNONYMS[oil_type]:\n\t\t\t\tif synonym.begins_with(short_oil_type):\n\t\t\t\t\tmatches = true\n\t\t\t\t\tbreak\n\t\t\n\t\tif matches:\n\t\t\tmatching_type_count += 1\n\t\t\tmatching_oil_type = oil_type\n\t\n\tvar more_than_one_match: bool = matching_type_count > 1\n\t\n\tif more_than_one_match:\n\t\treturn \"\"\n\telse:\n\t\treturn matching_oil_type\n"
  },
  {
    "path": "src/player/camera_origin.gd",
    "content": "class_name CameraOrigin extends Sprite2D\n\n# Defines an origin for player camera.\n\n@export var player_id: int\n\n\nfunc _ready():\n\tadd_to_group(\"camera_origins\")\n\t\n#\tNOTE: need to hide camera origin during gameplay. It\n#\tdisplays as a sprite in editor, for convenience while\n#\tdeveloping.\n\thide()\n"
  },
  {
    "path": "src/player/camera_origin.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ccrjj36jwy707\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bte5c4ua8te4k\" path=\"res://assets/misc/icon.png\" id=\"1_kf6ae\"]\n[ext_resource type=\"Script\" path=\"res://src/player/camera_origin.gd\" id=\"2_uigp7\"]\n\n[node name=\"CameraOrigin\" type=\"Sprite2D\"]\nz_index = 100\ntexture = ExtResource(\"1_kf6ae\")\nscript = ExtResource(\"2_uigp7\")\n"
  },
  {
    "path": "src/player/player.gd",
    "content": "class_name Player extends Node\n\n# Class representing the player that owns towers. Used for\n# multiplayer purposes. Create players using\n# Team.create_player().\n\nsignal wave_finished(level: int)\nsignal wave_spawned(level: int)\nsignal element_level_changed(element: Element.enm)\nsignal generated_waves()\nsignal selected_builder()\nsignal voted_ready()\nsignal roll_was_disabled()\nsignal rolled_starting_towers()\nsignal game_lose()\n\n\nconst STARTING_ELEMENT_COST = 20\nconst MAX_FOOD_CAP: int = 300\nconst INITIAL_FOOD_CAP: int = 55\nconst MAX_GOLD = 999999\n# NOTE: the interest gain max value comes from the JASS code\n# for original game\nconst INTEREST_GAIN_MAX: int = 1000\nconst MAX_KNOWLEDGE_TOMES: int = 999999\nconst KNOWLEDGE_TOMES_INCOME: int = 8\nconst INITIAL_TOWER_ROLL_COUNT: int = 6\nconst INITIAL_GOLD: int = 70\nconst INITIAL_TOMES: int = 90\n\nconst PLAYER_COLOR_MAP: Dictionary = {\n\t0: Color.RED,\n\t1: Color.ROYAL_BLUE,\n\t2: Color.ORANGE,\n\t3: Color.PURPLE,\n\t4: Color.GREEN,\n\t5: Color.CYAN,\n\t6: Color.BROWN,\n\t7: Color.PINK,\n}\n\n\nvar _team: Team = null\nvar _total_damage: float = 0\nvar _tower_count_for_starting_roll: int = INITIAL_TOWER_ROLL_COUNT\nvar _element_level_map: Dictionary = {}\nvar _max_element_level_bonus: int = 0\nvar _max_tower_level_bonus: int = 0\nvar _food: int = 0\nvar _food_cap: int = INITIAL_FOOD_CAP\nvar _income_rate: float = 1.0\nvar _interest_rate: float = 0.05\n# NOTE: gold is stored as centiunits (multiply by 100)\n# to preserve fractional values while avoiding float precision\n# issues in multiplayer. For example, 1.5 gold is stored as 150.\nvar _gold_centi: int = INITIAL_GOLD * 100\nvar _gold_farmed_centi: int = 0\nvar _tomes: int = INITIAL_TOMES\nvar _id: int = -1\nvar _peer_id: int = -1\nvar _user_id: String = \"\"\nvar _builder: Builder = null\nvar _have_placeholder_builder: bool = true\nvar _score: float = 0.0\nvar _is_ready: bool = false\nvar _focus_target_effect_id: int = 0\nvar _builder_wisdom_multiplier: float = 1.0\nvar _wisdom_modifier: Modifier = Modifier.new()\nvar _selected_unit: Unit = null\nvar _autooil: AutoOil = AutoOil.new()\nvar _player_name: String = \"Player\"\nvar _chat_ignored: bool = false\nvar _attack_range_bonus: float = 0.0\nvar _tower_exp_bonus: float = 0.0\n\n@export var _item_stash: ItemContainer\n@export var _horadric_stash: ItemContainer\n@export var _tower_stash: TowerStash\n@export var _wave_spawner: WaveSpawner\n\n@onready var _floating_text_container: Node = get_tree().get_root().get_node(\"GameScene/World/FloatingTextContainer\")\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_wave_spawner.set_player(self)\n\t\n\tfor element in Element.get_list():\n\t\t_element_level_map[element] = 0\n\n\t_gold_centi += Config.cheat_gold() * 100\n\t_tomes += Config.cheat_tomes()\n\t_food_cap += Config.cheat_food_cap()\n\t\n\t_item_stash.set_player(self)\n\t_horadric_stash.set_player(self)\n\n\t_player_name = _determine_player_name()\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: this attack range bonus will be applied to all\n# towers created by this player. There is a Wisdom Upgrade\n# which adds this bonus.\nfunc set_attack_range_bonus(value: float):\n\t_attack_range_bonus = value\n\n\nfunc get_attack_range_bonus() -> float:\n\treturn _attack_range_bonus\n\n\n# NOTE: this exp bonus will be applied to all towers created\n# by this player. There is a Wisdom Upgrade which adds this\n# bonus.\nfunc set_tower_exp_bonus(value: float):\n\t_tower_exp_bonus = value\n\n\nfunc get_tower_exp_bonus() -> float:\n\treturn _tower_exp_bonus\n\n\nfunc set_chat_ignored(value: bool):\n\t_chat_ignored = value\n\n\nfunc get_chat_ignored() -> bool:\n\treturn _chat_ignored\n\n\nfunc get_autooil_status() -> String:\n\treturn _autooil.get_status()\n\n\nfunc get_autooil_tower(oil_id: int) -> Tower:\n\treturn _autooil.get_tower(oil_id)\n\n\nfunc transfer_autooils(prev_tower: Tower, new_tower: Tower):\n\t_autooil.transfer_autooils(prev_tower, new_tower)\n\n\nfunc set_autooil_for_tower(type: String, tower: Tower):\n\t_autooil.set_tower(type, tower)\n\n\nfunc clear_autooil_for_tower(tower: Tower):\n\t_autooil.clear_for_tower(tower)\n\n\nfunc clear_all_autooil():\n\t_autooil.clear_all()\n\n\n# NOTE: destroy prev effect so that there's only one arrow\n# up at a time\nfunc create_focus_target_effect(target: Unit):\n\tEffect.destroy_effect(_focus_target_effect_id)\n\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/target_arrow.tscn\", target, Unit.BodyPart.HEAD)\n\tEffect.set_lifetime(effect, 2.0)\n\t_focus_target_effect_id = effect\n\n\nfunc vote_ready():\n\tif _is_ready:\n\t\treturn\n\n\t_is_ready = true\n\tvar player_name: String = get_player_name_with_color()\n\tMessages.add_normal(null, tr(\"MESSAGE_PLAYER_IS_READY\").format({PLAYER_NAME = player_name}))\n\tvoted_ready.emit()\n\n\nfunc is_ready() -> bool:\n\treturn _is_ready\n\n\nfunc generate_waves():\n\t_wave_spawner.generate_waves()\n\tgenerated_waves.emit()\n\n\nfunc start_wave(level: int):\n\t_wave_spawner.start_wave(level)\n\n\n# NOTE: wave is considered in progress if it's spawning\n# creeps or about to start spawning creeps. If it has\n# finished spawning creeps but creeps are still alive, the\n# wave is considered to not be in progress.\n# NOTE: include PENDING state to handle edge case of\n# multiplayer and 1 creep Boss waves.\nfunc wave_is_in_progress() -> bool:\n\tvar current_level: int = _team.get_level()\n\tvar current_wave: Wave = _wave_spawner.get_wave(current_level)\n\n\tif current_wave == null:\n\t\treturn false\n\n\tvar current_wave_state: Wave.State = current_wave.state\n\tvar is_in_progress: bool = current_wave_state == Wave.State.PENDING || current_wave_state == Wave.State.SPAWNING \n\n\treturn is_in_progress\n\n\nfunc current_wave_is_finished() -> bool:\n\treturn _wave_spawner.current_wave_is_finished()\n\n\nfunc wave_is_finished(level: int) -> bool:\n\treturn _wave_spawner.wave_is_finished(level)\n\n\nfunc set_builder(builder_id: int):\n\tif !_have_placeholder_builder:\n\t\tpush_error(\"Player already has a builder. set_builder() should only be called once.\")\n\n\t\treturn\n\n\tif _builder != null:\n\t\tremove_child(_builder)\n\t\t_builder.queue_free()\n\n\tvar builder: Builder = Builder.create_instance(builder_id)\n\t_builder = builder\n\tadd_child(builder)\n\n\tbuilder.apply_to_player(self)\n\n\t_have_placeholder_builder = false\n\n\tselected_builder.emit()\n\n\nfunc get_builder() -> Builder:\n\treturn _builder\n\n\nfunc get_item_stash() -> ItemContainer:\n\treturn _item_stash\n\n\nfunc get_horadric_stash() -> ItemContainer:\n\treturn _horadric_stash\n\n\nfunc get_tower_stash() -> TowerStash:\n\treturn _tower_stash\n\n\nfunc get_tower_count_for_starting_roll() -> int:\n\treturn _tower_count_for_starting_roll\n\n\nfunc research_element(element: Element.enm):\n\tvar research_cost: int = get_research_cost(element)\n\tspend_tomes(research_cost)\n\t\n\t_element_level_map[element] += 1\n\telement_level_changed.emit()\n\n\nfunc get_element_level(element: Element.enm) -> int:\n\tvar level: int = _element_level_map[element]\n\t\n\treturn level\n\n\nfunc get_element_level_map() -> Dictionary:\n\treturn _element_level_map\n\nfunc get_max_element_level_bonus() -> int:\n\treturn _max_element_level_bonus\n\nfunc get_max_element_level() -> int:\n\treturn Constants.MAX_ELEMENT_LEVEL_BASE + get_max_element_level_bonus()\n\nfunc get_max_tower_level_bonus() -> int:\n\treturn _max_tower_level_bonus\n\nfunc get_max_tower_level() -> int:\n\treturn min(Constants.TOWER_MAX_LEVEL_BASE + get_max_tower_level_bonus(), Constants.TOWER_MAX_LEVEL_WITH_BONUS)\n\nfunc get_research_cost(element: Element.enm) -> int:\n\tvar level: int = get_element_level(element)\n\tvar cost: int = STARTING_ELEMENT_COST + level\n\n\treturn cost\n\n\n# Returns true if have enough tomes to research element.\n# Doesn't check whether element is at max level.\nfunc can_afford_research(element: Element.enm) -> bool:\n\tvar cost: int = get_research_cost(element)\n\tvar tome_count: int = get_tomes()\n\tvar can_afford: bool = tome_count >= cost\n\n\treturn can_afford\n\n\n# Returns true if player is able to research element. Checks\n# whether element is at max level.\nfunc is_able_to_research(element: Element.enm) -> bool:\n\tvar can_afford: bool = can_afford_research(element)\n\tvar current_level: int = get_element_level(element)\n\tvar reached_max_level: bool = current_level == get_max_element_level()\n\tvar is_able: bool = can_afford && !reached_max_level\n\n\treturn is_able\n\n\nfunc get_player_name() -> String:\n\treturn _player_name\n\n\nfunc get_color() -> Color:\n\tvar player_color: Color = PLAYER_COLOR_MAP.get(_id, Color.WHITE)\n\n\treturn player_color\n\n\nfunc get_player_name_with_color() -> String:\n\tvar player_color: Color = get_color()\n\tvar player_name_with_color: String = Utils.get_colored_string(Utils.escape_bbcode(_player_name), player_color)\n\n\treturn player_name_with_color\n\n\nfunc get_id() -> int:\n\treturn _id\n\n\nfunc get_peer_id() -> int:\n\treturn _peer_id\n\n\nfunc get_user_id() -> String:\n\treturn _user_id\n\n\nfunc get_score() -> float:\n\treturn _score\n\n\nfunc add_score(amount: float):\n\t_score += amount\n\n\n# NOTE: player.getTeam() in JASS\nfunc get_team() -> Team:\n\treturn _team\n\n\n# NOTE: player.displayFloatingTextX() in JASS\nfunc display_floating_text_x(text: String, unit: Unit, color: Color, velocity: float, fadepoint: float, time: float):\n\tif self != PlayerManager.get_local_player():\n\t\treturn\n\t\n\tvar floating_text = Preloads.floating_text_scene.instantiate()\n\tfloating_text.text = text\n\tfloating_text.color = color\n\tfloating_text.duration = time\n\tfloating_text.fadepoint = fadepoint\n\tfloating_text.position = unit.get_visual_position()\n\tfloating_text.velocity = Vector2(0, -velocity)\n\t_floating_text_container.add_child(floating_text)\n\n\n# NOTE: player.displayFloatingTextX2() in JASS\nfunc display_floating_text_x_2(text: String, unit: Unit, color: Color, velocity: float, fadepoint: float, time: float, _scale: float, random_offset: float):\n\tif self != PlayerManager.get_local_player():\n\t\treturn\n\n\tvar floating_text = Preloads.floating_text_scene.instantiate()\n\tfloating_text.text = text\n\tfloating_text.color = color\n\tfloating_text.duration = time\n\tfloating_text.fadepoint = fadepoint\n\tfloating_text.position = unit.get_visual_position()\n\tfloating_text.random_offset = random_offset\n\tfloating_text.velocity = Vector2(0, -velocity)\n\t_floating_text_container.add_child(floating_text)\n\n\n# NOTE: player.displayFloatingText() in JASS\nfunc display_floating_text(text: String, unit: Unit, color: Color):\n\tif self != PlayerManager.get_local_player():\n\t\treturn\n\n\tvar floating_text = Preloads.floating_text_scene.instantiate()\n\tfloating_text.text = text\n\tfloating_text.color = color\n\tfloating_text.position = unit.get_visual_position()\n\t_floating_text_container.add_child(floating_text)\n\n\n# NOTE: player.displaySmallFloatingText() in JASS\nfunc display_small_floating_text(text: String, unit: Unit, color: Color, random_offset: float):\n\tif self != PlayerManager.get_local_player():\n\t\treturn\n\n\tvar floating_text = Preloads.floating_text_scene.instantiate()\n\tfloating_text.text = text\n\tfloating_text.color = color\n\tfloating_text.position = unit.get_visual_position()\n\tfloating_text.random_offset = random_offset\n\t_floating_text_container.add_child(floating_text)\n\n\nfunc display_floating_text_at_pos(text: String, pos_wc3: Vector2, color: Color):\n\tif self != PlayerManager.get_local_player():\n\t\treturn\n\n\tvar pos_canvas: Vector2 = VectorUtils.wc3_to_canvas(Vector3(pos_wc3.x, pos_wc3.y, 0))\n\n\tvar floating_text = Preloads.floating_text_scene.instantiate()\n\tfloating_text.text = text\n\tfloating_text.color = color\n\tfloating_text.position = pos_canvas\n\t_floating_text_container.add_child(floating_text)\n\n\n# NOTE: player.giveGold() in JASS\nfunc give_gold(amount: float, unit: Unit, show_effect: bool, show_text: bool):\n\tadd_gold(amount)\n\n\tif show_effect:\n\t\tEffect.create_simple_at_unit(\"res://src/effects/gold_credit.tscn\", unit)\n\n\tif show_text:\n\t\tvar text: String\n#\t\tNOTE: add 1 significant digit for <1.0 amounts but\n#\t\tnone for greater amounts because for those amounts\n#\t\tit's not important and only adds visual noise.\n\t\tvar amount_string_digits: int\n\t\tif amount < 1.0:\n\t\t\tamount_string_digits = 1\n\t\telse:\n\t\t\tamount_string_digits = 0\n\t\tvar amount_string: String = Utils.format_float(amount, amount_string_digits)\n\n\t\tif amount >= 0:\n\t\t\ttext = \"+%s\" % amount_string\n\t\telse:\n\t\t\ttext = \"-%s\" % amount_string\n\n\t\tvar color: Color\n\t\tif amount >= 0:\n\t\t\tcolor = Color.GOLD\n\t\telse:\n\t\t\tcolor = Color.RED\n\n\t\tdisplay_floating_text(text, unit, color)\n\n\nfunc add_gold(amount: float, source_is_income: bool = false):\n#\tNOTE: gold framed should include only gold gained from\n#\tcreep kills or item/tower effects\n#\tNOTE: store gold as centiunits (multiply by 100) to\n#\tpreserve fractional values while using integer arithmetic\n#\tfor multiplayer determinism.\n\tvar amount_centi: int = roundi(amount * 100.0)\n\n\tif !source_is_income:\n\t\t_gold_farmed_centi += amount_centi\n\n\tvar new_total_centi: int = _gold_centi + amount_centi\n\t_set_gold_centi(new_total_centi)\n\n\nfunc get_gold() -> float:\n\treturn _gold_centi / 100.0\n\n\nfunc get_gold_farmed() -> float:\n\treturn _gold_farmed_centi / 100.0\n\n\n# NOTE: player.modifyIncomeRate in JASS\nfunc modify_income_rate(amount: float):\n\t_income_rate = _income_rate + amount\n\n\n# NOTE: player.modifyInterestRate in JASS\nfunc modify_interest_rate(amount: float):\n\t_interest_rate = _interest_rate + amount\n\n\nfunc enough_gold_for_tower(tower_id: int) -> bool:\n\tvar cost: float = TowerProperties.get_cost(tower_id)\n\tvar current_gold: float = get_gold()\n\tvar enough_gold: bool = cost <= current_gold\n\n\treturn enough_gold\n\n\nfunc spend_gold(amount: float):\n#\tNOTE: store gold as centiunits (multiply by 100) to\n#\tpreserve fractional values while using integer arithmetic\n#\tfor multiplayer determinism.\n\tvar amount_centi: int = roundi(amount * 100.0)\n\tvar new_total_centi: int = _gold_centi - amount_centi\n\t_set_gold_centi(new_total_centi)\n\n\nfunc get_tomes() -> int:\n\treturn _tomes\n\n\nfunc add_tomes(amount: int):\n\tvar new_tomes: int = _tomes + amount\n\t_set_tomes(new_tomes)\n\n\nfunc spend_tomes(amount: int):\n\tvar new_value: int = _tomes - amount\n\t_set_tomes(new_value)\n\n\nfunc enough_tomes_for_tower(tower_id: int) -> bool:\n\tvar tome_cost: int = TowerProperties.get_tome_cost(tower_id)\n\tvar enough_tomes: bool = tome_cost <= _tomes\n\n\treturn enough_tomes\n\n\nfunc enough_food_for_tower(tower_id: int, preceding_tower_id: int = -1) -> bool:\n\tvar preceding_food_cost: int\n\tif preceding_tower_id != -1:\n\t\tpreceding_food_cost = TowerProperties.get_food_cost(preceding_tower_id)\n\telse:\n\t\tpreceding_food_cost = 0\n\n\tvar food_cost: int = TowerProperties.get_food_cost(tower_id)\n\tvar food_after_add: int = _food + food_cost - preceding_food_cost\n\tvar enough_food: bool = food_after_add <= _food_cap\n\n\treturn enough_food\n\n\nfunc add_food_for_tower(tower_id: int):\n\tvar food_cost: int = TowerProperties.get_food_cost(tower_id)\n\tvar new_food: int = _food + food_cost\n\n\tif new_food > _food_cap:\n\t\tpush_error(\"Tried to change food above cap.\")\n\n\t\treturn\n\n\t_food = new_food\n\n\nfunc remove_food_for_tower(tower_id: int):\n\tvar food_cost: int = TowerProperties.get_food_cost(tower_id)\n\tvar new_food: int = _food - food_cost\n\t\n\tif new_food < 0:\n\t\tpush_error(\"Tried to change food below 0.\")\n\n\t\treturn\n\t\n\t_food = new_food\n\n\nfunc modify_food_cap(amount: int):\n\t_food_cap = clampi(_food_cap + amount, 0, MAX_FOOD_CAP)\n\n\nfunc get_food() -> int:\n\treturn _food\n\n\nfunc get_food_cap() -> int:\n\treturn _food_cap\n\n\n# NOTE: player.getNumTowers in JASS\nfunc get_num_towers() -> int:\n\tvar tower_list: Array = get_tree().get_nodes_in_group(\"towers\")\n\tvar num_towers: int = tower_list.size()\n\n\treturn num_towers\n\n\nfunc add_to_total_damage(damage: float):\n\t_total_damage += damage\n\n\nfunc get_total_damage() -> float:\n\treturn _total_damage\n\n\nfunc get_next_5_waves() -> Array[Wave]:\n\tvar wave_list: Array[Wave] = []\n\tvar current_level: int = get_team().get_level()\n\n\tfor level in range(current_level, current_level + 6):\n\t\tvar wave: Wave = _wave_spawner.get_wave(level)\n\n\t\tif wave != null:\n\t\t\twave_list.append(wave)\n\n\treturn wave_list\n\n\nfunc disable_rolling():\n\troll_was_disabled.emit()\n\n\n# Sets the multiplier for all wisdom upgrade effects. This\n# multiplier comes from some builders and for most it is\n# simply x1.0.\nfunc set_builder_wisdom_multiplier(value: float):\n\t_builder_wisdom_multiplier = value\n\n\nfunc get_builder_wisdom_multiplier() -> float:\n\treturn _builder_wisdom_multiplier\n\n\nfunc set_wisdom_modifier(value: Modifier):\n\t_wisdom_modifier = value\n\n\nfunc get_wisdom_modifier() -> Modifier:\n\treturn _wisdom_modifier\n\n\n# NOTE: this functionality is split between here and\n# SelectUnit class at the moment. Need to figure out how to\n# factor it properly, to have correct syncing in multiplayer\n# and without sacrificing responsiveness.\n# \n# NOTE: this f-n should be called only by ActionSelectUnit\nfunc set_selected_unit(new_selected_unit: Unit):\n\tvar old_selected_unit: Unit = _selected_unit\n\n\tif old_selected_unit != null:\n\t\told_selected_unit.tree_exited.disconnect(_on_selected_unit_tree_exited)\n\n\tif new_selected_unit != null && !new_selected_unit.tree_exited.is_connected(_on_selected_unit_tree_exited):\n\t\tnew_selected_unit.tree_exited.connect(_on_selected_unit_tree_exited.bind(new_selected_unit))\n\n\t_selected_unit = new_selected_unit\n\n\nfunc get_selected_unit() -> Unit:\n\treturn _selected_unit\n\n\nfunc roll_starting_towers():\n\tif _tower_count_for_starting_roll == 0:\n\t\tpush_error(\"Cannot roll starting towers because remaining count is 0. Make sure to verify conditions before you call this function.\")\n\n\t\treturn\n\n\t_tower_stash.clear()\n\n\tvar rolled_towers: Array[int] = TowerDistribution.generate_random_towers_with_count(self, _tower_count_for_starting_roll)\n\t_tower_stash.add_towers(rolled_towers)\n\t_add_message_about_rolled_towers(rolled_towers)\n\t\n#\tNOTE: the number of rerolls is limited in multiplayer so\n#\tthat players can compete fairly. In singleplayer, make\n#\tthe reroll amount unlimited because player can restart\n#\tthe game to reset rerolls anyway.\n# \n#\t[ORIGINAL_GAME_DEVIATION] In original game, the reroll\n#\tcount was limited even in singleplayer.\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tvar is_multiplayer: bool = player_mode == PlayerMode.enm.MULTIPLAYER\n\tif is_multiplayer:\n\t\t_tower_count_for_starting_roll = max(0, _tower_count_for_starting_roll - 1)\n\n\tvar can_roll_again: bool = _tower_count_for_starting_roll > 0\n\n\tif can_roll_again:\n\t\tMessages.add_normal(self, tr(\"MESSAGE_REROLLS_REMAINING\").format({REROLL_COUNT = _tower_count_for_starting_roll}))\n\telse:\n\t\tdisable_rolling()\n\n\trolled_starting_towers.emit()\n\n\nfunc emit_game_lose_signal():\n\tgame_lose.emit()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _set_gold_centi(value_centi: int):\n\t_gold_centi = clampi(value_centi, 0, MAX_GOLD * 100)\n\n\nfunc _set_tomes(value):\n\t_tomes = clampi(value, 0, MAX_KNOWLEDGE_TOMES)\n\n\nfunc _add_message_about_rolled_towers(rolled_towers: Array[int]):\n\tMessages.add_normal(self, tr(\"MESSAGE_NEW_TOWERS\"))\n\n#\tSort tower list by element to group messages for same\n#\telement together\n\trolled_towers.sort_custom(func(a, b): \n\t\tvar element_a: int = TowerProperties.get_element(a)\n\t\tvar element_b: int = TowerProperties.get_element(b)\n\t\treturn element_a < element_b)\n\n\tfor tower in rolled_towers:\n\t\tvar element: Element.enm = TowerProperties.get_element(tower)\n\t\tvar element_string: String = Element.convert_to_colored_string(element)\n\t\tvar rarity: Rarity.enm = TowerProperties.get_rarity(tower)\n\t\tvar rarity_color: Color = Rarity.get_color(rarity)\n\t\tvar tower_name: String = TowerProperties.get_display_name(tower)\n\t\tvar tower_name_colored: String = Utils.get_colored_string(tower_name, rarity_color)\n\t\tvar message: String = \"    %s: %s\" % [element_string, tower_name_colored]\n\n\t\tMessages.add_normal(self, message)\n\n\n# NOTE: can't use PlayerManager.get_local_player() in here\n# because this f-n is called during the process of creating\n# players.\nfunc _determine_player_name() -> String:\n\tvar connection_type: Globals.ConnectionType = Globals.get_connect_type()\n\tvar player_is_local: bool = _peer_id == multiplayer.get_unique_id()\n\n\tvar player_name: String\n\tif player_is_local:\n\t\tplayer_name = Settings.get_setting(Settings.PLAYER_NAME)\n\telse:\n\t\tmatch connection_type:\n\t\t\tGlobals.ConnectionType.ENET:\n\t\t\t\tplayer_name = Globals.get_player_name_from_peer_id(_peer_id)\n\t\t\tGlobals.ConnectionType.NAKAMA:\n\t\t\t\tplayer_name = NakamaConnection.get_display_name_of_user(_user_id)\n\n\treturn player_name\n\n\n#########################\n###     Callbacks     ###\n#########################\n\n\nfunc _on_wave_spawner_wave_finished(level: int):\n\tvar upkeep: int = floori((20 + level * 2) * _income_rate)\n\tvar current_gold: int = _gold_centi / 100\n\tvar interest: int = floori(min(current_gold * _interest_rate, INTEREST_GAIN_MAX))\n\tvar income: int = upkeep + interest\n\tvar source_is_income: bool = true\n\tadd_gold(income, source_is_income)\n\n\tadd_tomes(KNOWLEDGE_TOMES_INCOME)\n\n\t_builder.apply_wave_finished_effect(self)\n\n\tMessages.add_normal(self, tr(\"MESSAGE_LEVEL_COMPLETED\").format({LEVEL = level}))\n\tMessages.add_normal(self, tr(\"MESSAGE_INCOME\").format({UPKEEP = upkeep, INTEREST = interest}))\n\n\tvar game_mode_is_random: bool = Globals.game_mode_is_random()\n\tif game_mode_is_random:\n\t\tvar rolled_towers: Array[int] = TowerDistribution.roll_towers(self)\n\t\t_tower_stash.add_towers(rolled_towers)\n\t\t_add_message_about_rolled_towers(rolled_towers)\n\n#\tWarn players if they have too many unspent knowledge\n#\ttomes.\n#\tNOTE: stop these warnings are a certain wave level is\n#\treached because after a certain point player would have\n#\tresearch 2 elements to the max and these warnings would\n#\tbecome annoying.\n\tvar current_tomes: int = get_tomes()\n\tvar too_many_tomes: bool = current_tomes >= Constants.TOMES_WARNING_THRESHOLD\n\tvar tome_warnings_are_stopped: bool = level >= Constants.WAVE_LEVEL_AFTER_WHICH_TOME_WARNINGS_STOP\n\tif too_many_tomes && !tome_warnings_are_stopped:\n\t\tMessages.add_normal(self, tr(\"MESSAGE_UNSPENT_TOMES\").format({TOME_COUNT = current_tomes}))\n\n\twave_finished.emit(level)\n\n\nfunc _on_wave_spawner_wave_spawned(level: int):\n\twave_spawned.emit(level)\n\n\n# NOTE: Need this slot because \"mouse_exited\" signal doesn't\n# get emitted when units exit the tree because of\n# queue_free().\nfunc _on_selected_unit_tree_exited(unit: Unit):\n\tvar selected_unit_is_being_removed: bool = _selected_unit == unit\n\tif selected_unit_is_being_removed:\n\t\tset_selected_unit(null)\n\n\n# NOTE: either peer_id or user_id has to be defined,\n# depending on if connection is Nakama or Enet\nstatic func make(player_id: int, peer_id: int, user_id: String) -> Player:\n\tvar player: Player = Preloads.player_scene.instantiate()\n\tplayer._id = player_id\n\tplayer._peer_id = peer_id\n\tplayer._user_id = user_id\n\n#\tAdd base class Builder as placeholder until the real\n#\tbuilder is assigned. This builder will have no effects.\n\tvar placeholder_builder: Builder = Builder.new()\n\tplayer._builder = placeholder_builder\n\tplayer.add_child(placeholder_builder)\n\n\treturn player\n"
  },
  {
    "path": "src/player/player.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://cc5f84ah71fsh\"]\n\n[ext_resource type=\"Script\" path=\"res://src/player/player.gd\" id=\"1_qsf5w\"]\n[ext_resource type=\"Script\" path=\"res://src/items/item_container.gd\" id=\"2_ietwb\"]\n[ext_resource type=\"Script\" path=\"res://src/player/tower_stash.gd\" id=\"3_rmd8h\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bah0cloqblp5n\" path=\"res://src/creeps/wave_spawner.tscn\" id=\"4_7cd82\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"5_146xb\"]\n\n[node name=\"Player\" type=\"Node\" node_paths=PackedStringArray(\"_item_stash\", \"_horadric_stash\", \"_tower_stash\", \"_wave_spawner\")]\nscript = ExtResource(\"1_qsf5w\")\n_item_stash = NodePath(\"ItemStash\")\n_horadric_stash = NodePath(\"HoradricStash\")\n_tower_stash = NodePath(\"TowerStash\")\n_wave_spawner = NodePath(\"WaveSpawner\")\n\n[node name=\"ItemStash\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_ietwb\")\n_capacity = 1000\n\n[node name=\"HoradricStash\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_ietwb\")\n_capacity = 6\n\n[node name=\"TowerStash\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"3_rmd8h\")\n\n[node name=\"WaveSpawner\" parent=\".\" instance=ExtResource(\"4_7cd82\")]\n\n[node name=\"StartWaveCooldownTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"5_146xb\")\n\n[connection signal=\"wave_finished\" from=\"WaveSpawner\" to=\".\" method=\"_on_wave_spawner_wave_finished\"]\n[connection signal=\"wave_spawned\" from=\"WaveSpawner\" to=\".\" method=\"_on_wave_spawner_wave_spawned\"]\n"
  },
  {
    "path": "src/player/team.gd",
    "content": "class_name Team extends Node\n\n# Represents the player's team. In singleplayer, the player\n# simply has a team. In multiplayer it can be 1-2 players\n# per team.\n\n\nsignal started_first_wave()\nsignal game_lose()\nsignal game_win()\nsignal level_changed()\n\n\nconst PORTAL_DAMAGE_SFX_COOLDOWN: float = 0.5\nconst START_WAVE_ACTION_COOLDOWN: float = 2.0\n\n\nvar _id: int = -1\nvar _lives: float = 100\nvar _level: int = 1\nvar _player_list: Array[Player] = []\nvar _finished_the_game: bool = false\nvar _player_defined_autospawn_time: float = -1\nvar _allow_shared_build_space: bool = false\n\n@export var _next_wave_timer: ManualTimer\n@export var _portal_damage_sound_cooldown_timer: Timer\n@export var _start_wave_action_cooldown_timer: ManualTimer\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_players() -> Array[Player]:\n\treturn _player_list\n\n\nfunc get_wave_is_in_progress() -> bool:\n\tvar wave_is_in_progress: bool = false\n\n\tfor player in _player_list:\n\t\tif player.wave_is_in_progress():\n\t\t\twave_is_in_progress = true\n\n\t\t\tbreak\n\n\treturn wave_is_in_progress\n\n\nfunc finished_the_game() -> bool:\n\treturn _finished_the_game\n\n\nfunc get_next_wave_timer() -> ManualTimer:\n\treturn _next_wave_timer\n\n\nfunc start_first_wave():\n\t_start_wave()\n\tstarted_first_wave.emit()\n\n\nfunc start_next_wave():\n\tvar reached_last_wave: bool = _level == Globals.get_wave_count()\n\tvar game_is_neverending: bool = Globals.game_is_neverending()\n\n\tif reached_last_wave && !game_is_neverending:\n\t\treturn\n\n\t_level += 1\n\tlevel_changed.emit()\n\t_start_wave()\n\n\nfunc add_player(player: Player):\n\tplayer._team = self\n\t_player_list.append(player)\n\tplayer.wave_spawned.connect(_on_player_wave_spawned)\n\tplayer.wave_finished.connect(_on_player_wave_finished)\n\n\nfunc get_id() -> int:\n\treturn _id\n\n\n# NOTE: Team.getLivesPercent() in JASS\nfunc get_lives_percent() -> float:\n\treturn _lives\n\n\nfunc get_lives_string() -> String:\n\tvar lives_string: String = Utils.format_percent(floori(_lives) / 100.0, 2)\n\n\treturn lives_string\n\n\nfunc modify_lives(amount: float):\n\t_lives = max(0.0, _lives + amount)\n\n\tif Config.unlimited_portal_lives() && _lives == 0:\n\t\t_lives = 1\n\n\tvar out_of_lives: bool = _lives <= 0\n\n\tif out_of_lives && !_finished_the_game:\n\t\t_do_game_lose()\n\n\n# Current level is the level of the last started wave.\n# Starts at 0 and becomes 1 when the first wave starts.\n# NOTE: Team.getLevel() in JASS\nfunc get_level() -> int:\n\treturn _level\n\n\nfunc is_local() -> bool:\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar contains_local_player: bool = _player_list.has(local_player)\n\n\treturn contains_local_player\n\n\nfunc set_waves_paused(paused: bool):\n\t_next_wave_timer.set_paused(paused)\n\n\nfunc set_autospawn_time(time: float):\n\t_player_defined_autospawn_time = time\n\n\nfunc play_portal_damage_sfx():\n\tvar portal_damage_sfx_on_cooldown: bool = !_portal_damage_sound_cooldown_timer.is_stopped()\n\t\n\tif portal_damage_sfx_on_cooldown:\n\t\treturn\n\t\n\tSFX.play_sfx_for_team(self, SfxPaths.HUMAN_DEATH_EXPLODE)\n\n\t_portal_damage_sound_cooldown_timer.start(PORTAL_DAMAGE_SFX_COOLDOWN)\n\n\nfunc convert_local_player_score_to_exp():\n\tvar old_exp_password: String = Settings.get_setting(Settings.EXP_PASSWORD)\n\tvar old_player_exp: int = ExperiencePassword.decode(old_exp_password)\n\tvar old_player_level: int = PlayerExperience.get_level_at_exp(old_player_exp)\n\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar score: int = floori(local_player.get_score())\n\tvar exp_gain: int = floori(score * Constants.SCORE_TO_EXP)\n\n\tvar new_player_exp: int = old_player_exp + exp_gain\n\tvar new_exp_password: String = ExperiencePassword.encode(new_player_exp)\n\tvar new_player_level: int = PlayerExperience.get_level_at_exp(new_player_exp)\n\tvar player_level_changed: bool = new_player_level != old_player_level\n\tSettings.set_setting(Settings.EXP_PASSWORD, new_exp_password)\n\tSettings.flush()\n\n\tvar old_upgrade_count: int = Utils.get_wisdom_upgrade_count_for_player_level(old_player_level)\n\tvar new_upgrade_count: int = Utils.get_wisdom_upgrade_count_for_player_level(new_player_level)\n\tvar gained_new_wisdom_upgrade_slot: bool = new_upgrade_count > old_upgrade_count\n\n\tvar exp_gain_message: String = tr(\"MESSAGE_GAINED_EXPERIENCE\").format({EXP_GAIN = exp_gain})\n\tvar level_up_message: String = tr(\"MESSAGE_PLAYER_LEVEL_UP\").format({LEVEL = new_player_level})\n\tvar wisdom_message: String = tr(\"MESSAGE_NEW_WISDOM_UPGRADE\")\n\n\tvar title_screen_notification: String = \"\"\n\n\tif exp_gain > 0:\n\t\tMessages.add_normal(local_player, exp_gain_message)\n\t\ttitle_screen_notification += exp_gain_message\n\telif exp_gain == 0:\n\t\tMessages.add_normal(local_player, tr(\"MESSAGE_NO_EXPERIENCE_GAINED\"))\n\telif exp_gain < 0:\n\t\tpush_error(\"Exp gained is negative!\")\n\n\tif player_level_changed:\n\t\tMessages.add_normal(local_player, level_up_message)\n\t\ttitle_screen_notification += \" \\n\"\n\t\ttitle_screen_notification += level_up_message\n\n\tif gained_new_wisdom_upgrade_slot:\n\t\tMessages.add_normal(local_player, wisdom_message)\n\t\ttitle_screen_notification += \" \\n\"\n\t\ttitle_screen_notification += wisdom_message\n\n\tif !title_screen_notification.is_empty():\n\t\ttitle_screen_notification = tr(\"NOTIFICATION_AFTER_GAME\") + \"\\n\" +title_screen_notification\n\t\tGlobals.add_title_screen_notification(title_screen_notification)\n\n\nfunc get_start_wave_action_is_on_cooldown() -> bool:\n\tvar is_on_cooldown: bool = !_start_wave_action_cooldown_timer.is_stopped()\n\t\n\treturn is_on_cooldown\n\n\nfunc enable_allow_shared_build_space():\n\t_allow_shared_build_space = true\n\n\nfunc get_allow_shared_build_space() -> bool:\n\treturn _allow_shared_build_space\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _start_wave():\n\t_next_wave_timer.stop()\n\t\n\tfor player in _player_list:\n\t\tplayer.start_wave(_level)\n\t\n\tSFX.play_sfx_for_team(self, SfxPaths.START_WAVE)\n\n# \tNOTE: \"start wave action cooldown\" is a cooldown for\n# \tplayer manually starting next wave by clicking on the\n# \tbutton. Need this cooldown for cases where it's possible\n# \tfor player to accidentally spawn two waves in a row. For\n# \texample, if there are two boss waves back to back and\n# \tplayer double clicks. Or if natural timer times out at\n# \tthe same time as player clicks on the button.\n\t_start_wave_action_cooldown_timer.start(START_WAVE_ACTION_COOLDOWN)\n\n\nfunc _do_game_win():\n\tvar game_is_neverending: bool = Globals.game_is_neverending()\n\t\n\tif !game_is_neverending:\n\t\t_finished_the_game = true\n\t\n\tvar game_win_message: String\n\tif game_is_neverending:\n\t\tgame_win_message = tr(\"MESSAGE_GAME_WIN_NEVERENDING\")\n\telse:\n\t\tgame_win_message = tr(\"MESSAGE_GAME_WIN_NORMAL\")\n\n\tfor player in _player_list:\n\t\tMessages.add_normal(PlayerManager.get_local_player(), game_win_message)\n\n\tif is_local():\n\t\tconvert_local_player_score_to_exp()\n\n\tgame_win.emit()\n\n\tvar COLOR_LIST: Array[Color] = [Color.WHITE, Color.FOREST_GREEN, Color.CYAN, Color.VIOLET, Color.GOLD, Color.PINK, Color.ORANGE]\n\n\tfor i in range(10):\n\t\tvar effect_count: int = 100 + i * 20\n\t\teffect_count = ceili(Globals.synced_rng.randf_range(0.5, 1.0) * effect_count)\n\n\t\tfor j in range(effect_count):\n\t\t\tvar x: float = Globals.synced_rng.randf_range(-4000, 4000)\n\t\t\tvar y: float = Globals.synced_rng.randf_range(-4000, 4000)\n\t\t\tvar scale: float = Globals.synced_rng.randf_range(1.0, 2.0)\n\t\t\tvar speed: float = Globals.synced_rng.randf_range(0.7, 1.0)\n\t\t\tvar color: Color = Utils.pick_random(Globals.synced_rng, COLOR_LIST)\n\n\t\t\tvar effect: int = Effect.create_simple(\"res://src/effects/placeholder.tscn\", Vector2(x, y))\n\t\t\tEffect.set_scale(effect, scale)\n\t\t\tEffect.set_color(effect, color)\n\t\t\tEffect.set_animation_speed(effect, speed)\n\n\t\tawait Utils.create_manual_timer(0.5, self).timeout\n\n\nfunc _do_game_lose():\n\t_finished_the_game = true\n\n#\tDelete all creeps for this team\n\tvar creep_list: Array[Creep] = Utils.get_creep_list()\n\tfor creep in creep_list:\n\t\tvar player_match: bool = _player_list.has(creep.get_player())\n\n\t\tif player_match:\n\t\t\tcreep.remove_from_game()\n\n\t_next_wave_timer.stop()\n\n\tfor player in _player_list:\n\t\tMessages.add_normal(player, tr(\"MESSAGE_GAME_LOSE\"))\n\n\tif is_local():\n\t\tconvert_local_player_score_to_exp()\n\n\tgame_lose.emit()\n\n\tfor player in _player_list:\n\t\tplayer.emit_game_lose_signal()\n\n\n# This function starts the timer only if it's not already\n# running or if new duration is shorter\n# \n# NOTE: it's possible for timer to already be running if the\n# difficulty is extreme and the timer has been started\n# automatically. In such cases, start timer only if new\n# timer is shorter.\nfunc _start_timer_before_next_wave(duration: float):\n\tvar timer_already_running: bool = !_next_wave_timer.is_stopped()\n\tvar new_duration_is_shorter: bool = duration < _next_wave_timer.get_time_left()\n\tvar need_to_start_timer: bool = !timer_already_running || new_duration_is_shorter\n\n\tif need_to_start_timer:\n\t\t_next_wave_timer.start(duration)\n\n\n# On extreme difficulty, there's built-in autospawn. This\n# f-n calculates the autospawn time.\n# Sample values:\n# lvl 1 = 25s\n# lvl 30 = 40s\n# lvl 100 = 40s\n# lvl 120 = 40s\n# lvl 240 = 34s\n# Goes up, stays at 40s, then goes down\nfunc _get_extreme_autospawn_time(level: int) -> float:\n\tvar time: float = min(25 + 0.5 * level, 40) + 6 - max(0.05 * level, 6)\n#\tNOTE: prevent negative value\n\ttime = max(time, 1)\n\n\treturn time\n\n\nfunc _get_bonus_wave_autospawn_time(level: int) -> float:\n\tconst START_TIME: float = 20.0\n\tconst MIN_TIME: float = 1.0\n\tconst REDUCTION_PER_LEVEL: float = 0.25\n\n\tvar autospawn_time: float = START_TIME - max(0, level - Constants.WAVE_COUNT_NEVERENDING) * REDUCTION_PER_LEVEL\n\tautospawn_time = max(autospawn_time, MIN_TIME)\n\n\treturn autospawn_time\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_next_wave_timer_timeout():\n\tstart_next_wave()\n\n\nfunc _on_player_wave_spawned(level: int):\n\tvar wave_is_in_progress: bool = get_wave_is_in_progress()\n\tif wave_is_in_progress:\n\t\treturn\n\n\tvar difficulty_is_extreme: bool = Globals.get_difficulty() == Difficulty.enm.EXTREME\n\tvar game_is_neverending: bool = Globals.game_is_neverending()\n\tvar bonus_waves_in_progress: bool = Utils.wave_is_bonus(level)\n\tvar autospawn_time_is_defined: bool = _player_defined_autospawn_time > 0\n\tvar extreme_autospawn_time: float = _get_extreme_autospawn_time(level)\n\n#\tNOTE: pick shortest autospawn time out of all possible\n#\tsources\n\tvar autospawn_time_list: Array[float] = []\n\tif autospawn_time_is_defined:\n\t\tautospawn_time_list.append(_player_defined_autospawn_time)\n\tif difficulty_is_extreme:\n\t\tautospawn_time_list.append(extreme_autospawn_time)\n\tif game_is_neverending && bonus_waves_in_progress:\n\t\tvar bonus_wave_autospawn_time: float = _get_bonus_wave_autospawn_time(level)\n\t\tautospawn_time_list.append(bonus_wave_autospawn_time)\n\n\tif !autospawn_time_list.is_empty():\n\t\tvar autospawn_time: float = autospawn_time_list.min()\n\t\t_start_timer_before_next_wave(autospawn_time)\n\n\nfunc _on_player_wave_finished(level: int):\n\tif _finished_the_game:\n\t\treturn\n\n\tvar all_players_finished: bool = true\n\tfor player in _player_list:\n\t\tif !player.wave_is_finished(level):\n\t\t\tall_players_finished = false\n\n\tvar player_finished_last_level: bool = level == Utils.get_max_level()\n\tvar team_achieved_victory: bool = player_finished_last_level && all_players_finished\n\n\tif team_achieved_victory:\n\t\t_do_game_win()\n\n\tvar current_level: int = get_level()\n\tvar finished_current_level: bool = level == current_level\n\tvar game_is_neverending: bool = Globals.game_is_neverending()\n\tvar need_to_start_next_wave_timer: bool = !player_finished_last_level || game_is_neverending\n\tvar can_start_next_wave_timer: bool = all_players_finished\n\n#\tNOTE: need to check that *current* level was finished\n#\tbecause waves can be finished out of order if they are\n#\tforce spawned by player. If player finished not-current\n#\tlevel, then we shouldn't start next wave timer.\n\tif finished_current_level && need_to_start_next_wave_timer && can_start_next_wave_timer:\n\t\t_start_timer_before_next_wave(Constants.TIME_BETWEEN_WAVES)\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(id: int) -> Team:\n\tvar team: Team = Preloads.team_scene.instantiate()\n\tteam._id = id\n\n\treturn team\n"
  },
  {
    "path": "src/player/team.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dprva0ovurf0c\"]\n\n[ext_resource type=\"Script\" path=\"res://src/player/team.gd\" id=\"1_58bum\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_r2jva\"]\n\n[node name=\"Team\" type=\"Node\" node_paths=PackedStringArray(\"_next_wave_timer\", \"_portal_damage_sound_cooldown_timer\", \"_start_wave_action_cooldown_timer\")]\nscript = ExtResource(\"1_58bum\")\n_next_wave_timer = NodePath(\"NextWaveTimer\")\n_portal_damage_sound_cooldown_timer = NodePath(\"PortalDamageSoundCooldownTimer\")\n_start_wave_action_cooldown_timer = NodePath(\"StartWaveActionCooldownTimer\")\n\n[node name=\"NextWaveTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_r2jva\")\none_shot = true\n\n[node name=\"PortalDamageSoundCooldownTimer\" type=\"Timer\" parent=\".\"]\none_shot = true\n\n[node name=\"StartWaveActionCooldownTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_r2jva\")\none_shot = true\n\n[connection signal=\"timeout\" from=\"NextWaveTimer\" to=\".\" method=\"_on_next_wave_timer_timeout\"]\n"
  },
  {
    "path": "src/player/tower_stash.gd",
    "content": "class_name TowerStash extends Node\n\n\n# Stores towers which can currently be built as well as how\n# many of each tower is available. Note that if player\n# selects build mode, then tower stash will fill up with all\n# towers and won't change after that.\n\n\nsignal changed()\n\n\n# Map of [tower_id -> available count]\nvar _tower_map: Dictionary = {}\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_towers() -> Dictionary:\n\treturn _tower_map\n\n\nfunc clear():\n\t_tower_map.clear()\n\tchanged.emit()\n\n\nfunc add_towers(tower_list: Array):\n\tfor tower in tower_list:\n\t\tif !_tower_map.has(tower):\n\t\t\t_tower_map[tower] = 0\n\n\t\t_tower_map[tower] += 1\n\n\tchanged.emit()\n\n\nfunc spend_tower(tower: int):\n#\tNOTE: in build mode, building a tower doesn't use it up\n#\tfrom the stash\n\tif Globals.get_game_mode() == GameMode.enm.BUILD:\n\t\treturn\n\n\tif !_tower_map.has(tower):\n\t\treturn\n\n\t_tower_map[tower] -= 1\n\n\tif _tower_map[tower] == 0:\n\t\t_tower_map.erase(tower)\n\n\tchanged.emit()\n\n\nfunc has_tower(tower: int) -> bool:\n\tif !_tower_map.has(tower):\n\t\treturn false\n\n\tvar count: int = _tower_map[tower]\n\tvar count_is_enough: bool = count > 0\n\n\treturn count_is_enough\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc add_all_towers():\n\tvar first_tier_towers: Array = TowerProperties.get_tower_id_list_by_filter(TowerProperties.CsvProperty.TIER, str(1))\n\tadd_towers(first_tier_towers)\n"
  },
  {
    "path": "src/projectiles/projectile.gd",
    "content": "class_name Projectile\nextends DummyUnit\n\n\n# Projectile are moving objects which have an origin and can\n# be setup to move towards a point or unit. The most common\n# use case is to fire a projectile from a tower towards a\n# creep to deal damage.\n\nenum MoveType {\n\tNORMAL,\n\tINTERPOLATED,\n}\n\n\nconst FALLBACK_PROJECTILE_VISUAL: String = \"res://src/projectiles/projectile_visuals/default_projectile.tscn\"\nconst PRINT_SPRITE_NOT_FOUND_ERROR: bool = false\nconst LIGHTNING_VISUAL_LIFETIME: float = 0.5\n# NOTE: same value is used in original game. It roughly\n# results in a position at the vertical center of\n# towers/creeps.\nconst UNIT_Z_OFFSET: Vector3 = Vector3(0, 0, 60)\n\n# UID system for deterministic sorting in multiplayer\nstatic var _uid_max: int = 1\nvar _uid: int = 0\n\nvar _move_type: MoveType\nvar _target_unit: Unit = null\nvar _target_pos: Vector3 = Vector3.INF\nvar _interpolation_is_stopped: bool = false\nvar _interpolation_start: Vector3\nvar _interpolation_progress: float = 0\nvar _interpolation_z_arc_height: float = 0\nvar _bezier_is_enabled: bool = false\nvar _bezier_control_1: Vector3 = Vector3.ZERO\nvar _bezier_control_2: Vector3 = Vector3.ZERO\nvar _is_homing: bool = false\nvar _ignore_target_z: bool = false\nvar _homing_control_value: float\nvar _speed: float = 50\nvar _physics_z_speed: float = 0\nvar _acceleration: float = 0\nvar _rotation: float = 0\nvar _gravity: float\nvar _explode_on_hit: bool = true\nvar _expire_when_homing_ends: bool = true\nvar _explode_on_expiration: bool = true\nvar _initial_scale: Vector2\nvar _tower_crit_count: int = 0\nvar _tower_crit_ratio: float = 0.0\nvar _tower_bounce_visited_list: Array[Unit] = []\nvar _interpolation_finished_handler: Callable = Callable()\nvar _target_hit_handler: Callable = Callable()\nvar _periodic_handler: Callable = Callable()\nvar _impact_handler: Callable = Callable()\nvar _avert_destruct_requested: bool = false\nvar _initial_pos: Vector3\nvar _range: float = 0.0\nvar _direction: float = 0.0\nvar _collision_radius: float = 0.0\nvar _collision_target_type: TargetType = null\nvar _destroy_on_collision: bool = false\nvar _collision_handler: Callable = Callable()\nvar _expiration_handler: Callable = Callable()\nvar _collision_history: Array[Unit] = []\nvar _collision_enabled: bool = true\nvar _periodic_enabled: bool = true\nvar _physics_enabled: bool = true\nvar _periodic_timer: ManualTimer = null\nvar _spawn_time: float\nvar _visual_path: String\nvar _use_lightning_visual: bool\nvar _explosion_art: String\n\nvar user_int: int = 0\nvar user_int2: int = 0\nvar user_int3: int = 0\nvar user_real: float = 0.0\nvar user_real2: float = 0.0\nvar user_real3: float = 0.0\n\n\n@export var _lifetime_timer: ManualTimer\n@export var _visual_node: Node2D\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tsuper()\n\n\t_uid = _uid_max\n\t_uid_max += 1\n\n\t_initial_scale = scale\n\t_spawn_time = Utils.get_time()\n\n\tvar visual_exists: bool = ResourceLoader.exists(_visual_path)\n\tif !visual_exists:\n\t\tif PRINT_SPRITE_NOT_FOUND_ERROR:\n\t\t\tprint_debug(\"Failed to find sprite for projectile. Tried at path:\", _visual_path)\n\n\t\t_visual_path = FALLBACK_PROJECTILE_VISUAL\n\n\tvar visual_scene: PackedScene = load(_visual_path)\n\tvar visual: Node2D = visual_scene.instantiate()\n\t_visual_node.add_child(visual)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc update(delta: float):\n\tif _target_unit != null:\n\t\t_target_pos = _target_unit.get_position_wc3() + UNIT_Z_OFFSET\n\n\tmatch _move_type:\n\t\tMoveType.NORMAL: _update_normal(delta)\n\t\tMoveType.INTERPOLATED: _update_interpolated(delta)\n\n\nfunc set_position_wc3(value: Vector3):\n\tsuper(value)\n\n\t_visual_node.position.y = -value.z\n\n\nfunc avert_destruction():\n\t_avert_destruct_requested = true\n\n\n# NOTE: aimAtUnit() in JASS\nfunc aim_at_unit(target_unit: Unit, targeted: bool, ignore_z: bool, expire_when_reached: bool):\n\tif targeted:\n\t\tset_homing_target(target_unit)\n\telse:\n\t\tset_homing_target(null)\n\n\tvar target_pos: Vector3 = target_unit.get_position_wc3() + UNIT_Z_OFFSET\n\t_start_movement_normal(target_pos, ignore_z, expire_when_reached)\n\n\n# NOTE: aimAtPoint() in JASS\nfunc aim_at_point(target_pos: Vector3, ignore_z: bool, expire_when_reached: bool):\n\t_start_movement_normal(target_pos, ignore_z, expire_when_reached)\n\n\nfunc stop_interpolation():\n\t_interpolation_is_stopped = true\n\tset_homing_target(null)\n\t_interpolation_progress = 0\n\n\nfunc start_interpolation_to_point(target_pos: Vector3, z_arc: float):\n\tset_homing_target(null)\n\t_start_movement_interpolated(target_pos, z_arc)\n\n\tif _use_lightning_visual:\n\t\t_visual_node.hide()\n\t\t\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_point(InterpolatedSprite.LIGHTNING, get_position_wc3(), target_pos)\n\t\t_setup_lightning_visual(lightning)\n\n\nfunc start_interpolation_to_unit(target_unit: Unit, z_arc: float, targeted: bool):\n\tif targeted:\n\t\tset_homing_target(target_unit)\n\telse:\n\t\tset_homing_target(null)\n\n\tvar target_pos: Vector3 = target_unit.get_position_wc3() + UNIT_Z_OFFSET\n\t_start_movement_interpolated(target_pos, z_arc)\n\n\tif _use_lightning_visual:\n\t\t_visual_node.hide()\n\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, get_position_wc3(), target_unit)\n\t\t_setup_lightning_visual(lightning)\n\n\nfunc start_bezier_interpolation_to_point(target_pos: Vector3, z_arc: float, side_arc: float, steepness: float):\n\tset_homing_target(null)\n\t_start_movement_bezier_interpolated(target_pos, z_arc, side_arc, steepness)\n\n\tif _use_lightning_visual:\n\t\t_visual_node.hide()\n\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_point(InterpolatedSprite.LIGHTNING, get_position_wc3(), target_pos)\n\t\t_setup_lightning_visual(lightning)\n\n\nfunc start_bezier_interpolation_to_unit(target_unit: Unit, z_arc: float, side_arc: float, steepness: float, targeted: bool):\n\tif targeted:\n\t\tset_homing_target(target_unit)\n\telse:\n\t\tset_homing_target(null)\n\n\tvar target_pos: Vector3 = target_unit.get_position_wc3() + UNIT_Z_OFFSET\n\t_start_movement_bezier_interpolated(target_pos, z_arc, side_arc, steepness)\n\n\tif _use_lightning_visual:\n\t\t_visual_node.hide()\n\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, get_position_wc3(), target_unit)\n\t\t_setup_lightning_visual(lightning)\n\n\n# NOTE: disablePeriodic() in JASS\nfunc disable_periodic():\n\t_periodic_enabled = false\n\n\n# NOTE: enablePeriodic() in JASS\nfunc enable_periodic(time: float):\n\t_periodic_enabled = true\n\n\tif _periodic_timer != null:\n\t\t_periodic_timer.wait_time = time\n\n\n# NOTE: setCollisionParameters() in JASS\nfunc set_collision_parameters(radius: float, target_type: TargetType):\n\t_collision_radius = radius\n\t_collision_target_type = target_type\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _setup_lightning_visual(lightning: InterpolatedSprite):\n\tvar caster_element: Element.enm = _caster.get_element()\n\tvar caster_element_color: Color = Element.get_color(caster_element)\n\tlightning.modulate = caster_element_color\n\tlightning.set_lifetime(LIGHTNING_VISUAL_LIFETIME)\n\n\nfunc _update_normal(delta: float):\n\tif _collision_enabled:\n\t\tvar destroyed_by_collision: bool = _collide_with_units()\n\n\t\tif destroyed_by_collision:\n\t\t\treturn\n\n\tif _range > 0:\n\t\tvar travel_vector: Vector2 = get_position_wc3_2d() - VectorUtils.vector3_to_vector2(_initial_pos)\n\t\tvar current_travel_distance: float = travel_vector.length()\n\t\tvar travel_complete: bool = current_travel_distance >= _range\n\n\t\tif travel_complete:\n\t\t\t_expire()\n\n\t\t\treturn\n\n\tif _is_homing:\n\t\t_turn_towards_target(delta)\n\t\t\n# \tApply rotation\n\tvar new_direction: float = _direction + _rotation\n\tset_direction(new_direction)\n\n# \tApply acceleration\n\tvar new_speed: float = _speed + _acceleration * delta\n\tset_speed(new_speed)\n\n#\tMove forward, based on current direction\n\tvar move_vector: Vector2 = (Vector2(1, 0) * _speed * delta).rotated(deg_to_rad(_direction))\n\tvar new_position_2d: Vector2 = get_position_wc3_2d() + move_vector\n\tset_position_wc3_2d(new_position_2d)\n\t\n#\tChange z coordinate\n#\tNOTE: derive speed for changing z from angle of travel\n#\tvector. This way, target z will be reached roughly at\n#\tthe same time as target x and y.\n\tvar current_position: Vector3 = get_position_wc3()\n\tvar target_pos_is_defined: bool = _target_pos != Vector3.INF\n\tvar should_update_z_to_match_target_z: bool = target_pos_is_defined && !_ignore_target_z\n\n\tif _physics_enabled:\n\t\t_physics_z_speed = clampf(_physics_z_speed - _gravity, -Constants.PROJECTILE_SPEED_MAX, Constants.PROJECTILE_SPEED_MAX)\n\n\t\tvar new_z: float = clampf(get_z() + _physics_z_speed, 0, 10000)\n\t\tset_z(new_z)\n\n\t\tvar reached_ground: bool = new_z == 0\n\n\t\tif reached_ground:\n\t\t\tif _impact_handler.is_valid():\n\t\t\t\t_impact_handler.call(self)\n\n\t\t\t_cleanup()\n\n\t\t\treturn\n\telif should_update_z_to_match_target_z:\n\t\tvar travel_vector: Vector3 = _target_pos - current_position\n\t\tvar travel_vector_flat: Vector3 = Vector3(travel_vector.x, travel_vector.y, 0)\n\t\tvar travel_angle_z: float = travel_vector.angle_to(travel_vector_flat)\n\t\tvar z_speed: float = get_speed() * sin(travel_angle_z)\n\t\tvar new_z: float = move_toward(get_z(), _target_pos.z, z_speed * delta)\n\t\tset_z(new_z)\n\n\tif _is_homing:\n#\t\tNOTE: contact distance prevents projectiles from\n#\t\tgoing past the target position during a tick and\n#\t\trubber-banding.\n# \n\t\tvar contact_distance: float = delta * _speed\n\t\tvar target_pos_2d: Vector2 = VectorUtils.vector3_to_vector2(_target_pos)\n\t\tvar reached_target = VectorUtils.in_range(target_pos_2d, get_position_wc3_2d(), contact_distance)\n\n\t\tif reached_target:\n#\t\t\tNOTE: finished handler will get called even if\n#\t\t\ttarget unit is dead and null. This is\n#\t\t\tintentional.\n\t\t\tif _target_hit_handler.is_valid():\n\t\t\t\t_target_hit_handler.call(self, _target_unit)\n\n#\t\t\tHandler can request projectile to not destroy\n#\t\t\titself. In that case do no explosion or cleanup.\n\t\t\tif _avert_destruct_requested:\n\t\t\t\t_avert_destruct_requested = false\n\n\t\t\t\treturn\n\n\t\t\tif _expire_when_homing_ends && _expiration_handler.is_valid():\n\t\t\t\t_expiration_handler.call(self)\n\n\t\t\tif _explode_on_hit:\n\t\t\t\t_do_explosion_visual()\n\n\t\t\t_cleanup()\n\n\nfunc _update_interpolated(delta: float):\n\tif _collision_enabled:\n\t\tvar destroyed_by_collision: bool = _collide_with_units()\n\n\t\tif destroyed_by_collision:\n\t\t\treturn\n\n\tif _interpolation_is_stopped:\n\t\treturn\n\n\t_interpolation_progress += _speed * delta\n\n\tvar travel_vector: Vector3 = _target_pos - _interpolation_start\n\tvar travel_vector_2d: Vector2 = VectorUtils.vector3_to_vector2(travel_vector)\n\tvar travel_distance: float = travel_vector_2d.length()\n\tvar progress_ratio: float = Utils.divide_safe(_interpolation_progress, travel_distance, 1.0)\n\tprogress_ratio = clampf(progress_ratio, 0.0, 1.0)\n\tvar old_position_2d: Vector2 = get_position_wc3_2d()\n\t\t\n\tvar new_pos: Vector3\n\tif _bezier_is_enabled:\n\t\tnew_pos = _interpolation_start.bezier_interpolate(_bezier_control_1, _bezier_control_2, _target_pos, progress_ratio)\n\telse:\n\t\tnew_pos = _interpolation_start.lerp(_target_pos, progress_ratio)\n\t\tvar z_arc_value: float = _interpolation_z_arc_height * progress_ratio * (1 - progress_ratio) * 4\n\t\tnew_pos.z += z_arc_value\n\n\tset_position_wc3(new_pos)\n\n#\tNOTE: save direction so it can be accessed by users of\n#\tprojectile via get_direction(). Note that unlike normal\n#\tprojectiles, interpolated projectiles don't actually use\n#\tdirection for movement logic.\n\tvar new_pos_2d: Vector2 = get_position_wc3_2d()\n\tvar move_vector: Vector2 = new_pos_2d - old_position_2d\n\t_direction = rad_to_deg(move_vector.angle())\n\n\tvar reached_target: float = progress_ratio == 1.0\n\n\tif reached_target:\n#\t\tNOTE: need to set _interpolation_is_stopped flag to\n#\t\ttrue here so that we can detect if it got changed by\n#\t\tthe \"finished\" handler\n\t\t_interpolation_is_stopped = true\n\n#\t\tNOTE: finished handler will get called even if\n#\t\ttarget unit is dead and null. This is intentional.\n\t\tif _interpolation_finished_handler.is_valid():\n\t\t\t_interpolation_finished_handler.call(self, _target_unit)\n\n#\t\tHandler can request projectile to not destroy\n#\t\titself. In that case do no explosion or cleanup.\n\t\tif _avert_destruct_requested:\n\t\t\t_avert_destruct_requested = false\n\n#\t\t\tNOTE: only stop interpolation here if\n#\t\t\t_interpolation_is_stopped is still true. If it\n#\t\t\tis false, then it got changed by the code inside\n#\t\t\t\"finished\" handler, which happens when\n#\t\t\t\"finished\" handler starts a new interpolation\n#\t\t\tafter averting destruction.\n\t\t\tif _interpolation_is_stopped:\n\t\t\t\tstop_interpolation()\n\n\t\t\treturn\n\n\t\tif _explode_on_hit:\n\t\t\t_do_explosion_visual()\n\n\t\t_cleanup()\n\n\n# Returns true if projectile expired because of a collision\nfunc _collide_with_units() -> bool:\n\tvar units_in_range: Array[Unit] = Utils.get_units_in_range(_caster, _collision_target_type, get_position_wc3_2d(), _collision_radius)\n\n# \tRemove units that have already collided. This way, we\n# \tcollide only once per unit.\n\tfor unit in _collision_history:\n\t\tif !Utils.unit_is_valid(unit):\n\t\t\tcontinue\n\n\t\tunits_in_range.erase(unit)\n\n\tvar collided_list: Array = units_in_range\n\n\tfor unit in collided_list:\n\t\tif _collision_handler.is_valid():\n\t\t\t_collision_handler.call(self, unit)\n\n\t\t_collision_history.append(unit)\n\n\t\tif _destroy_on_collision:\n\t\t\t_cleanup()\n\n\t\t\treturn true\n\n\treturn false\n\n\n# Homing behavior is implemented here. If target pos or\n# target unit is defined, the projectile will turn to face\n# towards it.\nfunc _turn_towards_target(delta: float):\n\tvar turn_instantly: float = _homing_control_value == 0\n\tvar target_pos_2d: Vector2 = VectorUtils.vector3_to_vector2(_target_pos)\n\tvar projectile_pos: Vector2 = get_position_wc3_2d()\n\tvar desired_direction_vector: Vector2 = target_pos_2d - projectile_pos\n\tvar desired_direction: float = rad_to_deg(desired_direction_vector.angle())\n\n\tif turn_instantly:\n\t\tset_direction(desired_direction)\n\n\t\treturn\n\n\tvar current_direction_vector: Vector2 = Vector2.from_angle(deg_to_rad(_direction))\n\tvar direction_diff: float = rad_to_deg(current_direction_vector.angle_to(desired_direction_vector))\n\tvar turn_amount: float = sign(direction_diff) * min(rad_to_deg(_homing_control_value) * delta, abs(direction_diff))\n\tvar new_direction: float = _direction + turn_amount\n\t\n\tset_direction(new_direction)\n\n\nfunc _expire():\n\tif _expiration_handler.is_valid():\n\t\t_expiration_handler.call(self)\n\n\tif _explode_on_expiration:\n\t\t_do_explosion_visual()\n\n\t_cleanup()\n\n\n# NOTE: angle should be in degrees. Normalizes the angle to\n# [-180, 180] range to match convention used by Vector2\n# functions. For example, 220 would be converted to -140.\nfunc _normalize_angle(angle: float) -> float:\n\tvar normalized_angle: float\n\tif angle > 180:\n\t\tnormalized_angle = angle - 360\n\telif angle < -180:\n\t\tnormalized_angle = angle + 360\n\telse:\n\t\tnormalized_angle = angle\n\n\treturn normalized_angle\n\n\nfunc _start_movement_normal(target_pos: Vector3, ignore_z: bool, expire_when_reached: bool):\n\t_target_pos = target_pos\n\t_ignore_target_z = ignore_z\n\n\tvar target_pos_2d: Vector2 = VectorUtils.vector3_to_vector2(_target_pos)\n\tvar from_pos_2d: Vector2 = get_position_wc3_2d()\n\tvar angle_to_target_pos: float = from_pos_2d.angle_to_point(target_pos_2d)\n\tvar initial_direction: float = rad_to_deg(angle_to_target_pos)\n\tset_direction(initial_direction)\n\n\tif _is_homing:\n\t\t_expire_when_homing_ends = expire_when_reached\n\n\t# NOTE: only setup the expire timer if project is NOT\n\t# homing. Because if it's homing, then it's not possible\n\t# to estimate the travel time for a moving target.\n\tif expire_when_reached && !_is_homing:\n\t\tvar travel_vector: Vector2 = target_pos_2d - from_pos_2d\n\t\tvar travel_distance: float = travel_vector.length()\n\t\tvar time_until_reached: float = Utils.divide_safe(travel_distance, get_speed(), 1.0)\n\t\tset_remaining_lifetime(time_until_reached)\n\n\n# NOTE: before this f-n is called, projectile must be added\n# to world and have a valid position\nfunc _start_movement_interpolated(target_pos: Vector3, z_arc: float):\n\t_target_pos = target_pos\n\n\tvar from_pos: Vector3 = get_position_wc3()\n\t_interpolation_start = from_pos\n\t_interpolation_progress = 0\n\t_interpolation_is_stopped = false\n\n\tvar travel_vector: Vector3 = _target_pos - from_pos\n\tvar travel_distance: float = travel_vector.length()\n\t_interpolation_z_arc_height = travel_distance * z_arc\n\n\nfunc _start_movement_bezier_interpolated(target_pos: Vector3, z_arc: float, side_arc: float, steepness: float):\n\t_target_pos = target_pos\n\n\tvar from_pos: Vector3 = get_position_wc3()\n\t_interpolation_start = from_pos\n\t_interpolation_progress = 0\n\t_interpolation_is_stopped = false\n\t_bezier_is_enabled = true\n\n\tvar travel_vector: Vector3 = _target_pos - from_pos\n\tvar travel_distance: float = travel_vector.length()\n\n\tvar dx: float = _target_pos.x - from_pos.x\n\tvar dy: float = _target_pos.y - from_pos.y\n\tvar dz: float = _target_pos.z - from_pos.z\n\n\tvar control1_ratio: float = 0.5 - steepness\n\t_bezier_control_1.x = from_pos.x + control1_ratio * dx + side_arc * dy \n\t_bezier_control_1.y = from_pos.y + control1_ratio * dy + side_arc * dx \n\t_bezier_control_1.z = from_pos.z + control1_ratio * dz + z_arc * travel_distance \n\n\tvar control2_ratio: float = 0.5 + steepness\n\t_bezier_control_2.x = from_pos.x + control2_ratio * dx + side_arc * dy \n\t_bezier_control_2.y = from_pos.y + control2_ratio * dy + side_arc * dx \n\t_bezier_control_2.z = from_pos.z + control2_ratio * dz + z_arc * travel_distance \n\n\nfunc _do_explosion_visual():\n\t# NOTE: if projectile is hidden, also don't display\n\t# explosion visual\n\tif !visible:\n\t\treturn\n\n\tif _explosion_art.is_empty():\n\t\treturn\n\n\tif _target_unit != null:\n\t\tEffect.create_simple_at_unit(_explosion_art, _target_unit)\n\telse:\n\t\tvar explosion_pos: Vector3 = get_position_wc3()\n\t\tEffect.create_animated(_explosion_art, explosion_pos, 0)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_periodic_timer_timeout():\n\tif !_periodic_enabled:\n\t\treturn\n\n\tif _periodic_handler.is_valid():\n\t\t_periodic_handler.call(self)\n\n\nfunc _on_target_tree_exited():\n\tif _target_unit == null:\n\t\treturn\n\n\t_target_pos = _target_unit.get_position_wc3() + UNIT_Z_OFFSET\n\t_target_unit.tree_exited.disconnect(_on_target_tree_exited)\n\t_target_unit = null\n\n\nfunc _on_projectile_type_tree_exited():\n\t_cleanup()\n\n\nfunc _on_lifetime_timer_timeout():\n\t_expire()\n\n\n#########################\n### Setters / Getters ###\n#########################\n\n# NOTE: getHomingTarget() in JASS\nfunc get_target() -> Unit:\n\treturn _target_unit\n\n\n# NOTE: projectile.setScale() in JASS\nfunc set_projectile_scale(value: float):\n\t_visual_node.scale = Vector2.ONE * value\n\n\nfunc get_tower_crit_count() -> int:\n\treturn _tower_crit_count\n\n\nfunc set_tower_crit_count(tower_crit_count: int):\n\t_tower_crit_count = tower_crit_count\n\n\nfunc get_tower_crit_ratio() -> float:\n\treturn _tower_crit_ratio\n\n\nfunc set_tower_crit_ratio(tower_crit_ratio: float):\n\t_tower_crit_ratio = tower_crit_ratio\n\n\nfunc get_tower_bounce_visited_list() -> Array[Unit]:\n\treturn _tower_bounce_visited_list\n\n\n# Returns current direction of projectile's movement. In\n# degrees and from top down perspective.\n# NOTE: projectile.direction in JASS\nfunc get_direction() -> float:\n\treturn _direction\n\n\n# Sets direction of projectile. In degrees and top down\n# perspective.\n# NOTE: this f-n must be used instead of modifying the value\n# directly. This is to ensure that direction is always\n# normalized.\nfunc set_direction(direction: float):\n\t_direction = _normalize_angle(direction)\n\n\nfunc get_speed() -> float:\n\treturn _speed\n\n\nfunc set_speed(new_speed: float):\n\t_speed = clampf(new_speed, 0, Constants.PROJECTILE_SPEED_MAX)\n\n\nfunc set_acceleration(new_acceleration: float):\n\t_acceleration = new_acceleration\n\n\n# Changes the rate of change of projectile's rotation.\n# This value is defined in degrees/tick, 30ticks/second.\nfunc set_projectile_rotation(value: float):\n\t_rotation = value\n\n\nfunc set_gravity(value: float):\n\t_gravity = value\n\n\n# NOTE: if new target is null, then homing is disabled\nfunc set_homing_target(new_target: Unit):\n\tvar old_target: Unit = _target_unit\n\n\tif Utils.unit_is_valid(old_target) && old_target.tree_exited.is_connected(_on_target_tree_exited):\n\t\told_target.tree_exited.disconnect(_on_target_tree_exited)\n\n\tif new_target != null:\n#\t\tNOTE: need to check that target is valid because\n#\t\tprojectile may be launched towards a dead target.\n#\t\tFor example if some other part of tower script\n#\t\tkilled the target right before projectile was\n#\t\tcreated. In such cases, projectile will move to the\n#\t\tposition where target was during death.\n\t\tif Utils.unit_is_valid(new_target):\n\t\t\tif !new_target.tree_exited.is_connected(_on_target_tree_exited):\n\t\t\t\tnew_target.tree_exited.connect(_on_target_tree_exited)\n\n\t\t\t_target_unit = new_target\n\t\telse:\n\t\t\t_target_unit = null\n\t\t\t_target_pos = new_target.get_position_wc3() + UNIT_Z_OFFSET\n\n\t\t_is_homing = true\n\telse:\n\t\t_target_unit = null\n\t\t_target_pos = Vector3.ZERO\n\t\t_is_homing = false\n\n\n# NOTE: setCollisionEnabled() in JASS\nfunc set_collision_enabled(enabled: bool):\n\t_collision_enabled = enabled\n\n\nfunc set_remaining_lifetime(new_lifetime: float):\n\tif is_inside_tree():\n\t\t_lifetime_timer.stop()\n\t\t_lifetime_timer.start(new_lifetime)\n\telse:\n\t\t_lifetime_timer.autostart = true\n\t\t_lifetime_timer.wait_time = new_lifetime\n\n\nfunc set_color(color: Color):\n\tmodulate = color\n\n\n# Returns time in seconds passed since projectile spawned.\nfunc get_age() -> float:\n\tvar current_time: float = Utils.get_time()\n\tvar age: float = current_time - _spawn_time\n\n\treturn age\n\n\nfunc get_uid() -> int:\n\treturn _uid\n\n\n#########################\n###       Static      ###\n#########################\n\n# NOTE: Projectile.createFromUnit() in JASS\nstatic func create_from_unit(type: ProjectileType, caster: Unit, from: Unit, facing: float, damage_ratio: float, crit_ratio: float) -> Projectile:\n\tvar pos: Vector3 = from.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, pos, facing)\n\t\n\treturn projectile\n\n\n# NOTE: Projectile.createFromPointToPoint() in JASS\nstatic func create_from_point_to_point(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_pos: Vector3, target_pos: Vector3, ignore_target_z: bool, expire_when_reached: bool) -> Projectile:\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.aim_at_point(target_pos, ignore_target_z, expire_when_reached)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createFromUnitToPoint() in JASS\nstatic func create_from_unit_to_point(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_unit: Unit, target_pos: Vector3, ignore_target_z: bool, expire_when_reached: bool) -> Projectile:\n\tvar from_pos: Vector3 = from_unit.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.aim_at_point(target_pos, ignore_target_z, expire_when_reached)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createFromPointToUnit() in JASS\nstatic func create_from_point_to_unit(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_pos: Vector3, target_unit: Unit, targeted: bool, ignore_target_z: bool, expire_when_reached: bool) -> Projectile:\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.aim_at_unit(target_unit, targeted, ignore_target_z, expire_when_reached)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createFromUnitToUnit() in JASS\nstatic func create_from_unit_to_unit(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_unit: Unit, target_unit: Unit, targeted: bool, ignore_target_z: bool, expire_when_reached: bool) -> Projectile:\n\tvar from_pos: Vector3 = from_unit.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.aim_at_unit(target_unit, targeted, ignore_target_z, expire_when_reached)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createLinearInterpolationFromPointToPoint() in JASS\nstatic func create_linear_interpolation_from_point_to_point(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_pos: Vector3, target_pos: Vector3, z_arc: float) -> Projectile:\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.start_interpolation_to_point(target_pos, z_arc)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createLinearInterpolationFromPointToUnit() in JASS\nstatic func create_linear_interpolation_from_point_to_unit(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_pos: Vector3, target_unit: Unit, z_arc: float, targeted: bool) -> Projectile:\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.start_interpolation_to_unit(target_unit, z_arc, targeted)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createLinearInterpolationFromUnitToPoint() in JASS\nstatic func create_linear_interpolation_from_unit_to_point(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_unit: Unit, target_pos: Vector3, z_arc: float) -> Projectile:\n\tvar from_pos: Vector3 = from_unit.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.start_interpolation_to_point(target_pos, z_arc)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createLinearInterpolationFromUnitToUnit() in JASS\nstatic func create_linear_interpolation_from_unit_to_unit(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_unit: Unit, target_unit: Unit, z_arc: float, targeted: bool) -> Projectile:\n\tvar from_pos: Vector3 = from_unit.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.start_interpolation_to_unit(target_unit, z_arc, targeted)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createBezierInterpolationFromUnitToUnit() in JASS\nstatic func create_bezier_interpolation_from_unit_to_unit(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_unit: Unit, target_unit: Unit, z_arc: float, side_arc: float, steepness: float, targeted: bool) -> Projectile:\n\tvar from_pos: Vector3 = from_unit.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.start_bezier_interpolation_to_unit(target_unit, z_arc, side_arc, steepness, targeted)\n\n\treturn projectile\n\n\n# NOTE: Projectile.createBezierInterpolationFromUnitToPoint() in JASS\nstatic func create_bezier_interpolation_from_unit_to_point(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, from_unit: Unit, target_pos: Vector3, z_arc: float, side_arc: float, steepness: float) -> Projectile:\n\tvar from_pos: Vector3 = from_unit.get_position_wc3() + UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create(type, caster, damage_ratio, crit_ratio, from_pos, 0)\n\tprojectile.start_bezier_interpolation_to_point(target_pos, z_arc, side_arc, steepness)\n\n\treturn projectile\n\n\n# NOTE: Projectile.create() in JASS\nstatic func create(type: ProjectileType, caster: Unit, damage_ratio: float, crit_ratio: float, initial_pos: Vector3, facing: float) -> Projectile:\n\tvar projectile: Projectile = Preloads.projectile_scene.instantiate()\n\n\tprojectile.set_speed(type._speed)\n\tprojectile._acceleration = type._acceleration\n\tprojectile._rotation = type._start_rotation\n\tprojectile._gravity = type._gravity\n\tprojectile._physics_z_speed = type._initial_z_speed\n\tprojectile._physics_enabled = type._physics_enabled\n\tprojectile._explode_on_hit = type._explode_on_hit\n\tprojectile._explode_on_expiration = type._explode_on_expiration\n\tprojectile._move_type = type._move_type\n\tprojectile._homing_control_value = type._homing_control_value\n\n\tprojectile._cleanup_handler = type._cleanup_handler\n\tprojectile._interpolation_finished_handler = type._interpolation_finished_handler\n\tprojectile._target_hit_handler = type._target_hit_handler\n\tprojectile._collision_handler = type._collision_handler\n\tprojectile._expiration_handler = type._expiration_handler\n\tprojectile._impact_handler = type._impact_handler\n\tprojectile._range = type._range\n\tprojectile._collision_radius = type._collision_radius\n\tprojectile._collision_target_type = type._collision_target_type\n\tprojectile._destroy_on_collision = type._destroy_on_collision\n\tprojectile._damage_bonus_to_size_map = type._damage_bonus_to_size_map\n\tprojectile._use_lightning_visual = type._use_lightning_visual\n\n\tvar periodic_handler_is_defined: bool = type._periodic_handler.is_valid() && type._periodic_handler_period > 0\n\tif periodic_handler_is_defined:\n\t\tprojectile._periodic_handler = type._periodic_handler\n\t\tvar timer: ManualTimer = ManualTimer.new()\n\t\tprojectile._periodic_timer = timer\n\t\ttimer.wait_time = type._periodic_handler_period\n\t\ttimer.autostart = true\n\t\ttimer.timeout.connect(projectile._on_periodic_timer_timeout)\n\t\tprojectile.add_child(timer)\n\n\tprojectile._damage_ratio = damage_ratio\n\tprojectile._crit_ratio = crit_ratio\n\tprojectile._caster = caster\n\tprojectile.set_position_wc3(initial_pos)\n\tprojectile._initial_pos = initial_pos\n\tprojectile._visual_path = type._visual_path\n\tprojectile._explosion_art = type._explosion_art\n\n\tprojectile.set_direction(facing)\n\n\tif type._lifetime > 0:\n\t\tprojectile.set_remaining_lifetime(type._lifetime)\n\n\ttype.tree_exited.connect(projectile._on_projectile_type_tree_exited)\n\n\tUtils.add_object_to_world(projectile)\n\n\tvar projectile_density: float = Settings.get_setting(Settings.PROJECTILE_DENSITY)\n\tvar projectile_should_be_visible: bool = Utils.rand_chance(Globals.local_rng, projectile_density)\n\tprojectile.visible = projectile_should_be_visible\n\n\treturn projectile\n"
  },
  {
    "path": "src/projectiles/projectile.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bdibpipbjyshb\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://by01sg1a1yihc\" path=\"res://src/unit/dummy_unit.tscn\" id=\"1_fkawk\"]\n[ext_resource type=\"Script\" path=\"res://src/projectiles/projectile.gd\" id=\"2_xv7xk\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"4_o28ps\"]\n\n[node name=\"Projectile\" node_paths=PackedStringArray(\"_lifetime_timer\", \"_visual_node\") groups=[\"projectiles\"] instance=ExtResource(\"1_fkawk\")]\nz_index = 100\nscript = ExtResource(\"2_xv7xk\")\n_lifetime_timer = NodePath(\"LifetimeTimer\")\n_visual_node = NodePath(\"Visual\")\n\n[node name=\"Visual\" type=\"Node2D\" parent=\".\" index=\"0\"]\n\n[node name=\"LifetimeTimer\" type=\"Node\" parent=\".\" index=\"1\"]\nscript = ExtResource(\"4_o28ps\")\n\n[connection signal=\"timeout\" from=\"LifetimeTimer\" to=\".\" method=\"_on_lifetime_timer_timeout\"]\n"
  },
  {
    "path": "src/projectiles/projectile_type.gd",
    "content": "class_name ProjectileType extends Node\n\nvar _move_type: Projectile.MoveType\nvar _speed: float\nvar _acceleration: float = 0.0\nvar _gravity: float = 1.0\nvar _initial_z_speed: float = 0.0\nvar _homing_control_value: float\nvar _range: float = 0.0\nvar _lifetime: float = 0.0\nvar _visual_path: String = \"\"\nvar _explosion_art: String = \"\"\nvar _explode_on_hit: bool = true\nvar _explode_on_expiration: bool = true\nvar _cleanup_handler: Callable = Callable()\nvar _interpolation_finished_handler: Callable = Callable()\nvar _target_hit_handler: Callable = Callable()\nvar _periodic_handler: Callable = Callable()\nvar _impact_handler: Callable = Callable()\nvar _periodic_handler_period: float = 0.0\nvar _expiration_handler: Callable = Callable()\nvar _collision_radius: float = 0.0\nvar _collision_target_type: TargetType = null\nvar _destroy_on_collision: bool = false\nvar _collision_handler: Callable = Callable()\nvar _damage_bonus_to_size_map: Dictionary = {}\nvar _physics_enabled: bool = false\nvar _use_lightning_visual: bool = false\nvar _start_rotation: float = 0.0\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init():\n\t#\tNOTE: fix \"unused\" warning\n\t_damage_bonus_to_size_map = _damage_bonus_to_size_map\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_explosion_art(path: String):\n\t_explosion_art = path\n\n\n# Sets the rate of change for projectile's duration, in\n# degrees/tick, 30ticks/second.\n# NOTE: \"ProjectileType.setStartRotation()\" in JASS\nfunc set_start_rotation(value: float):\n\t_start_rotation = value\n\n\nfunc set_speed(value: float):\n\t_speed = value\n\n\n# Makes projectile use lightning visual instead of the\n# visual scene passed to constructor.\n# NOTE: works only for interpolated projectiles.\nfunc switch_to_lightning_visual():\n\t_use_lightning_visual = true\n\n\n# projectileType.disableExplodeOnHit() in JASS\nfunc disable_explode_on_hit():\n\t_explode_on_hit = false\n\n\n# projectileType.disableExplodeOnExpiration() in JASS\nfunc disable_explode_on_expiration():\n\t_explode_on_expiration = false\n\n\n# projectileType.enableCollision() in JASS\nfunc enable_collision(handler: Callable, radius: float, target_type: TargetType, destroy_on_collision: bool):\n\t_collision_handler = handler\n\t_collision_radius = radius\n\t_collision_target_type = target_type\n\t_destroy_on_collision = destroy_on_collision\n\n\n# \"homing_control_value\" determines how fast the projectile\n# will turn towards the homing target. This value is in\n# degrees per second. If you set homing_control_value it too\n# low, then the projectile can miss the target!\n# \n# Set homing_control_value to 0 to make the projectile turn\n# instantly towards the target.\n# \n# NOTE: target hit handler will still get called if target\n# died. In that case, target argument will be null so you\n# need to do a null check if you use the target.\n# \n# projectileType.enableHoming() in JASS\nfunc enable_homing(target_hit_handler: Callable, homing_control_value: float):\n\t_target_hit_handler = target_hit_handler\n\t_homing_control_value = homing_control_value\n\n\n# NOTE: enablePhysics() in original youtd API also supported\n# \"bouncing\" but none of the tower scripts use bounce\n# feature so didn't implement it.\n# NOTE: projectileType.enablePhysics() in JASS\nfunc enable_physics(impact_handler: Callable, initial_z_speed: float):\n\t_physics_enabled = true\n\t_impact_handler = impact_handler\n\t_initial_z_speed = initial_z_speed\n\n\n# Example handler:\n# func periodic_handler(p: Projectile)\n# NOTE: projectileType.enable_periodic() in JASS\nfunc enable_periodic(handler: Callable, period: float):\n\t_periodic_handler = handler\n\t_periodic_handler_period = period\n\n\n#########################\n### Setters / Getters ###\n#########################\n\n# Example handler:\n# func on_cleanup(projectile: Projectile)\n# projectileType.setEventOnCleanup() in JASS\nfunc set_event_on_cleanup(handler: Callable):\n\t_cleanup_handler = handler\n\n\n# NOTE: finished handler will still get called if target\n# died. In that case, target argument will be null so you\n# need to do a null check if you use the target.\n# \n# Example handler:\n# func on_interpolation_finished(projectile: Projectile, target: Unit)\n# projectileType.setEventOnInterpolationFinished() in JASS\nfunc set_event_on_interpolation_finished(handler: Callable):\n\t_interpolation_finished_handler = handler\n\n\n# This handler will be called when projectile's lifetime\n# timer expires or when projectile travels for the defined\n# range.\n# Example handler:\n# func on_expiration(projectile: Projectile)\n# projectileType.setEventOnExpiration() in JASS\nfunc set_event_on_expiration(handler: Callable):\n\t_expiration_handler = handler\n\n\n# projectileType.setAcceleration() in JASS\nfunc set_acceleration(value: float):\n\t_acceleration = value\n\n\n# projectileType.setGravity() in JASS\nfunc set_gravity(value: float):\n\t_gravity = value\n\n\n# NOTE: DamageTable.setBonusToSize() in JASS\nfunc set_bonus_to_size(creep_size: CreepSize.enm, bonus: float):\n\t_damage_bonus_to_size_map[creep_size] = bonus\n\n\n#########################\n###       Static      ###\n#########################\n\n# ProjectileType.create() in JASS\nstatic func create(model: String, lifetime: float, speed: float, parent: Node) -> ProjectileType:\n\tvar pt: ProjectileType = ProjectileType.new()\n\tpt._move_type = Projectile.MoveType.NORMAL\n\tpt._speed = speed\n\tpt._lifetime = lifetime\n\tpt._visual_path = model\n\tparent.add_child(pt)\n\t\n\treturn pt\n\n\n# ProjectileType.createInterpolate() in JASS\nstatic func create_interpolate(model: String, speed: float, parent: Node) -> ProjectileType:\n\tvar pt: ProjectileType = ProjectileType.new()\n\tpt._move_type = Projectile.MoveType.INTERPOLATED\n\tpt._speed = speed\n\tpt._visual_path = model\n\tparent.add_child(pt)\n\n\treturn pt\n\n\n# Creates a projectile that will travel for a max of\n# range from initial position.\n# ProjectileType.createRanged() in JASS\nstatic func create_ranged(model: String, the_range: float, speed: float, parent: Node) -> ProjectileType:\n\tvar pt: ProjectileType = ProjectileType.new()\n\tpt._move_type = Projectile.MoveType.NORMAL\n\tpt._speed = speed\n\tpt._range = the_range\n\tpt._visual_path = model\n\tparent.add_child(pt)\n\t\n\treturn pt\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/ball_lightning_projectile.tscn",
    "content": "[gd_scene load_steps=21 format=3 uid=\"uid://bp0yq6h8y1fpr\"]\n\n[ext_resource type=\"Script\" path=\"res://src/projectiles/projectile_visuals/default_projectile.gd\" id=\"1_ue3pq\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dsvu05xjwic5g\" path=\"res://assets/effects/bdragon/purge_buff_target_195.png\" id=\"2_pqld0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bseim\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(0, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5c7jd\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(64, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n81s5\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(128, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_20pis\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(192, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e8vh7\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(256, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wm3vs\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0g1x8\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(384, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s61us\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(448, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s0xxf\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(512, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ldh17\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(576, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wvdyb\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(640, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_881du\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(704, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jsj1i\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(768, 128, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kbt3t\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(832, 128, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_mxonc\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bseim\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_5c7jd\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_n81s5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_20pis\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_e8vh7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wm3vs\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_0g1x8\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s61us\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s0xxf\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_ldh17\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_wvdyb\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_881du\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_jsj1i\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_kbt3t\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 20.0\n}]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_53xhx\"]\natlas = ExtResource(\"2_pqld0\")\nregion = Rect2(320, 128, 64, 64)\n\n[sub_resource type=\"Curve\" id=\"Curve_rkf74\"]\nmin_value = -200.0\nmax_value = 200.0\n_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.533708, 182.418), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0]\npoint_count = 3\n\n[sub_resource type=\"Gradient\" id=\"Gradient_pdi52\"]\ncolors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)\n\n[node name=\"BallLightningProjectile\" type=\"Node2D\"]\nscript = ExtResource(\"1_ue3pq\")\n\n[node name=\"AnimatedSprite2D\" type=\"AnimatedSprite2D\" parent=\".\"]\nsprite_frames = SubResource(\"SpriteFrames_mxonc\")\n\n[node name=\"CPUParticles2D\" type=\"CPUParticles2D\" parent=\".\"]\nlifetime = 0.1\ntexture = SubResource(\"AtlasTexture_53xhx\")\ngravity = Vector2(0, 0)\nradial_accel_curve = SubResource(\"Curve_rkf74\")\nscale_amount_min = 0.8\nscale_amount_max = 0.9\ncolor_ramp = SubResource(\"Gradient_pdi52\")\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/default_projectile.gd",
    "content": "extends Node2D\n\n# Rotate projectile so it looks more dynamic\nfunc _process(delta):\n\trotate(20.0 * delta)\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/default_projectile.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://ceephrn4p3nbi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cifmqgyviomde\" path=\"res://assets/misc/projectile.png\" id=\"1_ie6oa\"]\n[ext_resource type=\"Script\" path=\"res://src/projectiles/projectile_visuals/default_projectile.gd\" id=\"2_d2l1y\"]\n\n[sub_resource type=\"Gradient\" id=\"Gradient_pdi52\"]\ncolors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)\n\n[node name=\"DefaultProjectile\" type=\"Node2D\"]\nscale = Vector2(1.5, 1.5)\nscript = ExtResource(\"2_d2l1y\")\n\n[node name=\"Sprite2D\" type=\"Sprite2D\" parent=\".\"]\ntexture = ExtResource(\"1_ie6oa\")\n\n[node name=\"CPUParticles2D\" type=\"CPUParticles2D\" parent=\".\"]\nlifetime = 0.1\ntexture = ExtResource(\"1_ie6oa\")\ngravity = Vector2(0, 0)\ncolor_ramp = SubResource(\"Gradient_pdi52\")\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/energy_ball.tscn",
    "content": "[gd_scene load_steps=8 format=3 uid=\"uid://c24kk0jdlwm2v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b01ug8hkohe4a\" path=\"res://assets/effects/bdragon/mana_shield_026.png\" id=\"1_3yfyf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_l8xak\"]\natlas = ExtResource(\"1_3yfyf\")\nregion = Rect2(320, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_70doe\"]\natlas = ExtResource(\"1_3yfyf\")\nregion = Rect2(384, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xa56r\"]\natlas = ExtResource(\"1_3yfyf\")\nregion = Rect2(448, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s7ak5\"]\natlas = ExtResource(\"1_3yfyf\")\nregion = Rect2(512, 320, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bp1xw\"]\natlas = ExtResource(\"1_3yfyf\")\nregion = Rect2(192, 320, 64, 64)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_bhmsy\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_l8xak\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_70doe\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_xa56r\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_s7ak5\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_bp1xw\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 10.0\n}]\n\n[node name=\"EnergyBall\" type=\"Node2D\"]\n\n[node name=\"AnimatedSprite2D\" type=\"AnimatedSprite2D\" parent=\".\"]\nmodulate = Color(0.486275, 1, 1, 1)\nsprite_frames = SubResource(\"SpriteFrames_bhmsy\")\nframe_progress = 0.670588\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/flying_pork.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://250046jfagk3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bvgyvbj1s7jc7\" path=\"res://resources/icons/food/pork_without_plate.tres\" id=\"1_kkgpb\"]\n\n[node name=\"flying_pork\" type=\"Node2D\"]\n\n[node name=\"Sprite2D\" type=\"Sprite2D\" parent=\".\"]\nscale = Vector2(0.6, 0.6)\ntexture = ExtResource(\"1_kkgpb\")\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/omnislasher_mirror_image.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bkmfctakea8qe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_rd0ul\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1t213\"]\natlas = ExtResource(\"1_rd0ul\")\nregion = Rect2(38, 277, 174, 229)\n\n[sub_resource type=\"Gradient\" id=\"Gradient_4ewt2\"]\ncolors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)\n\n[node name=\"OmnislasherMirrorImage\" type=\"Node2D\"]\n\n[node name=\"CPUParticles2D\" type=\"CPUParticles2D\" parent=\".\"]\nposition = Vector2(-10, -60)\nlifetime = 0.1\ntexture = SubResource(\"AtlasTexture_1t213\")\ngravity = Vector2(0, 0)\nscale_amount_min = 0.9\nscale_amount_max = 0.9\ncolor_ramp = SubResource(\"Gradient_4ewt2\")\n"
  },
  {
    "path": "src/projectiles/projectile_visuals/quillspray_projectile.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://dw3ls6usukieu\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://ceephrn4p3nbi\" path=\"res://src/projectiles/projectile_visuals/default_projectile.tscn\" id=\"1_yocls\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cknypfqkfkgiq\" path=\"res://assets/effects/bdragon/quillspray_747.png\" id=\"2_dopv7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jqlyj\"]\natlas = ExtResource(\"2_dopv7\")\nregion = Rect2(64, 256, 64, 64)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xymab\"]\natlas = ExtResource(\"2_dopv7\")\nregion = Rect2(64, 256, 64, 64)\n\n[node name=\"DefaultProjectile\" instance=ExtResource(\"1_yocls\")]\n\n[node name=\"Sprite2D\" parent=\".\" index=\"0\"]\ntexture = SubResource(\"AtlasTexture_jqlyj\")\n\n[node name=\"CPUParticles2D\" parent=\".\" index=\"1\"]\ntexture = SubResource(\"AtlasTexture_xymab\")\n"
  },
  {
    "path": "src/singletons/README.md",
    "content": "This folder contains singletons. Note that all of the singletons need to be included in the \"auto-load\" system of godot.\n"
  },
  {
    "path": "src/singletons/button_sounds.gd",
    "content": "extends Node\n\n\n# This class playes a SFX when any button is clicked.\n\n\nfunc _enter_tree() -> void:\n\tget_tree().node_added.connect(_on_node_added)\n\n\nfunc _on_node_added(node:Node) -> void:\n\tif node is Button:\n\t\tnode.pressed.connect(_on_button_pressed)\n\n\n# TODO: decide on a good SFX\nfunc _on_button_pressed() -> void:\n\treturn\n\t# SFX.play_sfx(SfxPaths.PRESS_BUTTON, 0, randf_range(0.9, 1.1))\n"
  },
  {
    "path": "src/singletons/combat_log.gd",
    "content": "extends Node\n\n\n# Global access to CombatLogStorage node. Game code uses\n# log_x() to add a log entry and then CombatLogWindow\n# displays log entries ingame.\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc log_damage(caster: Unit, target: Unit, damage_source: Unit.DamageSource, damage: float, crit_count: int):\n\tvar entry: CombatLogStorage.DamageEntry = CombatLogStorage.DamageEntry.new(caster, target, damage_source, damage, crit_count)\n\t_log_internal(entry)\n\n\nfunc log_kill(caster: Unit, target: Unit):\n\tvar entry: CombatLogStorage.KillEntry = CombatLogStorage.KillEntry.new(caster, target)\n\t_log_internal(entry)\n\n\nfunc log_experience(unit: Unit, experience: float):\n\tvar entry: CombatLogStorage.ExpEntry = CombatLogStorage.ExpEntry.new(unit, experience)\n\t_log_internal(entry)\n\n\nfunc log_buff_apply(caster: Unit, target: Unit, buff: Buff):\n\tvar entry: CombatLogStorage.BuffApplyEntry = CombatLogStorage.BuffApplyEntry.new(caster, target, buff)\n\t_log_internal(entry)\n\n\n# NOTE: this is an optinal log f-n for logging custom tower abilities.\n# For example, if you tower has a chance on attack to deal extra damage,\n# you may use log_ability() to display this in combat log.\n# NOTE: target arg may be null\nfunc log_ability(caster: Unit, target: Unit, ability: String):\n\tvar entry: CombatLogStorage.AbilityEntry = CombatLogStorage.AbilityEntry.new(caster, target, ability)\n\t_log_internal(entry)\n\n\n# NOTE: target arg may be null\nfunc log_item_ability(item: Item, target: Unit, ability: String):\n\tvar entry: CombatLogStorage.ItemAbilityEntry = CombatLogStorage.ItemAbilityEntry.new(item, target, ability)\n\t_log_internal(entry)\n\n\n# NOTE: target arg may be null\nfunc log_autocast(caster: Unit, target: Unit, autocast: Autocast):\n\tvar entry: CombatLogStorage.AutocastEntry = CombatLogStorage.AutocastEntry.new(caster, target, autocast)\n\t_log_internal(entry)\n\n\nfunc log_item_charge(item: Item, old_charge: int, new_charge: int):\n\tvar entry: CombatLogStorage.ItemChargeEntry = CombatLogStorage.ItemChargeEntry.new(item, old_charge, new_charge)\n\t_log_internal(entry)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _log_internal(entry: CombatLogStorage.Entry):\n\tvar combat_log_storage: Node = get_tree().get_root().get_node_or_null(\"GameScene/Gameplay/CombatLogStorage\")\n\n\tif combat_log_storage == null:\n\t\tpush_warning(\"CombatLogStorage is null. You can ignore this warning during game restart.\")\n\n\t\treturn\n\n\tcombat_log_storage.add_entry(entry)\n"
  },
  {
    "path": "src/singletons/config.gd",
    "content": "extends Node\n\n\n# A collection of config items that can be defined in\n# project.godot or override.cfg. Use override.cfg to locally\n# override a config value without commiting the value to the\n# repo.\n\n\nfunc cheat_gold() -> int:\n\treturn ProjectSettings.get_setting(\"application/config/cheat_gold\") as int\n\nfunc cheat_tomes() -> int:\n\treturn ProjectSettings.get_setting(\"application/config/cheat_tomes\") as int\n\n# Displays a godot icon texture on the location of a spell dummy.\nfunc visible_spell_dummys_enabled() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/visible_spell_dummys\") as bool\n\nfunc dev_controls_enabled() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/dev_controls\") as bool\n\n# A list of items which will be added to stash when game the\n# starts. Leave as empty \"[]\" to not add any items.\nfunc test_item_list() -> Array:\n\treturn ProjectSettings.get_setting(\"application/config/test_item_list\") as Array\n\n# Load all tower scenes on startup. Otherwise tower scenes\n# will be loaded when needed.\nfunc preload_all_towers_on_startup() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/preload_all_towers_on_startup\") as bool\n\nfunc build_version() -> String:\n\treturn ProjectSettings.get_setting(\"application/config/version\") as String\n\n# Enable to make creeps always drop items on death.\n# Normally, items drop rarely, depending on creep's and\n# caster's item chance stats.\nfunc always_drop_items() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/always_drop_items\") as bool\n\n# Makes the game ignore required wave level and element\n# level.\nfunc ignore_tower_requirements() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/ignore_tower_requirements\") as bool\n\n# Enable to be able to zoom camera in and out using the\n# touchpad.\nfunc enable_zoom_by_touchpad() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/enable_zoom_by_touchpad\") as bool\n\n# Enable to be able to zoom camera in and out using the\n# mousewheel.\nfunc enable_zoom_by_mousewheel() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/enable_zoom_by_mousewheel\") as bool\n\n# Enable to show position info label under mouse. Used for\n# debugging.\nfunc show_position_info_label() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/show_position_info_label\") as bool\n\n# Override wave specials so that all waves have these\n# specials. Can be a single special or a comma-separated\n# list.\nfunc override_wave_specials() -> Array[int]:\n\tvar array: Array = ProjectSettings.get_setting(\"application/config/override_wave_specials\") as Array\n\n\tvar result: Array[int] = []\n\tfor value in array:\n\t\tresult.append(value as int)\n\n\treturn result\n\n# Override health values for all creeps to a some value.\n# Leave at 0 to use normal health values.\nfunc override_creep_health() -> float:\n\treturn ProjectSettings.get_setting(\"application/config/override_creep_health\") as float\n\nfunc override_creep_size() -> String:\n\treturn ProjectSettings.get_setting(\"application/config/override_creep_size\") as String\n\nfunc override_creep_armor() -> String:\n\treturn ProjectSettings.get_setting(\"application/config/override_creep_armor\") as String\n\nfunc override_creep_race() -> String:\n\treturn ProjectSettings.get_setting(\"application/config/override_creep_race\") as String\n\nfunc cheat_food_cap() -> int:\n\treturn ProjectSettings.get_setting(\"application/config/cheat_food_cap\") as int\n\nfunc allow_transform_in_build_mode() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/allow_transform_in_build_mode\") as bool\n\nfunc load_only_orc_scenes() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/load_only_orc_scenes\") as bool\n\nfunc run_test_towers_tool() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/run_test_towers_tool\") as bool\n\nfunc run_auto_playtest_bot() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/run_auto_playtest_bot\") as bool\n\nfunc run_test_items_tool() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/run_test_items_tool\") as bool\n\nfunc run_test_horadric_tool() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/run_test_horadric_tool\") as bool\n\nfunc run_test_tower_sprite_size() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/run_test_tower_sprite_size\") as bool\n\nfunc run_test_item_drop_chances() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/run_test_item_drop_chances\") as bool\n\nfunc unlimited_portal_lives() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/unlimited_portal_lives\") as bool\n\nfunc show_hidden_buffs() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/show_hidden_buffs\") as bool\n\n# NOTE: increasing this valid makes the game run at super\n# speed\nfunc update_ticks_per_physics_tick() -> int:\n\treturn ProjectSettings.get_setting(\"application/config/update_ticks_per_physics_tick\") as int\n\nfunc enable_dev_commands() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/enable_dev_commands\") as bool\n\nfunc print_wave_info() -> bool:\n\treturn ProjectSettings.get_setting(\"application/config/print_wave_info\") as bool\n"
  },
  {
    "path": "src/singletons/constants.gd",
    "content": "class_name Constants\n\n\n# NOTE: Constants class is not an autoload because it\n# contains only \"const\" vars which can be accessed\n# statically. It also needs to be accessed by some @tool\n# scripts which don't work with autoloads.\n\n\n# NOTE: this tile size is for isometric projection.\nconst TILE_SIZE: Vector2 = Vector2(256, 128)\n\n# TILE_SIZE_PIXELS is the size of the a tile in a top-down\n# projection. Derived using the Pythagorean identity.\nconst TILE_SIZE_PIXELS: float = sqrt(pow(256, 2) / 2)\nconst TILE_SIZE_PIXELS_HALF: float = Constants.TILE_SIZE_PIXELS / 2\n\n# NOTE: can be checked by placing a range checker in\n# original game and setting ranges to different values,\n# then divide range by tile count.\n# 700 / 5.5 = 127\n# 2000 / 15.5 = 129\nconst TILE_SIZE_WC3: float = 128\n\n# NOTE: this constant should be used to convert between wc3\n# distances and youtd2 distances in top-down projection.\n# This cannot be used for converting directly from youtd2 in\n# isometric projection, need to unproject vectors first.\nconst WC3_DISTANCE_TO_PIXELS: float = TILE_SIZE_PIXELS / TILE_SIZE_WC3\n\n# This extension comes from original youtd2/wc3 engine. It\n# basically changes attack range check to start from tower\n# edge instead of tower center.\nconst RANGE_CHECK_BONUS_FOR_TOWERS: float = 72\nconst RANGE_CHECK_BONUS_FOR_OTHER_UNITS: float = 8\n\nconst DEATH_EXPLODE_EFFECT_SIZE: float = 32.0\nconst LEVEL_UP_EFFECT_SIZE: float = 64.0\n\nconst SPELL_DAMAGE_RATIO: float = 0.9\nconst SPELL_DAMAGE_RATIO_FOR_SIF: float = 0.4\n\nconst TOWER_MAX_LEVEL_BASE: int = 25\nconst TOWER_MAX_LEVEL_WITH_BONUS: int = 30\nconst PLAYER_MAX_LEVEL: int = 300\nconst SIF_ARMOR_CHANCE: float = 0.15\nconst MIN_WAVE_FOR_SPECIAL: int = 8\n\nconst INVENTORY_CAPACITY_MAX: int = 6\n\nconst WAVE_COUNT_TRIAL: int = 80\nconst WAVE_COUNT_FULL: int = 120\nconst WAVE_COUNT_NEVERENDING: int = 240\n\nconst INNATE_MOD_ATK_CRIT_CHANCE: float = 0.0125\nconst INNATE_MOD_ATK_CRIT_DAMAGE: float = 1.25\nconst INNATE_MOD_SPELL_CRIT_DAMAGE: float = 1.25\nconst INNATE_MOD_SPELL_CRIT_CHANCE: float = 0.0125\n\nconst INNATE_MOD_ATK_CRIT_CHANCE_LEVEL_ADD: float = 0.0015\nconst INNATE_MOD_ATK_CRIT_DAMAGE_LEVEL_ADD: float = 0.02\nconst INNATE_MOD_SPELL_CRIT_CHANCE_LEVEL_ADD: float = 0.0015\nconst INNATE_MOD_SPELL_CRIT_DAMAGE_LEVEL_ADD: float = 0.02\nconst INNATE_MOD_DAMAGE_BASE_PERC_LEVEL_ADD: float = 0.04\nconst INNATE_MOD_ATTACKSPEED_LEVEL_ADD: float = 0.01\n\nconst ATK_CRIT_CHANCE_CAP: float = 0.8\nconst ATK_MULTICRIT_DIMISHING: float = 0.8\nconst MOD_ATTACKSPEED_MIN: float = 0.2\nconst MOD_ATTACKSPEED_MAX: float = 5.0\nconst ATTACK_COOLDOWN_MIN: float = 0.2\n\nconst PROJECTILE_SPEED_MAX: int = 30000\n# NOTE: couldn't find the exact value so had to calculate it\n# by eye from original youtd. This value is big enough to\n# always bounce from mass creeps and almost always bounce\n# for normal creeps - works like that in original game as\n# well. The calculation is like this:\n# Delay between normal creeps is [0.4s-2.2s].\n# Default speed is 222.\n# delay = 0.4-1.5 = bounce works\n# delay = 1.5-2.2 = bounce fails\nconst BOUNCE_ATTACK_RANGE: int = 340\nconst BASE_ITEM_DROP_CHANCE: float = 0.0475\n\n# NOTE: DEFAULT_MOVE_SPEED was obtained by measuring speed\n# in original game. 2000 / 9s ~= 222\n# \n# MOVE_SPEED_MAX can be found online, search \"warcraft 3 max\n# speed 522\"\n# \n# NOTE: MOVE_SPEED_MIN is 100 because this appears to be the\n# minimum limit applied internaly inside the WC3\n# SetUnitMoveSpeed() function.\nconst MOVE_SPEED_MIN: float = 100.0\nconst MOVE_SPEED_MAX: float = 522.0\nconst DEFAULT_MOVE_SPEED: float = 222.0\n\n# 24h = 480 irl seconds\nconst IRL_SECONDS_TO_GAME_WORLD_HOURS: float = 24.0 / 480.0\n# Time of day starts at 12:00, noon\nconst INITIAL_TIME_OF_DAY: float = 12.0\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] there was no damage\n# max in original game. This is just an arbitrary number to\n# protect against bugs. Note that it can't be lower than\n# this because creep hp can go up to billions in bonus\n# waves.\nconst DAMAGE_MIN: float = 0\nconst DAMAGE_MAX: float = 1000000000000000\n\nconst SIF_CREEP_HEALTH_MULTIPLIER: float = 0.48\n\nconst TIME_BEFORE_FIRST_WAVE: float = 180.0\nconst TIME_BETWEEN_WAVES: float = 15.0\n\nconst MAX_ELEMENT_LEVEL_BASE: int = 15\n\nconst BUFFGROUP_COUNT: int = 6\n\nconst MAX_UPDATE_TICKS_PER_PHYSICS_TICK: int = 20\n\n# NOTE: this value is the same as in original game. Player\n# earns about 60k score points per hour at medium\n# difficulty. Player must earn lvl 20 to unlock all\n# builders. Player reaches lvl 20 at 411 exp. Therefore it\n# takes about 3.5 hours to unlock all builders:\n# \n# 411xp / (60,000score * 0.002) ~= 3.5h\nconst SCORE_TO_EXP: float = 0.002\n# NOTE: picked 1 upgrade every 6 levels so that it takes\n# around ~20 ingame hours to unlock all upgrades:\n# - 10upgrades * 6level/upgrade = 60 levels for all upgrades\n# - need 2431 exp to reach level 60\n# - 60000score/hour * 0.002exp/score = 120exp/hour\n# - 2431exp / 120exp/hour ~= 20 hours\n# \n# In addition, this is 20 *ingame* hours. IRL time can be\n# half as much because of ability to speed up the game.\nconst PLAYER_LEVEL_TO_WISDOM_UPGRADE_COUNT: float = 1 / 6.0\n\nconst TOMES_WARNING_THRESHOLD: int = 50\nconst WAVE_LEVEL_AFTER_WHICH_TOME_WARNINGS_STOP: int = 100\n\n# NOTE: picked these values because they are used in a\n# certain game about a World on the Rim\nconst GAME_SPEED_NORMAL: int = 1\nconst GAME_SPEED_FAST: int = 3\nconst GAME_SPEED_FASTEST: int = 6\n\nconst ITEM_BUTTON_SIZE: Vector2 = Vector2(80, 80)\nconst ABILITY_BUTTON_SIZE: Vector2 = Vector2(85, 85)\n\n# Picked these ports because they were used in Godot\n# examples and are not present on the list of registered or\n# common ports as of December 2022:\n# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers\nconst SERVER_PORT: int = 8910\nconst ROOM_SCANNER_SEND_PORT: int = 8911\nconst ROOM_ADVERTISER_SEND_PORT: int = 8912\n\nconst PLAYER_COUNT_MAX: int = 8\n\nconst NAKAMA_ADDRESS: String = \"161.35.244.122\"\nconst NAKAMA_PORT: int = 7350\nconst NAKAMA_PROTOCOL: String = \"http\"\n\nconst MAX_CHAT_MESSAGE_LENGTH: int = 200\n\nconst PLAYER_NAME_ALLOWED_CHARS: String = \"[A-Za-z]\"\nconst PLAYER_NAME_LENGTH_MIN: int = 2\nconst PLAYER_NAME_LENGTH_MAX: int = 15\n\nconst TOWER_ATTACK_ABILITY_NAME_ENGLISH: String = \"Normal attack\"\n"
  },
  {
    "path": "src/singletons/effect.gd",
    "content": "extends Node\n\n\n# Functions to create \"effects\" which are used to add visual\n# indicators of buffs and abilities.\n\n# NOTE: effect scene args must be AnimatedSprite2D\n\n\nconst Z_INDEX_BELOW_CREEPS: int = 9\nconst Z_INDEX_BELOW_TOWERS: int = 19\n\n\n# NOTE: Effect.createAnimated() in JASS\nfunc create_animated(effect_path: String, effect_pos: Vector3, facing: float) -> int:\n\tvar effects_container: Node = get_tree().get_root().get_node_or_null(\"GameScene/World/EffectsContainer\")\n\t\n\tif effects_container == null:\n\t\tpush_warning(\"effects_container is null. You can ignore this warning during game restart.\")\n\n\t\treturn 0\n\n\tvar id: int = effects_container.create_animated(effect_path, effect_pos, facing)\n\tset_auto_destroy_enabled(id, true)\n\n#\tNOTE: by default, set z_index of effect to 100 so that\n#\teffect is drawn above all units\n\tset_z_index(id, 100)\n\n\treturn id\n\n\n# NOTE: Effect.createAnimatedScaled() in JASS\nfunc create_animated_scaled(effect_path: String, effect_pos: Vector3, facing: float, scale: float) -> int:\n\tvar effect: int = create_animated(effect_path, effect_pos, facing)\n\tEffect.set_scale(effect, scale)\n\n\treturn effect\n\n\n# NOTE: Effect.createSimple() in JASS\nfunc create_simple(effect_path: String, effect_pos: Vector2) -> int:\n\tvar effect_pos_3d: Vector3 = Vector3(effect_pos.x, effect_pos.y, 0)\n\treturn create_animated(effect_path, effect_pos_3d, 0.0)\n\n# Creates an effect at position of Unit. Effect will *not*\n# follow the unit if it moves.\n# NOTE: Effect.createSimpleAtUnit() in JASS\nfunc create_simple_at_unit(effect_path: String, unit: Unit, body_part: Unit.BodyPart = Unit.BodyPart.CHEST, z_offset: float = 0.0) -> int:\n\tif unit == null:\n\t\tpush_error(\"null unit passed to Effect.create_simple_at_unit()\")\n\t\t\n\t\treturn create_animated(effect_path, Vector3.ZERO, 0.0)\n\n\tvar effect_pos: Vector3 = unit.get_body_part_position(body_part)\n\teffect_pos.z += z_offset\n\n\treturn create_animated(effect_path, effect_pos, 0.0)\n\n\n# Creates an effect on the Unit. Effect will follow the unit\n# if it moves. The effect will also go away if the unit dies.\n# NOTE: Effect.createSimpleOnUnit() in JASS\nfunc create_simple_at_unit_attached(effect_path: String, unit: Unit, body_part: Unit.BodyPart = Unit.BodyPart.CHEST, z_offset: float = 0.0) -> int:\n\tif unit == null:\n\t\tpush_error(\"null unit passed to Effect.create_simple_at_unit_attached()\")\n\t\t\n\t\treturn create_animated(effect_path, Vector3.ZERO, 0.0)\n\n\tvar effects_container: Node = get_tree().get_root().get_node_or_null(\"GameScene/World/EffectsContainer\")\n\t\n\tif effects_container == null:\n\t\tpush_warning(\"effects_container is null. You can ignore this warning during game restart.\")\n\n\t\treturn 0\n\n\tvar id: int = effects_container.create_simple_at_unit_attached(effect_path, unit, body_part, z_offset)\n\tset_auto_destroy_enabled(id, true)\n\n\treturn id\n\n\n# NOTE: AddSpecialEffect() in JASS()\nfunc add_special_effect(effect_path: String, effect_pos: Vector2) -> int:\n\tvar effect_pos_3d: Vector3 = Vector3(effect_pos.x, effect_pos.y, 0)\n\treturn create_animated(effect_path, effect_pos_3d, 0.0)\n\n\n# NOTE: Effect.createScaled() in JASS()\nfunc create_scaled(effect_path: String, effect_pos: Vector3, facing: float, scale: float) -> int:\n\tvar effect: int = create_animated(effect_path, effect_pos, facing)\n\tEffect.set_scale(effect, scale)\n\n\treturn effect\n\n\n# NOTE: Effect.createColored() in JASS()\nfunc create_colored(effect_path: String, effect_pos: Vector3, facing: float, scale: float, color: Color):\n\tvar effect: int = create_animated(effect_path, effect_pos, facing)\n\tEffect.set_scale(effect, scale)\n\tEffect.set_color(effect, color)\n\n\treturn effect\n\n\n# NOTE: effect.setScale() in JASS()\nfunc set_scale(effect_id: int, scale: float):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\t\n\tvar effects_container: Node = get_tree().get_root().get_node_or_null(\"GameScene/World/EffectsContainer\")\n\t\n\tif effects_container == null:\n\t\tpush_warning(\"effects_container is null. You can ignore this warning during game restart.\")\n\n\t\treturn\n\n\tvar original_scale: Vector2 = effects_container.get_effect_original_scale(effect_id)\n\t\n\teffect.scale = original_scale * scale\n\n\nfunc set_color(effect_id: int, color: Color):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\teffect.modulate = color\n\n\n# This makes the effect be automatically destroyed after\n# given lifetime period.\n# NOTE: effect.setLifetime() in JASS()\nfunc set_lifetime(effect_id: int, lifetime: float):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\tset_auto_destroy_enabled(effect_id, false)\n\n\tvar timer: ManualTimer = Utils.create_manual_timer(lifetime, self)\n\ttimer.timeout.connect(_on_lifetime_timer_timeout.bind(effect_id))\n\n\n# NOTE: effect.setAnimationSpeed() in JASS()\nfunc set_animation_speed(effect_id: int, speed: float):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\tvar effect_sprite: AnimatedSprite2D = effect as AnimatedSprite2D\n\teffect_sprite.speed_scale = speed\n\n\n# NOTE: this f-n works differently than in original youtd.\n# In original youtd, calling destroy() would schedule effect\n# to be destroyed once the animation finished. In youtd2,\n# calling destroy_effect() will remove the effect instantly.\n# Also note that in youtd2 effects are by default scheduled\n# to be destroyed when animation finishes.\n# \n# NOTE: Effect.destroy() and DestroyEffect() in JASS()\nfunc destroy_effect(effect_id: int):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\teffect.queue_free()\n\n\n# Changes whether effect should be automatically destroyed\n# once it's animation ends. This is enabled by default.\nfunc set_auto_destroy_enabled(effect_id: int, enabled: bool):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\tif enabled:\n\t\tif !effect.animation_finished.is_connected(_on_effect_animation_finished):\n\t\t\teffect.animation_finished.connect(_on_effect_animation_finished.bind(effect_id))\n\t\tif !effect.animation_looped.is_connected(_on_effect_animation_finished):\n\t\t\teffect.animation_looped.connect(_on_effect_animation_finished.bind(effect_id))\n\telse:\n\t\tif effect.animation_finished.is_connected(_on_effect_animation_finished):\n\t\t\teffect.animation_finished.disconnect(_on_effect_animation_finished)\n\t\tif effect.animation_looped.is_connected(_on_effect_animation_finished):\n\t\t\teffect.animation_looped.disconnect(_on_effect_animation_finished)\n\n\nfunc set_position(effect_id: int, pos_wc3: Vector2):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\tvar pos_wc3_3d: Vector3 = Vector3(pos_wc3.x, pos_wc3.y, 0)\n\tvar pos_canvas: Vector2 = VectorUtils.wc3_to_canvas(pos_wc3_3d)\n\teffect.position = pos_canvas\n\n\nfunc set_z_index(effect_id: int, z_index):\n\tvar effect: Node2D = _get_effect(effect_id)\n\tif effect == null:\n\t\treturn\n\n\teffect.z_index = z_index\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_effect(effect_id: int) -> Node2D:\n\tvar effects_container: Node = get_tree().get_root().get_node_or_null(\"GameScene/World/EffectsContainer\")\n\t\n\tif effects_container == null:\n\t\tpush_warning(\"effects_container is null. You can ignore this warning during game restart.\")\n\n\t\treturn null\n\n\tvar effect: Node2D = effects_container.get_effect(effect_id)\n\n\treturn effect\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_lifetime_timer_timeout(effect_id: int):\n\tdestroy_effect(effect_id)\n\n\nfunc _on_effect_animation_finished(effect_id: int):\n\tdestroy_effect(effect_id)\n"
  },
  {
    "path": "src/singletons/elapsed_timer.gd",
    "content": "extends Node\n\n\n# Useful for debugging. Measures elapsed time between two\n# points in time. Use by putting start() and end() calls\n# around the code that you want to measure.\n\n\nvar _elapsed_timer_map: Dictionary = {}\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc start(timer_name: String):\n\tif _elapsed_timer_map.has(timer_name):\n\t\tpush_error(\"Timer already in progress for name:\", timer_name)\n\n\t\treturn\n\n\tvar start_time: float = Time.get_ticks_msec() / 1000.0\n\t_elapsed_timer_map[timer_name] = start_time\n\n\nfunc end(timer_name: String):\n\t_end_internal(timer_name, false)\n\n\nfunc end_verbose(timer_name: String):\n\t_end_internal(timer_name, true)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _end_internal(timer_name: String, verbose: bool):\n\tif !_elapsed_timer_map.has(timer_name):\n\t\tpush_error(\"Timer hasn't been started for name:\", timer_name)\n\n\t\treturn\n\n\tvar start_time: float = _elapsed_timer_map[timer_name]\n\tvar end_time: float = Time.get_ticks_msec() / 1000.0\n\tvar elapsed_time: float = end_time - start_time\n\tvar time_string: String = Utils.format_float(elapsed_time, 8)\n\tvar message: String = \"Elapsed time for %s = %s\" % [timer_name, time_string]\n\n\tif verbose:\n\t\tprint_verbose(message)\n\telse:\n\t\tprint(message)\n\n\t_elapsed_timer_map.erase(timer_name)\n"
  },
  {
    "path": "src/singletons/event_bus.gd",
    "content": "extends Node\n\n# Class for global events. Emitters can use this to emit\n# global events. Subscribers can connect to global signals.\n# EventBus is useful for cases where connecting signals\n# normally would require a long chain of connections.\n\n\nsignal received_first_timeslot()\nsignal player_selected_builder()\nsignal player_requested_quit_to_title()\nsignal player_requested_transmute()\nsignal player_requested_return_from_horadric_cube()\nsignal player_requested_autofill(recipe: HoradricCube.Recipe, rarity_filter: Array)\nsignal player_requested_to_research_element(element: Element.enm)\nsignal player_requested_to_build_tower(tower_id: int)\nsignal player_requested_to_upgrade_tower(tower: Tower)\nsignal player_requested_to_sell_tower(tower: Tower)\nsignal player_requested_to_clear_combatlog()\nsignal player_requested_to_sort_item_stash()\nsignal player_requested_help()\nsignal player_clicked_autocast(autocast: Autocast)\nsignal player_right_clicked_autocast(autocast: Autocast)\nsignal player_shift_right_clicked_item(item: Item)\nsignal player_right_clicked_item(item: Item)\nsignal player_clicked_in_item_container(item_container: ItemContainer, clicked_index: int)\nsignal player_clicked_tower_buff_group(tower: Tower, buff_group: int)\nsignal item_flew_to_item_stash(item: Item)\nsignal player_requested_to_roll_towers()\nsignal player_requested_start_game()\nsignal player_requested_next_wave()\nsignal player_started_build_process()\nsignal player_stopped_build_process()\nsignal mouse_entered_unit(unit: Unit)\nsignal mouse_exited_unit(unit: Unit)\nsignal item_started_flying_to_item_stash(item: Item, canvas_pos: Vector2)\n\n# NOTE: signals for triggering tutorials\nsignal finished_tutorial_section(tutorial_id: int)\nsignal item_dropped()\nsignal portal_received_damage()\nsignal built_a_tower()\nsignal unit_leveled_up()\n"
  },
  {
    "path": "src/singletons/experience.gd",
    "content": "extends Node\n\n# Containts data about how tower levels map to experience.\n# Mapping of level -> required experience\n# Mapping of experience -> current level\n\nconst EXP_FOR_LEVEL_PATH: String = \"res://data/exp_for_level.csv\"\n\nenum ExpForLevelColumn {\n\tLEVEL = 0,\n\tEXPERIENCE,\n}\n\n# This map is loaded from csv file\nvar _exp_for_level: Dictionary = _load_exp_for_level_map()\n# This map is generated based on _exp_for_level\nvar _level_at_exp: Dictionary = make_level_at_exp_map(_exp_for_level)\n\n\nfunc _load_exp_for_level_map() -> Dictionary:\n\tvar map: Dictionary = {}\n\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(EXP_FOR_LEVEL_PATH)\n\n\tfor csv_line in csv:\n\t\tvar level: int = csv_line[ExpForLevelColumn.LEVEL].to_int()\n\t\tvar experience: int = csv_line[ExpForLevelColumn.EXPERIENCE].to_int()\n\n\t\tmap[level] = experience\n\n\treturn map\n\n# NOTE: this map is needed to simplify implementation of\n# Unit._change_experience()\n# Example:\n# 0 = 0\n# 1 = 0\n# 2 = 0\n# 3 = 0\n# ...\n# 12 = 1\n# 13 = 1\n# 14 = 1\n# ...\n# 24 = 2\n# 25 = 2\n# 26 = 2\n# ...\nfunc make_level_at_exp_map(exp_for_level: Dictionary) -> Dictionary:\n\tvar map: Dictionary = {}\n\t\n\tfor current_level in range(0, Constants.TOWER_MAX_LEVEL_WITH_BONUS):\n\t\tvar current_level_experience: int = exp_for_level[current_level]\n\t\tvar next_level: int = current_level + 1\n\t\tvar next_level_experience: int = exp_for_level[next_level]\n\n\t\tfor i in range(current_level_experience, next_level_experience):\n\t\t\tmap[i] = current_level\n\n\tvar max_level_exp: int = exp_for_level[Constants.TOWER_MAX_LEVEL_WITH_BONUS]\n\tmap[max_level_exp] = Constants.TOWER_MAX_LEVEL_WITH_BONUS\n\n\treturn map\n\n\n# Returns how much experience is required to reach given\n# level\nfunc get_exp_for_level(level: int) -> int:\n\tvar value_for_invalid_level: int = 1000000\n\tvar experience: int = _exp_for_level.get(level, value_for_invalid_level)\n\n\treturn experience\n\n\n# Returns what level the tower should be at when it has a\n# certain amount of experience\nfunc get_level_at_exp(experience_float: float, player: Player) -> int:\n\tvar experience: int = floori(experience_float)\n\tvar level: int\n\t\n\tif experience >= 0:\n\t\tif _level_at_exp.has(experience):\n\t\t\tlevel = _level_at_exp[experience]\n\t\telse:\n\t\t\tlevel = Constants.TOWER_MAX_LEVEL_WITH_BONUS\n\telse:\n\t\tlevel = 0\n\t\n\t# limit by player's max tower level\n\tif player != null:\n\t\tlevel = min(level, player.get_max_tower_level())\n\treturn level\n"
  },
  {
    "path": "src/singletons/experience_password.gd",
    "content": "extends Node\n\n# Functions for encoding/decoding player experience\n# password.\n\n\nconst MAGIC_BYTES: Array = [0x64, 0x01, 0xDF, 0xEA, 0x7A, 0x17, 0x69, 0x35, 0x1B, 0x18, 0x02, 0xFF, 0x67, 0x11, 0xB0, 0xE1]\n\n\nfunc decode(password: String) -> int:\n\tif password.is_empty():\n\t\treturn 0\n\t\n\tvar is_valid_hex: bool = password.is_valid_hex_number()\n\tif !is_valid_hex:\n\t\tpush_error(\"password is not valid hex\")\n\n\t\treturn -1\n\n#\tNOTE: need to check for length because otherwise godot\n#\twill push errors about \"uneven length\"\n\tvar is_even_length: bool = password.length() % 2 == 0\n\tif !is_even_length:\n\t\tpush_error(\"password is not even length\")\n\n\t\treturn -1\n\n\tvar byte_array: PackedByteArray = password.hex_decode()\n\t\n\tvar byte_array_length_is_valid: bool = byte_array.size() == MAGIC_BYTES.size()\n\tif !byte_array_length_is_valid:\n\t\tpush_error(\"password length doesn't match with magic\")\n\n\t\treturn -1\n\t\n\tfor i in range(0, MAGIC_BYTES.size()):\n\t\tbyte_array[i] = byte_array[i] ^ MAGIC_BYTES[i]\n\n\tvar value_list: Array = []\n\n\tfor byte_offset in range(0, MAGIC_BYTES.size(), 4):\n\t\tvar value: int = byte_array.decode_s32(byte_offset) - byte_offset\n\t\tvalue_list.append(value)\n\n\tvar exp_int: int = value_list[0]\n\n\tfor value in value_list:\n\t\tif value != exp_int:\n\t\t\tpush_error(\"password sub-values don't match up\")\n\n\t\t\treturn -1\n\n\tif exp_int < 0:\n\t\tpush_error(\"exp int is negative\")\n\n\t\treturn -1\n\n\treturn exp_int\n\n\nfunc encode(exp_int: int) -> String:\n\tvar byte_array: PackedByteArray = PackedByteArray()\n\tbyte_array.resize(MAGIC_BYTES.size())\n\n\tfor byte_offset in range(0, MAGIC_BYTES.size(), 4):\n\t\tbyte_array.encode_s32(byte_offset, exp_int + byte_offset)\n\n\tfor i in range(0, MAGIC_BYTES.size()):\n\t\tbyte_array[i] = byte_array[i] ^ MAGIC_BYTES[i]\n\n\tvar password: String = byte_array.hex_encode()\n\n\treturn password\n"
  },
  {
    "path": "src/singletons/globals.gd",
    "content": "extends Node\n\n\n# NOTE: singleplayer is also treated as ENET type so there's\n# no \"NONE\" connection\nenum ConnectionType {\n\tENET,\n\tNAKAMA\n}\n\n\n# NOTE: these settings are selected during game start. If\n# they are accessed before that point, you will get these\n# placeholders.\nvar _player_mode: PlayerMode.enm = PlayerMode.enm.SINGLEPLAYER\nvar _wave_count: int = 0\nvar _game_mode: GameMode.enm = GameMode.enm.BUILD\nvar _difficulty: Difficulty.enm = Difficulty.enm.EASY\nvar _team_mode: TeamMode.enm = TeamMode.enm.ONE_PLAYER_PER_TEAM\nvar _origin_seed: int = 0\nvar _update_ticks_per_physics_tick: int = 1\nvar _connection_type: ConnectionType = ConnectionType.ENET\nvar _enet_peer_id_to_player_name: Dictionary = {}\nvar _title_screen_notification_list: Array[String] = []\nvar _map: Map = null\n\n\n# NOTE: you must use random functions via one of the\n# RandomNumberGenerator instances below. This is to prevent\n# desyncs.\n# \n# synced_rng => for deterministic code, which is executed in\n# the same way on all multiplayer clients. Examples: picking\n# a random damage value, picking a random item.\n# \n# local_rng => for non-deterministic code, which is executed\n# in a way which is particular to local client. Example:\n# random offset for floating text which is visible only to\n# local player.\n# \n# NOTE: need to use RandomNumberGenerator instead of global\n# random functions because it's impossible to keep global\n# rng pure. This is because some Godot engine components\n# (CPUParticles2D) use global rng and corrupt it.\nvar synced_rng: RandomNumberGenerator = RandomNumberGenerator.new()\nvar local_rng: RandomNumberGenerator = RandomNumberGenerator.new()\n\n\n# NOTE: current variables don't need to be reset. If you add\n# some variable which needs to be reset, reset it here.\nfunc reset():\n\tpass\n\n\nfunc get_player_mode() -> PlayerMode.enm:\n\treturn _player_mode\n\n\nfunc get_wave_count() -> int:\n\treturn _wave_count\n\n\nfunc get_game_mode() -> GameMode.enm:\n\treturn _game_mode\n\n\nfunc get_difficulty() -> Difficulty.enm:\n\treturn _difficulty\n\n\nfunc get_team_mode() -> TeamMode.enm:\n\treturn _team_mode\n\n\nfunc get_origin_seed() -> int:\n\treturn _origin_seed\n\n\nfunc game_mode_is_random() -> bool:\n\treturn Globals.get_game_mode() == GameMode.enm.RANDOM_WITH_UPGRADES || Globals.get_game_mode() == GameMode.enm.TOTALLY_RANDOM\n\n\nfunc game_mode_allows_transform() -> bool:\n\treturn Globals.get_game_mode() != GameMode.enm.BUILD || Config.allow_transform_in_build_mode()\n\n\nfunc game_is_neverending() -> bool:\n\treturn _wave_count == Constants.WAVE_COUNT_NEVERENDING\n\n\nfunc get_update_ticks_per_physics_tick() -> int:\n\treturn _update_ticks_per_physics_tick\n\n\nfunc set_update_ticks_per_physics_tick(value: int):\n\t_update_ticks_per_physics_tick = value\n\n\nfunc get_connect_type() -> ConnectionType:\n\treturn _connection_type\n\n\nfunc get_player_name_from_peer_id(peer_id: int):\n\tvar player_name: String = _enet_peer_id_to_player_name.get(peer_id, \"\")\n\n\treturn player_name\n\n\nfunc get_map() -> Map:\n\treturn _map\n\n\nfunc add_title_screen_notification(text: String):\n\t_title_screen_notification_list.append(text)\n\n\nfunc get_title_screen_notification_list() -> Array[String]:\n\treturn _title_screen_notification_list\n\n\nfunc clear_title_screen_notification_list():\n\t_title_screen_notification_list.clear()\n\n"
  },
  {
    "path": "src/singletons/group_manager.gd",
    "content": "extends Node\n\n\n# Provides lookup for nodes via uid. Note that uid ranges\n# can be different for each group.\n\n\nvar _group_map: Dictionary = {}\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc add(group_name: String, node: Node, uid: int):\n\tnode.add_to_group(group_name)\n\n\tif !_group_map.has(group_name):\n\t\t_group_map[group_name] = {}\n\n\t_group_map[group_name][uid] = node\n\n\nfunc get_by_uid(group_name: String, uid: int) -> Node:\n\tif !_group_map.has(group_name):\n\t\treturn null\n\n\tif !_group_map[group_name].has(uid):\n\t\treturn null\n\n\tvar is_valid: bool = is_instance_valid(_group_map[group_name][uid])\n\n\tif !is_valid:\n\t\treturn \n\n\tvar node: Node = _group_map[group_name][uid]\n\n\tif node.is_queued_for_deletion():\n\t\treturn null\n\n\treturn node\n\n\nfunc reset():\n\t_group_map = {}\n"
  },
  {
    "path": "src/singletons/item_drop_calc.gd",
    "content": "extends Node\n\n\n# This is a rough translation of the original JASS code that\n# picks which item should be dropped. Some of the code has\n# been rewritten but the end behavior is the same.\n\n# \tValues in this list translate to the following\n# \tprobabilities.\n# \n#\tcommon \t\t= 75%\n#\tuncommon \t= 25%\n#\trare \t\t= 6%\n#\tunique \t\t= 2%\nvar _rarity_probabilities: Array[float] = [\n\t1000.0,\n\t0.25,\n\t0.06,\n\t0.02\n]\n\n# Quality threshold for different rarities of oils.\n# Doesn't affect regular items, those have custom required\n# levels assigned to each item.\nvar _quality_threshold: Array[int] = [\n\t0,\n\t6,\n\t18,\n\t36\n]\n\n\n# NOTE: returns 0 if no item was available for current game\n# conditions.\nfunc get_random_item(tower: Tower, target: Creep) -> int:\n\tvar creep_level: int = target.get_spawn_level()\n\tvar tower_quality_ratio: float = tower.get_item_quality_ratio()\n\tvar target_quality_ratio: float = target.get_item_quality_ratio_on_death()\n\tvar quality_multiplier: float = tower_quality_ratio * target_quality_ratio\n\tvar random_item: int = _calculate_item_drop(creep_level, quality_multiplier)\n\t\n\treturn random_item\n\n\nfunc _calculate_item_drop(creep_level: int, quality_multiplier: float) -> int:\n\tvar rarity: int = 3\n\tvar rarity_chance: float = Globals.synced_rng.randf_range(0.0, 1.0)\n\n#\tPick a random rarity, using\n#\t_rarity_probabilities and quality_multiplier.\n\twhile true:\n\t\trarity_chance = rarity_chance - _rarity_probabilities[rarity] * quality_multiplier\n\n\t\tif rarity_chance < 0.0 || rarity == 0:\n\t\t\tbreak\n\n\t\trarity = rarity - 1\n\n\tvar drop_oil_or_consumable: bool = Utils.rand_chance(Globals.synced_rng, 0.4)\n\n\tif drop_oil_or_consumable:\n#\t\tOil and consumable items\n\n# \t\tReduce rarity to match tower's level. For example,\n# \t\tif we initially picked \"uncommon\" rarity but tower\n# \t\tis level 1, then the rarity gets reduced to\n# \t\t\"common\".\n\t\twhile true:\n\t\t\tif creep_level >= _quality_threshold[rarity]:\n\t\t\t\tbreak\n\n\t\t\trarity = rarity - 1\n\n\t\tvar random_oil_or_consumable: int = get_random_oil_or_consumable(rarity)\n\n\t\treturn random_oil_or_consumable\n\telse:\n#\t\tRegular items\n\t\tvar random_regular_item: int = get_random_item_at_or_below_rarity_bounded(rarity, 0, creep_level)\n\n\t\treturn random_regular_item\n\n\nfunc get_random_oil_or_consumable(rarity: int) -> int:\n\tvar oil_list: Array = get_oil_and_consumables_list(rarity)\n\n\tif !oil_list.is_empty():\n\t\tvar random_item: int = Utils.pick_random(Globals.synced_rng, oil_list)\n\n\t\treturn random_item\n\telse:\n\t\treturn 0\n\n\nfunc get_random_item_at_or_below_rarity_bounded(rarity: int, lvl_min: int, lvl_max: int) -> int:\n\tvar random_item: int = get_random_item_at_rarity_bounded(rarity, lvl_min, lvl_max)\n\n\tif random_item != 0:\n\t\treturn random_item\n\telse:\n\t\tif rarity > 0:\n#\t\t\tTry to find items in lower rarity\n\t\t\treturn get_random_item_at_rarity_bounded(rarity - 1, lvl_min, lvl_max)\n\t\telse:\n#\t\t\tGive up\n\t\t\treturn 0\n\n\n# RandomItemSet.permanent.getRandomItemAtRarityBounded() in JASS\nfunc get_random_item_at_rarity_bounded(rarity: int, lvl_min: int, lvl_max: int) -> int:\n\tvar available_item_list: Array[int] = get_item_list_bounded(rarity, lvl_min, lvl_max)\n\n\tvar items_are_available: bool = !available_item_list.is_empty()\n\n\tif items_are_available:\n\t\tvar random_item: int = Utils.pick_random(Globals.synced_rng, available_item_list)\n\n\t\treturn random_item\n\telse:\n\t\treturn 0\n\n\nfunc get_item_list_bounded(rarity: int, lvl_min: int, lvl_max: int) -> Array[int]:\n#\tFind all items which are not oils and fall into selected\n#\trarity\n\tvar rarity_string: String = Rarity.convert_to_string(rarity)\n\tvar regular_type_string: String = ItemType.convert_to_string(ItemType.enm.REGULAR)\n\tvar item_list: Array = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, regular_type_string)\n\titem_list = ItemProperties.filter_item_id_list(item_list, ItemProperties.CsvProperty.RARITY, rarity_string)\n\n# \tFilter the item list by level\n\tvar available_item_list: Array[int] = []\n\n\tfor item in item_list:\n\t\tvar required_level: int = ItemProperties.get_required_wave_level(item)\n\t\tvar level_is_ok: bool = lvl_min <= required_level && required_level <= lvl_max\n\n\t\tif level_is_ok:\n\t\t\tavailable_item_list.append(item)\n\n\treturn available_item_list\n\n\nfunc get_oil_and_consumables_list(rarity: int) -> Array:\n#\tFind all items which are oils and fall into selected\n#\trarity\n\tvar rarity_string: String = Rarity.convert_to_string(rarity)\n\tvar oil_type_string: String = ItemType.convert_to_string(ItemType.enm.OIL)\n\tvar consumable_type_string: String = ItemType.convert_to_string(ItemType.enm.CONSUMABLE)\n\tvar oil_item_list: Array = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, oil_type_string)\n\tvar consumable_item_list: Array = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, consumable_type_string)\n\n\tvar item_list: Array = oil_item_list + consumable_item_list\n\n\titem_list = ItemProperties.filter_item_id_list(item_list, ItemProperties.CsvProperty.RARITY, rarity_string)\n\n\treturn item_list\n"
  },
  {
    "path": "src/singletons/messages.gd",
    "content": "extends Node\n\n# Functions that display messages to the player. Messages\n# will be displayed only if player arg is equal to local\n# player. Pass null to player arg to display message to all\n# players.\n\nconst ERROR_MESSAGE_MAX: int = 3\nconst ERROR_DELAY_BEFORE_FADE_START: float = 2.0\nconst ERROR_FADE_DURATION: float = 2.0\nconst NORMAL_MESSAGE_MAX: int = 15\nconst NORMAL_DELAY_BEFORE_FADE_START: float = 10.0\nconst NORMAL_FADE_DURATION: float = 2.0\n\n\n# Adds an error message to the center of the screen. Note\n# that error messages are always colored red.\n# NOTE: try to use Utils.add_ui_error() instead of this f-n\n# because it also plays an error sound.\nfunc add_error(player: Player, text: String):\n\tvar player_match: bool = player == PlayerManager.get_local_player() || player == null\n\t\n\tif !player_match:\n\t\treturn\n\n\tvar hud: HUD = get_tree().get_root().get_node_or_null(\"GameScene/UI/HUD\")\n\n\tif hud == null:\n\t\tpush_warning(\"hud is null. You can ignore this warning during game restart.\")\n\t\t\n\t\treturn\n\n\tvar error_message_container: VBoxContainer = hud.get_error_message_container()\n\n\tvar formatted_text: String = \"[center][color=RED]%s[/color][/center]\" % text\n\n\tvar label: RichTextLabel = Utils.create_message_label(formatted_text)\n\n\tlabel.modulate = Color.WHITE\n\tvar modulate_tween: Tween = create_tween()\n\tmodulate_tween.tween_property(label, \"modulate\",\n\t\tColor(label.modulate.r, label.modulate.g, label.modulate.b, 0),\n\t\tERROR_FADE_DURATION).set_delay(ERROR_DELAY_BEFORE_FADE_START)\n\n\terror_message_container.add_child(label)\n\n\tvar label_count: int = error_message_container.get_children().size()\n\tvar reached_max: bool = label_count >= ERROR_MESSAGE_MAX + 1\n\n\tif reached_max:\n\t\tvar child_list: Array = error_message_container.get_children()\n\t\tvar last_label: RichTextLabel = child_list.front()\n\n\t\terror_message_container.remove_child(last_label)\n\t\tlast_label.queue_free()\n\n\n# Adds a normal message to the left side of the screen.\nfunc add_normal(player: Player, text: String):\n\tvar player_match: bool = player == PlayerManager.get_local_player() || player == null\n\n\tif !player_match:\n\t\treturn\n\n\tvar hud: HUD = get_tree().get_root().get_node_or_null(\"GameScene/UI/HUD\")\n\t\n\tif hud == null:\n\t\tpush_warning(\"hud is null. You can ignore this warning during game restart.\")\n\t\t\n\t\treturn\n\t\n\tvar normal_message_container: VBoxContainer = hud.get_normal_message_container()\n\n\tvar label: RichTextLabel = Utils.create_message_label(text)\n\n\tlabel.modulate = Color.WHITE\n\tvar modulate_tween: Tween = create_tween()\n\tmodulate_tween.tween_property(label, \"modulate\",\n\t\tColor(label.modulate.r, label.modulate.g, label.modulate.b, 0),\n\t\tNORMAL_FADE_DURATION).set_delay(NORMAL_DELAY_BEFORE_FADE_START)\n\t\n\tnormal_message_container.add_child(label)\n\t\n\tvar label_count: int = normal_message_container.get_children().size()\n\tvar reached_max: bool = label_count >= NORMAL_MESSAGE_MAX + 1\n\n\tif reached_max:\n\t\tvar child_list: Array = normal_message_container.get_children()\n\t\tvar last_label: RichTextLabel = child_list.front()\n\n\t\tnormal_message_container.remove_child(last_label)\n\t\tlast_label.queue_free()\n"
  },
  {
    "path": "src/singletons/mission_status.gd",
    "content": "extends Node\n\n\n# Controls state of missions.\n\n\nfunc get_mission_is_complete(id: int) -> bool:\n\tvar mission_status: Dictionary = Settings.get_setting(Settings.MISSION_STATUS) as Dictionary\n\tvar id_string: String = str(id)\n\tvar mission_is_complete: bool = mission_status.get(id_string, false)\n\n\treturn mission_is_complete\n\n\nfunc set_mission_is_complete(id: int, is_complete: bool):\n\tvar prev_mission_status: Dictionary = Settings.get_setting(Settings.MISSION_STATUS) as Dictionary\n\tvar new_mission_status: Dictionary = prev_mission_status.duplicate()\n\tvar id_string: String = str(id)\n\tnew_mission_status[id_string] = is_complete\n\n\tSettings.set_setting(Settings.MISSION_STATUS, new_mission_status)\n\tSettings.flush()\n"
  },
  {
    "path": "src/singletons/mission_tracking.gd",
    "content": "extends Node\n\n\nconst MAX_TRACKED_COUNT: int = 3\n\n\nvar _tracked_mission_map: Dictionary = {}\n\n\nfunc get_mission_is_tracked(id: int) -> bool:\n\tvar is_tracked: bool = _tracked_mission_map.get(id, false)\n\t\n\treturn is_tracked\n\n\nfunc set_mission_is_tracked(id: int, value: bool):\n\t_tracked_mission_map[id] = value\n\n\nfunc get_tracked_count() -> int:\n\tvar count: int = 0\n\tfor id in _tracked_mission_map.keys():\n\t\tvar is_tracked: bool = get_mission_is_tracked(id)\n\t\t\n\t\tif is_tracked:\n\t\t\tcount += 1\n\t\n\treturn count\n"
  },
  {
    "path": "src/singletons/nakama_connection.gd",
    "content": "extends Node\n\n\n# Stores Nakama objects which need to be persisted between\n# title screen and game scene. This class is used if\n# connection type is Nakama - it is completely unused\n# otherwise, if connection is Enet - for singleplayer or\n# LAN.\n\nsignal state_changed()\n\n\nenum State {\n\tCONNECTING,\n\tCONNECTED,\n\tFAILED_TO_CONNECT\n}\n\n\nvar _client: NakamaClient = null\nvar _session: NakamaSession = null\nvar _socket: NakamaSocket = null\nvar _user_id_to_display_name_map: Dictionary = {}\nvar _state: State = NakamaConnection.State.FAILED_TO_CONNECT\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# NOTE: create_client() can be done here because it doesn't\n# require connecting to server\nfunc _ready():\n\tvar server_key: String = Secrets.get_secret(Secrets.Key.SERVER_KEY)\n\t_client = Nakama.create_client(server_key, Constants.NAKAMA_ADDRESS, Constants.NAKAMA_PORT, Constants.NAKAMA_PROTOCOL, Nakama.DEFAULT_TIMEOUT, NakamaLogger.LOG_LEVEL.INFO)\n\n\tconnect_to_server()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_server():\n\tvar running_on_desktop: bool = OS.has_feature(\"pc\")\n\tif !running_on_desktop:\n\t\tprint_verbose(\"Skipping Nakama connection because running in browser.\")\n\t\t_set_state(NakamaConnection.State.FAILED_TO_CONNECT)\n\t\t\n\t\treturn\n\n\t_set_state(NakamaConnection.State.CONNECTING)\n\n# \tCreate Nakama session by authenticating on the server\n# \n# \tNOTE: set username to null to let Nakama automatically\n# \tgenerate a unique username. This way, we don't need to\n# \tcare about username conflicts.\n\tif _session == null:\n\t\tvar device_id: String = OS.get_unique_id()\n\t\tvar null_username = null\n\t\tvar create_user: bool = true\n\t\t_session = await _client.authenticate_device_async(device_id, null_username, create_user)\n\n\t\tif _session.is_exception():\n\t\t\tpush_error(\"Error in authenticate_device_async(): %s\" % _session)\n\t\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"ERROR_FAILED_TO_AUTHENTICATE\"), _session.exception.message])\n\t\t\t_set_state(NakamaConnection.State.FAILED_TO_CONNECT)\n\t\t\t_session = null\n\n\t\t\treturn\n\n# \tUpdate display name of user on Nakama server, based on\n# \tvalue stored in settings (defined in Profile menu)\n\tvar username = null\n\tvar display_name: String = Settings.get_setting(Settings.PLAYER_NAME)\n\tvar avatar_url = null\n\tvar lang_tag = null\n\tvar location = null\n\tvar timezone = null\n\tvar update_account_async_result: NakamaAsyncResult = await _client.update_account_async(_session, username, display_name, avatar_url, lang_tag, location, timezone)\n\n\tif update_account_async_result.is_exception():\n\t\tpush_error(\"Error in update_account_async(): %s\" % update_account_async_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"ERROR_FAILED_TO_UPDATE_DISPLAY_NAME\"), update_account_async_result.exception.message])\n\t\t_set_state(NakamaConnection.State.FAILED_TO_CONNECT)\n\t\t\n\t\treturn\n\n# \tEstablish connection (socket)\n\tif _socket == null:\n\t\t_socket = Nakama.create_socket_from(_client)\n\n\t\tvar connect_async_result: NakamaAsyncResult = await _socket.connect_async(_session)\n\t\tif connect_async_result.is_exception():\n\t\t\tpush_error(\"Error in connect_async(): %s\" % connect_async_result)\n\t\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"ERROR_FAILED_TO_CONNECT\"), connect_async_result.exception.message])\n\t\t\t_set_state(NakamaConnection.State.FAILED_TO_CONNECT)\n\t\t\t_socket = null\n\t\t\t\n\t\t\treturn\n\n\t\t_set_state(NakamaConnection.State.CONNECTED)\n\n\nfunc get_state() -> State:\n\treturn _state\n\n\nfunc get_client() -> NakamaClient:\n\treturn _client\n\n\nfunc get_session() -> NakamaSession:\n\treturn _session\n\n\nfunc get_socket() -> NakamaSocket:\n\treturn _socket\n\n\nfunc get_display_name_of_user(user_id: String) -> String:\n\treturn _user_id_to_display_name_map.get(user_id, \"\")\n\n\nfunc set_display_name_of_user(user_id: String, display_name_raw: String):\n\tvar display_name_sanitized: String = SanitizeText.sanitize_player_name(display_name_raw)\n\t\n\t_user_id_to_display_name_map[user_id] = display_name_sanitized\n\n\nfunc get_local_user_id() -> String:\n\tvar local_user_id: String = _session.user_id\n\n\treturn local_user_id\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _set_state(value: State):\n\t_state = value\n\tstate_changed.emit()\n"
  },
  {
    "path": "src/singletons/player_experience.gd",
    "content": "extends Node\n\n\n# Functions for converting player experience to player level.\n\n# NOTE: this class duplicates some code from \"Experience\"\n# class which is used for tower experience. Need two\n# separate versions of experience f-ns because\n# get_level_at_exp() needs to be implemented differently for\n# player vs tower. For tower, it's possible to optimize that\n# f-n by pre-calculating 576 values (576exp=25lvl). For\n# player, experience maxes out at ~27000, which is too much\n# to pre-calculate.\n\nconst EXP_FOR_LEVEL_PATH: String = \"res://data/player_exp_for_level.csv\"\n\nenum ExpForLevelColumn {\n\tLEVEL = 0,\n\tEXPERIENCE,\n}\n\n# This map is loaded from csv file\nvar _exp_for_level_map: Dictionary = _load_exp_for_level_map()\n\n\n#########################\n###       Public      ###\n#########################\n\n# Returns how much experience is required to reach given\n# level\nfunc get_exp_for_level(level: int) -> int:\n\tvar value_for_invalid_level: int = 1000000\n\tvar experience: int = _exp_for_level_map.get(level, value_for_invalid_level)\n\n\treturn experience\n\n\n# Returns what level the player should be at when it has a\n# certain amount of experience\nfunc get_level_at_exp(player_exp: int) -> int:\n\tvar player_level: int = 0\n\n\tfor level in range(0, Constants.PLAYER_MAX_LEVEL + 1):\n\t\tvar exp_for_level: int = _exp_for_level_map[level]\n\t\tvar enough_exp: bool = player_exp >= exp_for_level\n\n\t\tif enough_exp:\n\t\t\tplayer_level = level\n\n\treturn player_level\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _load_exp_for_level_map() -> Dictionary:\n\tvar map: Dictionary = {}\n\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(EXP_FOR_LEVEL_PATH)\n\n\tfor csv_line in csv:\n\t\tvar level: int = csv_line[ExpForLevelColumn.LEVEL].to_int()\n\t\tvar experience: int = csv_line[ExpForLevelColumn.EXPERIENCE].to_int()\n\n\t\tmap[level] = experience\n\n\treturn map\n"
  },
  {
    "path": "src/singletons/player_manager.gd",
    "content": "extends Node\n\n\n# Provides global access to players.\n\n\nsignal players_created()\n\n\nvar _id_to_player_map: Dictionary = {}\nvar _enet_peer_id_to_player_map: Dictionary = {}\nvar _nakama_user_id_to_player_map: Dictionary = {}\nvar _player_list: Array[Player] = []\n\n\n#########################\n###       Public      ###\n#########################\n\n# Returns player which owns the local game client. In\n# singleplayer this is *the player*. In multiplayer, each\n# game client has it's own player instance.\n# NOTE: \"GetLocalPlayer()\" in JASS\nfunc get_local_player() -> Player:\n\tvar local_peer_id: int = multiplayer.get_unique_id()\n\tvar local_player: Player = get_player_by_peer_id(local_peer_id)\n\n\treturn local_player\n\n\n# NOTE: \"Player()\" in JASS\nfunc get_player(id: int) -> Player:\n\tif !_id_to_player_map.has(id):\n\t\tpush_error(\"Failed to find player for id \", id)\n\n\t\treturn null\n\n\tvar player: Player = _id_to_player_map[id]\n\n\treturn player\n\n\nfunc get_player_by_peer_id(peer_id: int) -> Player:\n\tif !_enet_peer_id_to_player_map.has(peer_id):\n\t\tpush_error(\"Failed to find player for peer id \", peer_id)\n\n\t\treturn null\n\n\tvar player: Player = _enet_peer_id_to_player_map[peer_id]\n\n\treturn player\n\n\nfunc get_player_by_nakama_user_id(user_id: String) -> Player:\n\tif !_nakama_user_id_to_player_map.has(user_id):\n\t\tpush_error(\"Failed to find player for nakama user id \", user_id)\n\n\t\treturn null\n\n\tvar player: Player = _nakama_user_id_to_player_map[user_id]\n\n\treturn player\n\n\nfunc get_player_list() -> Array[Player]:\n\treturn _player_list.duplicate()\n\n\nfunc reset():\n\t_id_to_player_map = {}\n\t_enet_peer_id_to_player_map = {}\n\t_nakama_user_id_to_player_map = {}\n\t_player_list = []\n\n\nfunc add_player(player: Player):\n\tvar id: int = player.get_id()\n\t_id_to_player_map[id] = player\n\t\n\tvar peer_id: int = player.get_peer_id()\n\t_enet_peer_id_to_player_map[peer_id] = player\n\n\tadd_child(player)\n\n# \tNOTE: need to sort player id list to ensure determinism in multiplayer\n\t_player_list.append(player)\n\t_player_list.sort_custom(\n\t\tfunc(a, b) -> bool:\n\t\t\treturn a.get_id() < b.get_id()\n\t\t\t)\n\n\nfunc send_players_created_signal():\n\tplayers_created.emit()\n"
  },
  {
    "path": "src/singletons/preloads.gd",
    "content": "extends Node\n\n\n# Stores preloaded resources, such as scenes and textures.\n# Need to preload scenes here instead of directly in scripts\n# to prevent cyclic references. Note that not all of these\n# scenes cause cyclic references.\n\n\nconst title_screen_scene: PackedScene = preload(\"res://src/ui/title_screen/title_screen.tscn\")\nconst game_scene_scene: PackedScene = preload(\"res://src/game_scene/game_scene.tscn\")\nconst item_button_scene: PackedScene = preload(\"res://src/ui/buttons/item_button.tscn\")\nconst tower_button_scene: PackedScene = preload(\"res://src/ui/buttons/tower_button.tscn\")\nconst floating_text_scene: PackedScene = preload(\"res://src/ui/hud/floating_text.tscn\")\nconst projectile_scene: PackedScene = preload(\"res://src/projectiles/projectile.tscn\")\nconst aura_scene: PackedScene = preload(\"res://src/buffs/aura.tscn\")\nconst buff_range_area_scene: PackedScene = preload(\"res://src/buffs/buff_range_area.tscn\")\nconst corpse_scene: PackedScene = preload(\"res://src/creeps/creep_corpse.tscn\")\nconst blood_pool_scene: PackedScene = preload(\"res://src/creeps/creep_blood_pool.tscn\")\nconst flying_item_scene: PackedScene = preload(\"res://src/ui/hud/flying_item.tscn\")\nconst autocast_button_scene: PackedScene = preload(\"res://src/ui/buttons/autocast_button.tscn\")\nconst autocast_scene: PackedScene = preload(\"res://src/towers/autocast.tscn\")\nconst placeholder_effect_scene: PackedScene = preload(\"res://src/effects/placeholder.tscn\")\nconst empty_slot_button_scene: PackedScene = preload(\"res://src/ui/buttons/empty_unit_button.tscn\")\nconst range_indicator_scene: PackedScene = preload(\"res://src/towers/range_indicator.tscn\")\nconst outline_shader: Material = preload(\"res://resources/shaders/glowing_outline.material\")\nconst player_scene: PackedScene = preload(\"res://src/player/player.tscn\")\nconst team_scene: PackedScene = preload(\"res://src/player/team.tscn\")\nconst tower_preview_scene: PackedScene = preload(\"res://src/towers/tower_preview.tscn\")\nconst tower_scene: PackedScene = preload(\"res://src/towers/tower.tscn\")\nconst buff_display_scene: PackedScene = preload(\"res://src/ui/unit_menu/buff_display.tscn\")\nconst fallback_buff_icon: Texture = preload(\"res://resources/icons/generic_icons/egg.tres\")\nconst builder_button_scene: PackedScene = preload(\"res://src/ui/buttons/builder_button.tscn\")\nconst ability_button_scene: PackedScene = preload(\"res://src/ui/buttons/ability_button.tscn\")\nconst inventory_slot_button_scene: PackedScene = preload(\"res://src/ui/buttons/inventory_slot_button.tscn\")\nconst mission_card: PackedScene = preload(\"res://src/ui/title_screen/missions_menu/mission_card.tscn\")\nconst mission_track_indicator_scene: PackedScene = preload(\"res://src/ui/hud/mission_track_indicator.tscn\")\nconst noto_sans_chinese_font: Font = preload(\"res://assets/fonts/NotoSansSC-Medium.ttf\")\nconst friz_font: Font = preload(\"res://assets/fonts/Friz Quadrata Std Medium.otf\")\n\n\nconst element_icons: Dictionary = {\n\tElement.enm.ICE: preload(\"res://resources/icons/elements/ice.tres\"),\n\tElement.enm.NATURE: preload(\"res://resources/icons/elements/nature.tres\"),\n\tElement.enm.ASTRAL: preload(\"res://resources/icons/elements/astral.tres\"),\n\tElement.enm.DARKNESS: preload(\"res://resources/icons/elements/darkness.tres\"),\n\tElement.enm.FIRE: preload(\"res://resources/icons/elements/fire.tres\"),\n\tElement.enm.IRON: preload(\"res://resources/icons/elements/iron.tres\"),\n\tElement.enm.STORM: preload(\"res://resources/icons/elements/storm.tres\"),\n}\n\n\nconst creep_scenes: Dictionary = {\n\t\"OrcChampion\": preload(\"res://src/creeps/instances/orc/orc_champion_creep.tscn\"),\n\t\"OrcAir\": preload(\"res://src/creeps/instances/orc/orc_air_creep.tscn\"),\n\t\"OrcBoss\": preload(\"res://src/creeps/instances/orc/orc_boss_creep.tscn\"),\n\t\"OrcMass\": preload(\"res://src/creeps/instances/orc/orc_mass_creep.tscn\"),\n\t\"OrcNormal\": preload(\"res://src/creeps/instances/orc/orc_normal_creep.tscn\"),\n\t\n\t\"ChallengeBoss\": preload(\"res://src/creeps/instances/challenge/challenge_boss_creep.tscn\"),\n\t\"ChallengeMass\": preload(\"res://src/creeps/instances/challenge/challenge_mass_creep.tscn\"),\n}\n"
  },
  {
    "path": "src/singletons/properties/README.md",
    "content": "This folder contains \"Property singletons\". These singletons load properties out of CSV files and then provide access to those properties via various getters.\n"
  },
  {
    "path": "src/singletons/properties/ability_properties.gd",
    "content": "extends Node\n\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tRANGE,\n\tTARGET_TYPE,\n\tICON_PATH,\n\tNAME,\n\tDESCRIPTION_SHORT,\n\tDESCRIPTION_LONG,\n}\n\nconst PROPERTIES_PATH = \"res://data/ability_properties.csv\"\n\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n#\tCheck paths\n\tvar id_list: Array = get_id_list()\n\tfor id in id_list:\n\t\tvar icon_path: String = AbilityProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid icon path for ability: %s\" % icon_path)\n\n\n# \tCheck range definitions\n\tfor id in id_list:\n\t\tvar ability_range: float = AbilityProperties.get_ability_range(id)\n\t\tvar target_type: TargetType = AbilityProperties.get_target_type(id)\n\t\tvar range_is_defined: bool = ability_range != 0\n\t\tvar target_type_is_defined: bool = target_type != null\n\t\tvar definition_mismatch: bool = range_is_defined != target_type_is_defined\n\n\t\tif definition_mismatch:\n\t\t\tvar ability_name: String = AbilityProperties.get_name_english(id)\n\t\t\tpush_error(\"Invalid ability config for ability %s. If ability has a range, then both ability range and target_type must be defined.\" % [ability_name])\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_name_english(id: int) -> String:\n\tvar name_english: String = _get_property(id, CsvProperty.NAME_ENGLISH)\n\n\treturn name_english\n\n\nfunc get_ability_range(id: int) -> float:\n\tvar string: String = _get_property(id, CsvProperty.RANGE)\n\tvar ability_range: float = string.to_float()\n\n\treturn ability_range\n\n\nfunc get_target_type(id: int) -> TargetType:\n\tvar string: String = _get_property(id, CsvProperty.TARGET_TYPE)\n\tvar target_type: TargetType = TargetType.convert_from_string(string)\n\n\treturn target_type\n\n\nfunc get_icon_path(id: int) -> String:\n\tvar icon_path: String = _get_property(id, CsvProperty.ICON_PATH)\n\n\treturn icon_path\n\n\nfunc get_ability_name(id: int) -> String:\n\tvar ability_name_text_id: String = _get_property(id, CsvProperty.NAME)\n\tvar ability_name: String = tr(ability_name_text_id)\n\n\treturn ability_name\n\n\nfunc get_description_short(id: int) -> String:\n\tvar description_short_text_id: String = _get_property(id, CsvProperty.DESCRIPTION_SHORT)\n\tvar description_short: String = tr(description_short_text_id)\n\n\treturn description_short\n\n\nfunc get_description_long(id: int) -> String:\n\tvar description_long_text_id: String = _get_property(id, CsvProperty.DESCRIPTION_LONG)\n\tvar description_long: String = tr(description_long_text_id)\n\n\treturn description_long\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(id: int, property: CsvProperty) -> String:\n\tif !_properties.has(id):\n\t\tpush_error(\"No properties for id: \", id)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[id]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n"
  },
  {
    "path": "src/singletons/properties/aura_properties.gd",
    "content": "extends Node\n\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tBUFF_TYPE,\n\tTARGET_SELF,\n\tRANGE,\n\tTARGET_TYPE,\n\tIS_HIDDEN,\n\tLEVEL,\n\tLEVEL_ADD,\n\tICON_PATH,\n\tNAME,\n\tDESCRIPTION_SHORT,\n\tDESCRIPTION_LONG,\n}\n\nconst PROPERTIES_PATH = \"res://data/aura_properties.csv\"\n\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n#\tCheck paths\n\tvar id_list: Array = get_id_list()\n\tfor id in id_list:\n\t\tvar icon_path: String = AuraProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid icon path for aura: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_name_english(id: int) -> String:\n\tvar name_english: String = _get_property(id, CsvProperty.NAME_ENGLISH)\n\n\treturn name_english\n\n\nfunc get_buff_type(id: int) -> String:\n\tvar buff_type: String = _get_property(id, CsvProperty.BUFF_TYPE)\n\n\treturn buff_type\n\n\nfunc get_target_self(id: int) -> bool:\n\tvar target_self_string: String = _get_property(id, CsvProperty.TARGET_SELF)\n\tvar target_self: bool = Utils.string_to_bool(target_self_string)\n\n\treturn target_self\n\n\nfunc get_aura_range(id: int) -> float:\n\tvar aura_range_string: String = _get_property(id, CsvProperty.RANGE)\n\tvar aura_range: float = aura_range_string.to_float()\n\n\treturn aura_range\n\n\nfunc get_level(id: int) -> int:\n\tvar level_string: String = _get_property(id, CsvProperty.LEVEL)\n\tvar level: int = level_string.to_int()\n\n\treturn level\n\n\nfunc get_level_add(id: int) -> int:\n\tvar level_add_string: String = _get_property(id, CsvProperty.LEVEL_ADD)\n\tvar level_add: int = level_add_string.to_int()\n\n\treturn level_add\n\n\nfunc get_target_type(id: int) -> TargetType:\n\tvar string: String = _get_property(id, CsvProperty.TARGET_TYPE)\n\tvar target_type: TargetType = TargetType.convert_from_string(string)\n\n\treturn target_type\n\n\n# NOTE: if this value is set to true, the aura won't be\n# shown as an ability icon in tower menu and won't be\n# included in tower tooltip.\nfunc get_is_hidden(id: int) -> bool:\n\tvar is_hidden_string: String = _get_property(id, CsvProperty.IS_HIDDEN)\n\tvar is_hidden: bool = Utils.string_to_bool(is_hidden_string)\n\n\treturn is_hidden\n\n\nfunc get_icon_path(id: int) -> String:\n\tvar icon_path: String = _get_property(id, CsvProperty.ICON_PATH)\n\n\treturn icon_path\n\n\nfunc get_aura_name(id: int) -> String:\n\tvar aura_name_text_id: String = _get_property(id, CsvProperty.NAME)\n\tvar aura_name: String = tr(aura_name_text_id)\n\n\treturn aura_name\n\n\nfunc get_description_short(id: int) -> String:\n\tvar description_short_text_id: String = _get_property(id, CsvProperty.DESCRIPTION_SHORT)\n\tvar description_short: String = tr(description_short_text_id)\n\n\treturn description_short\n\n\nfunc get_description_long(id: int) -> String:\n\tvar description_long_text_id: String = _get_property(id, CsvProperty.DESCRIPTION_LONG)\n\tvar description_long: String = tr(description_long_text_id)\n\n\treturn description_long\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(id: int, property: CsvProperty) -> String:\n\tif !_properties.has(id):\n\t\tpush_error(\"No properties for id: \", id)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[id]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n"
  },
  {
    "path": "src/singletons/properties/autocast_properties.gd",
    "content": "extends Node\n\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tHANDLER_FUNCTION,\n\tAUTOCAST_TYPE,\n\tCOOLDOWN,\n\tMANA_COST,\n\tCAST_RANGE,\n\tAUTO_RANGE,\n\tTARGET_SELF,\n\tIS_EXTENDED,\n\tBUFF_TYPE,\n\tBUFF_TARGET_TYPE,\n\tNUM_BUFFS_BEFORE_IDLE,\n\tCASTER_ART,\n\tTARGET_ART,\n\tICON_PATH,\n\tNAME,\n\tDESCRIPTION_SHORT,\n\tDESCRIPTION_LONG,\n}\n\nconst PROPERTIES_PATH = \"res://data/autocast_properties.csv\"\n\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n#\tCheck paths\n\tvar id_list: Array = get_id_list()\n\tfor id in id_list:\n\t\tvar icon_path: String = AutocastProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid icon path for autocast: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_name_english(id: int) -> String:\n\tvar name_english: String = _get_property(id, CsvProperty.NAME_ENGLISH)\n\n\treturn name_english\n\n\nfunc get_handler_function(id: int) -> String:\n\tvar handler_function: String = _get_property(id, CsvProperty.HANDLER_FUNCTION)\n\n\treturn handler_function\n\n\nfunc get_autocast_type(id: int) -> Autocast.Type:\n\tvar autocast_type_string: String = _get_property(id, CsvProperty.AUTOCAST_TYPE)\n\tvar autocast_type: Autocast.Type = Autocast.string_to_autocast_type(autocast_type_string)\n\n\treturn autocast_type\n\n\nfunc get_cooldown(id: int) -> float:\n\tvar cooldown_string: String = _get_property(id, CsvProperty.COOLDOWN)\n\tvar cooldown: float = cooldown_string.to_float()\n\n\treturn cooldown\n\n\nfunc get_mana_cost(id: int) -> int:\n\tvar mana_cost_string: String = _get_property(id, CsvProperty.MANA_COST)\n\tvar mana_cost: int = mana_cost_string.to_int()\n\n\treturn mana_cost\n\n\n# NOTE: cast_range is the range used when autocast is casted\n# by the player.\nfunc get_cast_range(id: int) -> float:\n\tvar cast_range_string: String = _get_property(id, CsvProperty.CAST_RANGE)\n\tvar cast_range: float = cast_range_string.to_float()\n\n\treturn cast_range\n\n\n# NOTE: auto_range is the range used when autocast is casted\n# automatically, without player input.\nfunc get_auto_range(id: int) -> float:\n\tvar auto_range_string: String = _get_property(id, CsvProperty.AUTO_RANGE)\n\tvar auto_range: float = auto_range_string.to_float()\n\n\treturn auto_range\n\n\nfunc get_target_self(id: int) -> bool:\n\tvar target_self_string: String = _get_property(id, CsvProperty.TARGET_SELF)\n\tvar target_self: bool = Utils.string_to_bool(target_self_string)\n\n\treturn target_self\n\n\nfunc get_is_extended(id: int) -> bool:\n\tvar is_extended_string: String = _get_property(id, CsvProperty.IS_EXTENDED)\n\tvar is_extended: bool = Utils.string_to_bool(is_extended_string)\n\n\treturn is_extended\n\n\nfunc get_buff_type(id: int) -> String:\n\tvar buff_type: String = _get_property(id, CsvProperty.BUFF_TYPE)\n\n\treturn buff_type\n\n\nfunc get_buff_target_type(id: int) -> TargetType:\n\tvar buff_type_string: String = _get_property(id, CsvProperty.BUFF_TARGET_TYPE)\n\tvar buff_target_type: TargetType = TargetType.convert_from_string(buff_type_string)\n\n\treturn buff_target_type\n\n\n# NOTE: this property is currently unused. In original\n# engine \"num_buffs_before_idle\" determines how many times\n# autocast is triggered before it checks whether tower is\n# still in combat. This is needed because in original engine\n# checking if tower is still in combat takes time. In godot\n# engine, combat check is instant so it looks like this\n# value isn't needed.\nfunc get_num_buffs_before_idle(id: int) -> int:\n\tvar string: String = _get_property(id, CsvProperty.\tNUM_BUFFS_BEFORE_IDLE)\n\tvar num_buffs_before_idle: int = string.to_int()\n\n\treturn num_buffs_before_idle\n\n\nfunc get_caster_art(id: int) -> String:\n\tvar caster_art: String = _get_property(id, CsvProperty.CASTER_ART)\n\n\treturn caster_art\n\n\nfunc get_target_art(id: int) -> String:\n\tvar target_art: String = _get_property(id, CsvProperty.TARGET_ART)\n\n\treturn target_art\n\n\nfunc get_icon_path(id: int) -> String:\n\tvar icon_path: String = _get_property(id, CsvProperty.ICON_PATH)\n\n\treturn icon_path\n\n\nfunc get_autocast_name(id: int) -> String:\n\tvar autocast_name_text_id: String = _get_property(id, CsvProperty.NAME)\n\tvar autocast_name: String = tr(autocast_name_text_id)\n\n\treturn autocast_name\n\n\nfunc get_description_short(id: int) -> String:\n\tvar description_short_text_id: String = _get_property(id, CsvProperty.DESCRIPTION_SHORT)\n\tvar description_short: String = tr(description_short_text_id)\n\n\treturn description_short\n\n\nfunc get_description_long(id: int) -> String:\n\tvar description_long_text_id: String = _get_property(id, CsvProperty.DESCRIPTION_LONG)\n\tvar description_long: String = tr(description_long_text_id)\n\n\treturn description_long\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(id: int, property: CsvProperty) -> String:\n\tif !_properties.has(id):\n\t\tpush_error(\"No properties for id: \", id)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[id]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n"
  },
  {
    "path": "src/singletons/properties/builder_properties.gd",
    "content": "extends Node\n\n\nconst PROPERTIES_PATH: String = \"res://data/builder_properties.csv\"\nconst BACKPACKER_BUILDER_ID: int = 19\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tSHORT_NAME,\n\tTIER,\n\tREQUIRED_LEVEL,\n\tSCRIPT_PATH,\n\tICON,\n\tDISPLAY_NAME,\n\tDESCRIPTION,\n}\n\n\nvar _properties: Dictionary = {}\nvar _string_to_id_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n\t_string_to_id_map = _make_string_to_id_map()\n\n#\tCheck BACKPACKER_BUILDER_ID\n\tvar backpacker_name: String = get_name_english(BACKPACKER_BUILDER_ID)\n\tif !backpacker_name.contains(\"Backpacker\"):\n\t\tpush_error(\"BACKPACKER_BUILDER_ID is incorrect.\")\n\n#\tCheck script paths\n\tvar builder_id_list: Array = get_id_list()\n\tfor builder_id in builder_id_list:\n\t\tvar script_path: String = get_script_path(builder_id)\n\t\tvar script_path_is_valid: bool = ResourceLoader.exists(script_path)\n\n\t\tif !script_path_is_valid:\n\t\t\tpush_error(\"Invalid builder script path: %s\" % script_path)\n\n\t\tvar icon_path: String = get_icon_path(builder_id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid builder icon path: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\n\nfunc get_id_list() -> Array:\n\tvar id_list: Array = _properties.keys()\n\tid_list.sort()\n\n\treturn id_list\n\n\nfunc get_name_english(builder: int) -> String:\n\tvar string: String = _get_property(builder, CsvProperty.NAME_ENGLISH)\n\n\treturn string\n\n\nfunc get_display_name(builder: int) -> String:\n\tvar string_text_id: String = _get_property(builder, CsvProperty.DISPLAY_NAME)\n\tvar string: String = tr(string_text_id)\n\n\treturn string\n\n\nfunc get_short_name(builder: int) -> String:\n\tvar string: String = _get_property(builder, CsvProperty.SHORT_NAME)\n\n\treturn string\n\n\nfunc get_tier(builder: int) -> BuilderTier.enm:\n\tvar tier_string: String = _get_property(builder, CsvProperty.TIER)\n\tvar tier: BuilderTier.enm = BuilderTier.from_string(tier_string)\n\n\treturn tier\n\n\nfunc get_required_level(builder: int) -> int:\n\tvar required_level: int = _get_property(builder, CsvProperty.REQUIRED_LEVEL) as int\n\n\treturn required_level\n\n\nfunc get_script_path(builder: int) -> String:\n\tvar script_path: String = _get_property(builder, CsvProperty.SCRIPT_PATH)\n\n\treturn script_path\n\n\nfunc get_icon_path(builder: int) -> String:\n\tvar icon_path: String = _get_property(builder, CsvProperty.ICON)\n\n\treturn icon_path\n\n\nfunc get_description(builder: int) -> String:\n\tvar string_text_id: String = _get_property(builder, CsvProperty.DESCRIPTION)\n\tvar string: String = tr(string_text_id)\n\n\treturn string\n\n\nfunc string_to_id(string: String) -> int:\n\tif _string_to_id_map.has(string):\n\t\treturn _string_to_id_map[string]\n\telse:\n\t\tpush_error(\"Invalid string: \\\"%s\\\". Possible values: %s\" % [string, _string_to_id_map.keys()])\n\n\t\treturn 0\n\n\nfunc string_is_valid_builder(string: String) -> bool:\n\treturn _string_to_id_map.has(string)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(builder: int, property: BuilderProperties.CsvProperty) -> String:\n\tif !_properties.has(builder):\n\t\tpush_error(\"No properties for builder: \", builder)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[builder]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n\n\nfunc _make_string_to_id_map() -> Dictionary:\n\tvar map: Dictionary = {}\n\n\tvar id_list: Array = BuilderProperties.get_id_list()\n\n\tfor id in id_list:\n\t\tvar short_name: String = BuilderProperties.get_short_name(id)\n\n\t\tmap[short_name] = id\n\n\treturn map\n"
  },
  {
    "path": "src/singletons/properties/item_properties.gd",
    "content": "extends Node\n\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tTYPE,\n\tAUTHOR,\n\tRARITY,\n\tCOST,\n\tREQUIRED_WAVE_LEVEL,\n\tSPECIALS,\n\tABILITY_LIST,\n\tAURA_LIST,\n\tAUTOCAST_LIST,\n\tSCRIPT_PATH,\n\tICON,\n\tNAME,\n\tDESCRIPTION\n}\n\nconst PROPERTIES_PATH = \"res://data/item_properties.csv\"\n# NOTE: this id needs to be updated if it's changed in csv\nconst CONSUMABLE_CHICKEN_ID: int = 2003\nconst PLACEHOLDER_ITEM_ICON: String = \"res://resources/icons/animals/cow.tres\"\n\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n#\tCheck script paths\n\tvar id_list: Array = get_item_id_list()\n\tfor id in id_list:\n\t\tvar script_path: String = ItemProperties.get_script_path(id)\n\t\tvar script_path_is_valid: bool = ResourceLoader.exists(script_path)\n\n\t\tif !script_path_is_valid:\n\t\t\tpush_error(\"Invalid item script path item: %s\" % script_path)\n\n\t\tvar icon_path: String = ItemProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid item icon path: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_specials_modifier(item_id: int) -> Modifier:\n\tvar string: String = _get_property(item_id, CsvProperty.SPECIALS)\n\t\n\tif string.is_empty():\n\t\treturn Modifier.new()\n\n\tvar modifier: Modifier = Modifier.convert_from_string(string)\n\n\treturn modifier\n\n\nfunc get_ability_id_list(item_id: int) -> Array[int]:\n\tvar string: String = _get_property(item_id, CsvProperty.ABILITY_LIST)\n\tvar ability_id_list: Array[int] = UtilsStatic.convert_string_to_id_list(string)\n\n\treturn ability_id_list\n\n\nfunc get_aura_id_list(item_id: int) -> Array[int]:\n\tvar string: String = _get_property(item_id, CsvProperty.AURA_LIST)\n\tvar aura_id_list: Array[int] = UtilsStatic.convert_string_to_id_list(string)\n\n\treturn aura_id_list\n\n\nfunc get_autocast_id_list(item_id: int) -> Array[int]:\n\tvar string: String = _get_property(item_id, CsvProperty.AUTOCAST_LIST)\n\tvar autocast_id_list: Array[int] = UtilsStatic.convert_string_to_id_list(string)\n\n\treturn autocast_id_list\n\n\nfunc get_script_path(item_id: int):\n\tvar script_path: String = _get_property(item_id, CsvProperty.SCRIPT_PATH)\n\n\treturn script_path\n\n\nfunc get_item_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_id_list_by_filter(item_property: CsvProperty, filter_value: String) -> Array:\n\tvar all_item_list: Array = _properties.keys()\n\tvar result_list: Array = filter_item_id_list(all_item_list, item_property, filter_value)\n\n\treturn result_list\n\n\nfunc filter_item_id_list(item_list: Array, item_property: CsvProperty, filter_value: String) -> Array:\n\tvar result_list = []\n\tfor item_id in item_list:\n\t\tif _properties[item_id][item_property] == filter_value:\n\t\t\tresult_list.append(item_id)\n\treturn result_list\n\n\nfunc get_icon(item_id: int) -> Texture2D:\n\tvar icon_path: String = ItemProperties.get_icon_path(item_id)\n\tvar icon_path_exists: bool = ResourceLoader.exists(icon_path)\n\n\tif !icon_path_exists:\n\t\tpush_error(\"Icon path doesn't exist, loading placeholder.\")\n\n\t\ticon_path = PLACEHOLDER_ITEM_ICON\n\t\n\tvar item_icon: Texture2D = load(icon_path)\n\n\treturn item_icon\n\n\nfunc get_display_name(item_id: int) -> String:\n\tvar display_name_text_id: String = _get_property(item_id, CsvProperty.NAME)\n\tvar display_name: String = tr(display_name_text_id)\n\n\treturn display_name\n\n\nfunc get_author(item_id: int) -> String:\n\treturn _get_property(item_id, CsvProperty.AUTHOR)\n\n\nfunc get_rarity(item_id: int) -> Rarity.enm:\n\tvar rarity_string: String = _get_property(item_id, CsvProperty.RARITY)\n\tvar rarity: Rarity.enm = Rarity.convert_from_string(rarity_string)\n\n\treturn rarity\n\n\nfunc get_cost(item_id: int) -> int:\n\treturn _get_property(item_id, CsvProperty.COST).to_int()\n\n\nfunc get_description(item_id: int) -> String:\n\tvar description_text_id: String = _get_property(item_id, CsvProperty.DESCRIPTION)\n\tvar description: String = tr(description_text_id)\n\n\treturn description\n\n\nfunc get_required_wave_level(item_id: int) -> int:\n\treturn _get_property(item_id, CsvProperty.REQUIRED_WAVE_LEVEL).to_int()\n\n\nfunc get_icon_path(item_id: int) -> String:\n\tvar icon_path: String = _get_property(item_id, CsvProperty.ICON)\n\n\treturn icon_path\n\n\nfunc get_tooltip_text(item_id: int) -> String:\n\tvar item_name: String = get_display_name(item_id)\n\tvar item_description: String = get_description(item_id)\n\tvar text: String = \"%s\\n%s\" % [item_name, item_description]\n\n\treturn text\n\n\nfunc get_type(item_id: int) -> ItemType.enm:\n\tvar type_name: String = _get_property(item_id, CsvProperty.TYPE)\n\tvar type: ItemType.enm = ItemType.from_string(type_name)\n\n\treturn type\n\n\nfunc get_is_oil(item_id: int) -> bool:\n\tvar type: ItemType.enm = get_type(item_id)\n\tvar is_oil: bool = type == ItemType.enm.OIL\n\n\treturn is_oil\n\n\nfunc is_consumable(item_id: int) -> bool:\n\tvar item_type: ItemType.enm = ItemProperties.get_type(item_id)\n\tvar result: bool = item_type == ItemType.enm.CONSUMABLE\n\n\treturn result\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(item: int, property: CsvProperty) -> String:\n\tif !_properties.has(item):\n\t\tpush_error(\"No properties for item: \", item)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[item]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n"
  },
  {
    "path": "src/singletons/properties/mission_properties.gd",
    "content": "extends Node\n\n\n# Stores mission properties. For controlling mission state,\n# see mission_manager.gd.\n\n\nenum CsvProperty {\n\tID,\n\tSECTION,\n\tDESCRIPTION,\n\tSCRIPT_PATH,\n\tWAVE_COUNT,\n\tGAME_MODE,\n\tDIFFICULTY,\n\tBUILDER,\n}\n\nconst PROPERTIES_PATH: String = \"res://data/mission_properties.csv\"\nconst BUILDER_ANY_STRING: String = \"any\"\nconst BUILDER_ANY_ID: int = -1\nconst SECTION_LIST: Array = [\"general\", \"builders\", \"elements\", \"special\"]\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\t\n\tvar id_list: Array = get_id_list()\n\t\n#\tCheck values in CSV\n\tfor id in id_list:\n\t\tvar script_path: String = MissionProperties.get_script_path(id)\n\t\tvar script_exists: bool = ResourceLoader.exists(script_path)\n\t\t\n\t\tif !script_exists:\n\t\t\tpush_error(\"Mission %d has invalid script path: %s!\" % [id, script_path])\n\n\t\tvar builder_string: String = _get_property(id, CsvProperty.BUILDER)\n\t\tvar builder_is_valid: bool = builder_string == BUILDER_ANY_STRING || BuilderProperties.string_is_valid_builder(builder_string)\n\t\tif !builder_is_valid:\n\t\t\tpush_error(\"Mission %d has invalid builder: %s!\" % [id, builder_string])\n\n\t\tvar section: String = MissionProperties.get_section(id)\n\t\tvar section_is_valid: bool = SECTION_LIST.has(section)\n\t\tif !section_is_valid:\n\t\t\tpush_error(\"Mission %d has invalid section: %s!\" % [id, section])\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_section(id: int) -> String:\n\tvar section: String = _get_property(id, CsvProperty.SECTION)\n\n\treturn section\n\n\nfunc get_description(id: int) -> String:\n\tvar description_text_id: String = _get_property(id, CsvProperty.DESCRIPTION)\n\tvar description: String = tr(description_text_id)\n\n\treturn description\n\n\nfunc get_script_path(id: int) -> String:\n\tvar script_path: String = _get_property(id, CsvProperty.SCRIPT_PATH)\n\n\treturn script_path\n\n\nfunc get_wave_count(id: int) -> int:\n\tvar wave_count: int = _get_property(id, CsvProperty.WAVE_COUNT) as int\n\n\treturn wave_count\n\n\nfunc get_game_mode(id: int) -> GameMode.enm:\n\tvar game_mode_string: String = _get_property(id, CsvProperty.GAME_MODE)\n\tvar game_mode: GameMode.enm = GameMode.from_string(game_mode_string)\n\n\treturn game_mode\n\n\nfunc get_difficulty(id: int) -> Difficulty.enm:\n\tvar difficulty_string: String = _get_property(id, CsvProperty.DIFFICULTY)\n\tvar difficulty: Difficulty.enm = Difficulty.from_string(difficulty_string)\n\n\treturn difficulty\n\n\nfunc get_builder(id: int) -> int:\n\tvar builder_string: String = _get_property(id, CsvProperty.BUILDER)\n\n\tif builder_string == BUILDER_ANY_STRING:\n\t\treturn BUILDER_ANY_ID\n\n\tvar builder_id: int = BuilderProperties.string_to_id(builder_string)\n\n\treturn builder_id\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(id: int, csv_property: CsvProperty) -> String:\n\tif !_properties.has(id):\n\t\tpush_error(\"Invalid mission id: \", id)\n\n\t\treturn \"\"\n\t\n\tvar properties: Dictionary = _properties[id]\n\tvar value: String = properties[csv_property]\n\n\treturn value\n"
  },
  {
    "path": "src/singletons/properties/recipe_properties.gd",
    "content": "extends Node\n\n\nconst PROPERTIES_PATH: String = \"res://data/recipe_properties.csv\"\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tPERMANENT_COUNT,\n\tUSABLE_COUNT,\n\tRESULT_ITEM_TYPE,\n\tRESULT_COUNT,\n\tRARITY_CHANGE,\n\tLVL_BONUS_MIN,\n\tLVL_BONUS_MAX,\n\tUNLOCKED_BY_BACKPACKER,\n\tDISPLAY_NAME,\n\tDESCRIPTION,\n}\n\n\nconst _permanent_type_list: Array[ItemType.enm] = [ItemType.enm.REGULAR]\nconst _usable_type_list: Array[ItemType.enm] = [ItemType.enm.OIL, ItemType.enm.CONSUMABLE]\n\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n\n#########################\n###       Public      ###\n#########################\n\n\nfunc get_id_list() -> Array:\n\tvar id_list: Array = _properties.keys()\n\tid_list.sort()\n\n\treturn id_list\n\n\nfunc get_display_name(recipe: int) -> String:\n\tvar string_text_id: String = _get_property(recipe, CsvProperty.DISPLAY_NAME)\n\tvar string: String = tr(string_text_id)\n\n\treturn string\n\n\nfunc get_permanent_count(recipe: int) -> int:\n\tvar permanent_count: int = _get_property(recipe, CsvProperty.PERMANENT_COUNT) as int\n\n\treturn permanent_count\n\n\nfunc get_usable_count(recipe: int) -> int:\n\tvar usable_count: int = _get_property(recipe, CsvProperty.USABLE_COUNT) as int\n\n\treturn usable_count\n\n\nfunc get_result_item_type(recipe: int) -> Array[ItemType.enm]:\n\tvar result_item_type_string: String = _get_property(recipe, CsvProperty.RESULT_ITEM_TYPE)\n\tvar result_item_type: Array[ItemType.enm]\n\tif result_item_type_string == \"permanent\":\n\t\tresult_item_type = _permanent_type_list\n\telif result_item_type_string == \"usable\":\n\t\tresult_item_type = _usable_type_list\n\telif result_item_type_string == \"none\":\n\t\tresult_item_type = []\n\n\treturn result_item_type\n\n\nfunc get_result_count(recipe: int) -> int:\n\tvar result_count: int = _get_property(recipe, CsvProperty.RESULT_COUNT) as int\n\n\treturn result_count\n\n\nfunc get_rarity_change(recipe: int) -> int:\n\tvar rarity_change: int = _get_property(recipe, CsvProperty.RARITY_CHANGE) as int\n\n\treturn rarity_change\n\n\nfunc get_lvl_bonus_min(recipe: int) -> int:\n\tvar lvl_bonus_min: int = _get_property(recipe, CsvProperty.LVL_BONUS_MIN) as int\n\n\treturn lvl_bonus_min\n\n\nfunc get_lvl_bonus_max(recipe: int) -> int:\n\tvar lvl_bonus_max: int = _get_property(recipe, CsvProperty.LVL_BONUS_MAX) as int\n\n\treturn lvl_bonus_max\n\n\nfunc get_unlocked_by_backpacker(recipe: int) -> bool:\n\tvar value: bool = _get_property(recipe, CsvProperty.UNLOCKED_BY_BACKPACKER) == \"TRUE\"\n\n\treturn value\n\n\nfunc get_description(recipe: int) -> String:\n\tvar description_text_id: String = _get_property(recipe, CsvProperty.DESCRIPTION)\n\tvar description: String = tr(description_text_id)\n\n\treturn description\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(recipe: int, property: CsvProperty) -> String:\n\tif !_properties.has(recipe):\n\t\tpush_error(\"No properties for recipe: \", recipe)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[recipe]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n"
  },
  {
    "path": "src/singletons/properties/tower_properties.gd",
    "content": "extends Node\n\n\n# NOTE: order of CsvProperty enums must match the order of\n# the columns in tower_properties.csv\nenum CsvProperty {\n\tNAME_ENGLISH,\n\tTIER,\n\tID,\n\tFAMILY_ID,\n\tAUTHOR,\n\tRARITY,\n\tELEMENT,\n\tATTACK_ENABLED,\n\tATTACK_TYPE,\n\tATTACK_RANGE,\n\tATTACK_CD,\n\tATTACK_DAMAGE_MIN,\n\tATTACK_DAMAGE_MAX,\n\tMANA,\n\tMANA_REGEN,\n\tCOST,\n\tMISSILE_SPEED,\n\tMISSILE_ARC,\n\tMISSILE_USE_LIGHTNING_VISUAL,\n\tATTACK_TARGET_TYPE,\n\tMULTISHOT,\n\tSPLASH_ATTACK,\n\tBOUNCE_ATTACK,\n\tSPECIALS,\n\tABILITY_LIST,\n\tAURA_LIST,\n\tAUTOCAST_LIST,\n\tSCRIPT_PATH,\n\tICON_PATH,\n\tSPRITE_PATH,\n\tNAME,\n\tDESCRIPTION,\n}\n\n\nenum RangeColumn {\n\tTOWER_ID,\n\tNAME,\n\tRADIUS,\n\tTARGETS_CREEPS,\n\tAFFECTED_BY_BUILDER,\n\tCOUNT\n}\n\nconst PROPERTIES_PATH = \"res://data/tower_properties.csv\"\nconst TOWER_SPRITES_DIR: String = \"res://src/towers/tower_sprites\"\nconst TOWER_BEHAVIORS_DIR: String = \"res://src/towers/tower_behaviors\"\nconst TOWER_ICON_DIR: String = \"res://resources/icons/tower_icons\"\nconst PLACEHOLDER_ITEM_ICON: String = \"res://resources/icons/tower_icons/abandoned_pit.tres\"\n\nconst REQUIRED_WAVE_MAX: int = 80\n\nvar _min_required_wave_for_build_mode = {\n\tRarity.enm.COMMON: 0,\n\tRarity.enm.UNCOMMON: 6,\n\tRarity.enm.RARE: 24,\n\tRarity.enm.UNIQUE: 60\n}\n\nvar _properties: Dictionary = {}\nvar _element_map: Dictionary = {}\nvar _attack_type_map: Dictionary = {}\nvar _rarity_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# NOTE: convert some property strings to enums in _ready()\n# so that we avoid this overhead during runtime.\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n\tfor tower_id in get_tower_id_list():\n\t\tvar element_string: String = _get_property(tower_id, CsvProperty.ELEMENT)\n\t\tvar element: Element.enm = Element.from_string(element_string)\n\n\t\tvar attack_type_string: String = _get_property(tower_id, CsvProperty.ATTACK_TYPE)\n\t\tvar attack_type: AttackType.enm = AttackType.from_string(attack_type_string)\n\n\t\tvar rarity_string: String = _get_property(tower_id, CsvProperty.RARITY)\n\t\tvar rarity: Rarity.enm = Rarity.convert_from_string(rarity_string)\n\t\t\n\t\t_element_map[tower_id] = element\n\t\t_attack_type_map[tower_id] = attack_type\n\t\t_rarity_map[tower_id] = rarity\n\n#\tCheck paths\n\tvar id_list: Array = TowerProperties.get_tower_id_list()\n\tfor id in id_list:\n\t\tvar sprite_path: String = TowerProperties.get_sprite_path(id)\n\t\tvar sprite_path_is_valid: bool = ResourceLoader.exists(sprite_path)\n\t\tif !sprite_path_is_valid:\n\t\t\tpush_error(\"Invalid tower sprite path: %s\" % sprite_path)\n\t\t\n\t\tvar script_path: String = TowerProperties.get_script_path(id)\n\t\tvar script_path_is_valid: bool = ResourceLoader.exists(script_path)\n\t\tif !script_path_is_valid:\n\t\t\tpush_error(\"Invalid tower script path: %s\" % script_path)\n\n\t\tvar icon_path: String = TowerProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid tower icon path: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_properties(tower_id: int) -> Dictionary:\n\tif _properties.has(tower_id):\n\t\tvar out: Dictionary = _properties[tower_id]\n\n\t\treturn out\n\telse:\n\t\treturn {}\n\n\nfunc get_tower_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_tower_id_list_by_filter(tower_property: CsvProperty, filter_value: String) -> Array:\n\tvar result_list = []\n\tfor tower_id in _properties.keys():\n\t\tif _properties[tower_id][tower_property] == filter_value:\n\t\t\tresult_list.append(tower_id)\n\treturn result_list\n\n\nfunc get_tier(tower_id: int) -> int:\n\treturn _get_property(tower_id, CsvProperty.TIER).to_int()\n\n\nfunc get_icon_path(tower_id: int) -> String:\n\tvar icon_path: String = _get_property(tower_id, CsvProperty.ICON_PATH)\n\n\treturn icon_path\n\n\nfunc get_icon(item_id: int) -> Texture2D:\n\tvar icon_path: String = TowerProperties.get_icon_path(item_id)\n\tvar icon_path_exists: bool = ResourceLoader.exists(icon_path)\n\n\tif !icon_path_exists:\n\t\tpush_error(\"Icon path doesn't exist, loading placeholder.\")\n\n\t\ticon_path = PLACEHOLDER_ITEM_ICON\n\t\n\tvar item_icon: Texture2D = load(icon_path)\n\n\treturn item_icon\n\n\nfunc get_element(tower_id: int) -> Element.enm:\n\tvar element: Element.enm = _element_map[tower_id]\n\n\treturn element\n\n\nfunc get_rarity(tower_id: int) -> Rarity.enm:\n\tvar rarity: Rarity.enm = _rarity_map[tower_id]\n\n\treturn rarity\n\t\n\nfunc get_display_name(tower_id: int) -> String:\n\tvar name_text_id: String = _get_property(tower_id, CsvProperty.NAME)\n\tvar display_name: String = tr(name_text_id)\n\n\treturn display_name\n\n\nfunc get_cost(tower_id: int) -> int:\n\tvar cost: int = _get_property(tower_id, CsvProperty.COST) as int\n\n\treturn cost\n\n\nfunc get_missile_speed(tower_id: int) -> int:\n\tvar speed: int = _get_property(tower_id, CsvProperty.MISSILE_SPEED) as int\n\n\treturn speed\n\n\n# NOTE: need to use this formula for missile arc because\n# original values for Missilearc were defined to be consumed\n# by projectile code in wc3 engine. In youtd2, we give this\n# value to create_linear_interpolation() f-n which consumes\n# it slightly differently. WC3 engine uses missilearc to\n# determine the launch angle (multiply arc value by 45\n# degrees). Youtd linear interpolation uses angle to\n# determine the max height of the arc (multiply arc value by\n# travel distance). Use a formula to get something close to\n# original WC3 trajectory.\n# \n# Note that I'm not 100% sure that WC3 engine uses 45\n# degrees and not 60 or something higher but this is close\n# enough.\nfunc get_missile_arc(tower_id: int) -> float:\n\tvar arc_from_csv: float = _get_property(tower_id, CsvProperty.MISSILE_ARC) as float\n\tvar arc: float = 0.5 * sin(arc_from_csv * deg_to_rad(45)) \n\n\treturn arc\n\n\nfunc get_missile_use_lightning_visual(tower_id: int) -> bool:\n\tvar value: bool = _get_property(tower_id, CsvProperty.MISSILE_USE_LIGHTNING_VISUAL) == \"TRUE\"\n\n\treturn value\n\n\nfunc get_attack_target_type(tower_id: int) -> TargetType:\n\tvar string: String = _get_property(tower_id, CsvProperty.ATTACK_TARGET_TYPE)\n\tvar attack_target_type: TargetType = TargetType.convert_from_string(string)\n\n\treturn attack_target_type\n\n\nfunc get_multishot(tower_id: int) -> int:\n\tvar string: String = _get_property(tower_id, CsvProperty.MULTISHOT)\n\tvar multishot: int\n\tif !string.is_empty():\n\t\tmultishot = string.to_int()\n\telse:\n\t\tmultishot = 1\n\n\treturn multishot\n\n\nfunc get_splash_attack(tower_id: int) -> Dictionary:\n\tvar string: String = _get_property(tower_id, CsvProperty.SPLASH_ATTACK)\n\t\n\tif string.is_empty():\n\t\treturn {}\n\t\n\tvar value_list: Array = string.split(\",\")\n\tvar result: Dictionary = {}\n\n\tfor i in range(0, value_list.size(), 2):\n\t\tvar splash_range: float = value_list[i].to_float()\n\t\tvar splash_multiplier: float = value_list[i + 1].to_float()\n\n\t\tresult[splash_range] = splash_multiplier\n\n\treturn result\n\n\nfunc get_bounce_attack(tower_id: int) -> Array:\n\tvar string: String = _get_property(tower_id, CsvProperty.BOUNCE_ATTACK)\n\t\n\tif string.is_empty():\n\t\treturn []\n\t\n\tvar string_list: Array = string.split(\",\")\n\tvar value_list: Array = []\n\n\tif string_list.size() == 2:\n\t\tvalue_list.append(string_list[0].to_int())\n\t\tvalue_list.append(string_list[1].to_float())\n\telse:\n\t\tvalue_list = []\n\n\treturn value_list\n\n\nfunc get_specials_modifier(tower_id: int) -> Modifier:\n\tvar string: String = _get_property(tower_id, CsvProperty.SPECIALS)\n\t\n\tif string.is_empty():\n\t\treturn Modifier.new()\n\n\tvar modifier: Modifier = Modifier.convert_from_string(string)\n\n\treturn modifier\n\n\nfunc get_sell_price(tower_id: int) -> int:\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar sell_ratio: float = GameMode.get_sell_ratio(game_mode)\n\tvar cost: float = TowerProperties.get_cost(tower_id)\n\tvar sell_price: int = floori(cost * sell_ratio)\n\n\treturn sell_price\n\n\nfunc get_description(tower_id: int) -> String:\n\tvar description_text_id: String = _get_property(tower_id, CsvProperty.DESCRIPTION)\n\tvar description: String = tr(description_text_id)\n\n\treturn description\n\n\nfunc get_author(tower_id: int) -> String:\n\tvar author: String = _get_property(tower_id, CsvProperty.AUTHOR)\n\n\treturn author\n\n\nfunc get_damage_min(tower_id: int) -> int:\n\tvar damage_min: int = _get_property(tower_id, CsvProperty.ATTACK_DAMAGE_MIN).to_int()\n\n\treturn damage_min\n\n\nfunc get_damage_max(tower_id: int) -> int:\n\tvar damage_max: int = _get_property(tower_id, CsvProperty.ATTACK_DAMAGE_MAX).to_int()\n\n\treturn damage_max\n\n\nfunc get_base_damage(tower_id: int) -> int:\n\tvar base_damage: int = floor((get_damage_min(tower_id) + get_damage_max(tower_id)) / 2.0)\n\n\treturn base_damage\n\n\nfunc get_base_attack_speed(tower_id: int) -> float:\n\tvar attack_speed: float = _get_property(tower_id,  CsvProperty.ATTACK_CD).to_float()\n\n\tif attack_speed == 0.0:\n\t\tpush_error(\"Base attack speed for tower %d is equal to 0.0. Attack speed must greater than 0.0, even if the tower doesn't attack. Returning 1.0 instead.\")\n\n\t\treturn 1.0\n\n\treturn attack_speed\n\n\nfunc get_attack_enabled(tower_id: int) -> bool:\n\tvar attack_enabled: bool = _get_property(tower_id, CsvProperty.ATTACK_ENABLED) == \"TRUE\"\n\n\treturn attack_enabled\n\n\nfunc get_attack_type(tower_id: int) -> AttackType.enm:\n\tvar attack_type: AttackType.enm = _attack_type_map[tower_id]\n\n\treturn attack_type\n\n\nfunc get_range(tower_id: int) -> float:\n\tvar attack_range: float = _get_property(tower_id, CsvProperty.ATTACK_RANGE).to_float()\n\n\tif attack_range == 0.0:\n\t\tpush_error(\"Tower attack range must be greater than 0. Forcing value to 1.\")\n\n\t\tattack_range = 1\n\n\treturn attack_range\n\n\nfunc get_required_element_level(tower_id: int) -> int:\n\tconst element_level_to_min_cost_map: Dictionary = {\n\t\t1: 140,\n\t\t2: 215,\n\t\t3: 345,\n\t\t4: 500,\n\t\t5: 680,\n\t\t6: 900,\n\t\t7: 1080,\n\t\t8: 1300,\n\t\t9: 1550,\n\t\t10: 1850,\n\t\t11: 2130,\n\t\t12: 2440,\n\t\t13: 2750,\n\t\t14: 3100,\n\t\t15: 3500,\n\t}\n\n\tvar tower_cost: int = get_cost(tower_id)\n\n\tvar element_level: int = 1\n\n\tfor level in range(15, 0, -1):\n\t\tvar min_cost: int = element_level_to_min_cost_map[level]\n\n\t\tif tower_cost >= min_cost:\n\t\t\telement_level = level\n\n\t\t\tbreak\n\n\treturn element_level\n\n\n# NOTE: this formula is the inverse of the formula for tower cost\n# from TowerDistribution._get_max_cost()\nfunc get_required_wave_level(tower_id: int) -> int:\n# \tNOTE: prevent value inside sqrt() from going below 0\n# \tbecause sqrt() expects positive arg\n\tvar tower_cost: int = get_cost(tower_id)\n\tvar required_wave: int = ceili((sqrt(max(0.01, 60 * tower_cost - 3575)) - 25) / 6)\n\n\tvar required_wave_min: int\n\tif Globals.get_game_mode() == GameMode.enm.BUILD:\n\t\tvar rarity: Rarity.enm = TowerProperties.get_rarity(tower_id)\n\t\trequired_wave_min = _min_required_wave_for_build_mode[rarity]\n\telse:\n\t\trequired_wave_min = 0\n\n\trequired_wave = clampi(required_wave, required_wave_min, REQUIRED_WAVE_MAX)\n\n\treturn required_wave\n\n\nfunc wave_level_foo(tower_id: int, player: Player) -> bool:\n\tvar wave_level: int = player.get_team().get_level()\n\tvar required_wave_level: int = TowerProperties.get_required_wave_level(tower_id)\n\tvar out: bool = wave_level >= required_wave_level\n\n\treturn out\n\n\nfunc element_level_foo(tower_id: int, player: Player) -> bool:\n\tvar required_element_level: int = TowerProperties.get_required_element_level(tower_id)\n\tvar element: Element.enm = get_element(tower_id)\n\tvar element_research_level: int = player.get_element_level(element)\n\tvar out: bool = element_research_level >= required_element_level\n\n\treturn out\n\n\nfunc requirements_are_satisfied(tower_id: int, player: Player) -> bool:\n\tif Config.ignore_tower_requirements():\n\t\treturn true\n\n\tvar tier: int = TowerProperties.get_tier(tower_id)\n\n#\tNOTE: for random game modes, some towers do not have\n#\trequirements because they are obtained randomly from the\n#\ttower distribution game mechanic. Tower distribution\n#\talready has minimum requirements for when a tower can be\n#\trolled.\n# \n#\tFor \"random with upgrades\" mode, only the first tiers\n#\tcome from tower distribution. Other tiers still need\n#\trequirements.\n# \n#   For \"totally random\" mode, all towers come from tower\n#   distribution, so we can ignore requirements completely.\n\tif Globals.get_game_mode() == GameMode.enm.RANDOM_WITH_UPGRADES && tier == 1:\n\t\treturn true\n\telif Globals.get_game_mode() == GameMode.enm.TOTALLY_RANDOM:\n\t\treturn true\n\n\tvar out: bool = element_level_foo(tower_id, player) && wave_level_foo(tower_id, player)\n\n\treturn out\n\n\n# NOTE: tower.getFamily() in JASS\nfunc get_family(tower_id: int) -> int:\n\treturn _get_property(tower_id, CsvProperty.FAMILY_ID).to_int()\n\n\n# NOTE: sorted by tier\nfunc get_towers_in_family(family_id: int) -> Array:\n\tvar family_list: Array = get_tower_id_list_by_filter(CsvProperty.FAMILY_ID, str(family_id))\n\tfamily_list.sort_custom(func(a, b): \n\t\tvar tier_a: int = TowerProperties.get_tier(a)\n\t\tvar tier_b: int = TowerProperties.get_tier(b)\n\t\treturn tier_a < tier_b)\n\n\treturn family_list\n\n\nfunc get_food_cost(tower_id: int) -> int:\n\tvar food_cost_map: Dictionary = {\n\t\tRarity.enm.COMMON: 2,\n\t\tRarity.enm.UNCOMMON: 3,\n\t\tRarity.enm.RARE: 4,\n\t\tRarity.enm.UNIQUE: 6,\n\t}\n\tvar rarity: Rarity.enm = get_rarity(tower_id)\n\tvar food_cost: int = food_cost_map[rarity]\n\n\treturn food_cost\n\n\nfunc get_tome_cost(tower_id: int) -> int:\n\tif Globals.game_mode_is_random():\n\t\treturn 0\n\n\tvar tome_cost_map: Dictionary = {\n\t\tRarity.enm.COMMON: 0,\n\t\tRarity.enm.UNCOMMON: 4,\n\t\tRarity.enm.RARE: 10,\n\t\tRarity.enm.UNIQUE: 25,\n\t}\n\tvar rarity: Rarity.enm = get_rarity(tower_id)\n\tvar tome_cost: int = tome_cost_map[rarity]\n\n\treturn tome_cost\n\n\n# Inventory capacity is derived from tower cost and there\n# are also min/max values based on tower rarity.\n# \n# Examples:\n# \n# Energy Junction is an uncommon tower which costs 500. 500\n# is between 400 and 1200, so it's capacity is 2. Capacity of 2\n# fits within the [1,4] range of allowed capacities for\n# uncommon towers.\n# \n# Igloo is a rare tower and costs 700. 700 is between 400\n# and 1200 so it's capacity should be 2 BUT the minimum\n# capacity for rare towers is 3, so Igloo's capacity is 3.\nfunc get_inventory_capacity(tower_id: int) -> int:\n\tvar capacity_to_min_cost_map: Dictionary = {\n\t\t1: 0,\n\t\t2: 400,\n\t\t3: 1200,\n\t\t4: 1500,\n\t\t5: 1700,\n\t\t6: 2000,\n\t}\n\tvar min_capacity_map: Dictionary = {\n\t\tRarity.enm.COMMON: 1,\n\t\tRarity.enm.UNCOMMON: 1,\n\t\tRarity.enm.RARE: 3,\n\t\tRarity.enm.UNIQUE: 5,\n\t}\n\tvar max_capacity_map: Dictionary = {\n\t\tRarity.enm.COMMON: 4,\n\t\tRarity.enm.UNCOMMON: 4,\n\t\tRarity.enm.RARE: 5,\n\t\tRarity.enm.UNIQUE: 6,\n\t}\n\n\tvar tower_cost: int = get_cost(tower_id)\n\tvar tower_rarity: Rarity.enm = get_rarity(tower_id)\n\tvar min_capacity: int = min_capacity_map[tower_rarity]\n\tvar max_capacity: int = max_capacity_map[tower_rarity]\n\n\tvar result_capacity: int = 1\n\n\tfor capacity in range(max_capacity, 0, -1):\n\t\tvar min_cost: int = capacity_to_min_cost_map[capacity]\n\n\t\tif tower_cost >= min_cost:\n\t\t\tresult_capacity = clampi(capacity, min_capacity, max_capacity)\n\n\t\t\tbreak\n\n\tresult_capacity = min(result_capacity, Constants.INVENTORY_CAPACITY_MAX)\n\n\treturn result_capacity\n\n\nfunc get_dps(tower_id: int) -> float:\n\tvar damage: int = TowerProperties.get_base_damage(tower_id)\n\tvar attack_speed: float = TowerProperties.get_base_attack_speed(tower_id)\n\tvar dps: float = Utils.divide_safe(damage, attack_speed)\n\n\treturn dps\n\n\nfunc get_mana(tower_id: int) -> int:\n\tvar mana: int = _get_property(tower_id, CsvProperty.MANA) as int\n\n\treturn mana\n\n\nfunc get_mana_regen(tower_id: int) -> int:\n\tvar mana_regen: int = _get_property(tower_id, CsvProperty.MANA_REGEN) as int\n\n\treturn mana_regen\n\n\nfunc get_upgrade_id_for_tower(tower_id: int) -> int:\n\tvar family_id: int = get_family(tower_id)\n\tvar family_list: Array = get_towers_in_family(family_id)\n\tvar next_tier: int = get_tier(tower_id) + 1\n\n\tfor id in family_list:\n\t\tvar this_tier: int = get_tier(id)\n\n\t\tif this_tier == next_tier:\n\t\t\treturn id\n\t\n\treturn -1\n\n\nfunc get_range_data_list(tower_id: int) -> Array[RangeData]:\n\tvar range_data_list: Array[RangeData] = []\n\n\tvar attack_enabled: bool = TowerProperties.get_attack_enabled(tower_id)\n\tif attack_enabled:\n\t\tvar attack_range: float = TowerProperties.get_range(tower_id)\n\t\tvar ability_name_english: String = Constants.TOWER_ATTACK_ABILITY_NAME_ENGLISH\n\t\tvar ability_target_type: TargetType = TargetType.new(TargetType.CREEPS)\n\n\t\tvar range_data: RangeData = RangeData.new(ability_name_english, attack_range, ability_target_type, true)\n\t\trange_data_list.append(range_data)\n\n\tvar ability_id_list: Array = TowerProperties.get_ability_id_list(tower_id)\n\tfor ability_id in ability_id_list:\n\t\tvar ability_range: float = AbilityProperties.get_ability_range(ability_id)\n\t\t\n\t\tvar ability_has_range: bool = ability_range != 0\n\t\tif !ability_has_range:\n\t\t\tcontinue\n\n\t\tvar ability_name_english: String = AbilityProperties.get_name_english(ability_id)\n\t\tvar ability_target_type: TargetType = AbilityProperties.get_target_type(ability_id)\n\n\t\tvar range_data: RangeData = RangeData.new(ability_name_english, ability_range, ability_target_type)\n\t\trange_data_list.append(range_data)\n\n\tvar aura_id_list: Array = TowerProperties.get_aura_id_list(tower_id)\n\tfor aura_id in aura_id_list:\n\t\tvar aura_name_english: String = AuraProperties.get_name_english(aura_id)\n\t\tvar aura_range: float = AuraProperties.get_aura_range(aura_id)\n\t\tvar aura_target_type: TargetType = AuraProperties.get_target_type(aura_id)\n\n\t\tvar range_data: RangeData = RangeData.new(aura_name_english, aura_range, aura_target_type)\n\n#\t\tNOTE: only range of aura abilities are affected by\n#\t\tbuilder bonuses\n\t\trange_data.affected_by_builder = true\n\n\t\trange_data_list.append(range_data)\n\n\tvar autocast_id_list: Array = TowerProperties.get_autocast_id_list(tower_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast_range: float = AutocastProperties.get_cast_range(autocast_id)\n\t\t\n\t\tvar autocast_has_range: bool = autocast_range != 0\n\t\tif !autocast_has_range:\n\t\t\tcontinue\n\n\t\tvar autocast_name_english: String = AutocastProperties.get_name_english(autocast_id)\n\t\tvar autocast_type: Autocast.Type = AutocastProperties.get_autocast_type(autocast_id)\n\t\tvar autocast_buff_target_type: TargetType = AutocastProperties.get_buff_target_type(autocast_id)\n\t\tvar autocast_target_type: TargetType = Autocast.calculate_target_type(autocast_type, autocast_buff_target_type)\n\n\t\tvar range_data: RangeData = RangeData.new(autocast_name_english, autocast_range, autocast_target_type)\n\t\trange_data_list.append(range_data)\n\n\treturn range_data_list\n\n\nfunc get_sprite_path(tower_id: int) -> String:\n\tvar sprite_path: String = _get_property(tower_id, CsvProperty.SPRITE_PATH)\n\t\n\treturn sprite_path\n\n\nfunc get_ability_id_list(tower_id: int) -> Array[int]:\n\tvar string: String = _get_property(tower_id, CsvProperty.ABILITY_LIST)\n\tvar ability_id_list: Array[int] = UtilsStatic.convert_string_to_id_list(string)\n\n\treturn ability_id_list\n\n\nfunc get_aura_id_list(tower_id: int) -> Array[int]:\n\tvar string: String = _get_property(tower_id, CsvProperty.AURA_LIST)\n\tvar aura_id_list: Array[int] = UtilsStatic.convert_string_to_id_list(string)\n\n\treturn aura_id_list\n\n\nfunc get_autocast_id_list(tower_id: int) -> Array[int]:\n\tvar string: String = _get_property(tower_id, CsvProperty.AUTOCAST_LIST)\n\tvar autocast_id_list: Array[int] = UtilsStatic.convert_string_to_id_list(string)\n\n\treturn autocast_id_list\n\n\nfunc get_script_path(tower_id: int) -> String:\n\tvar script_path: String = _get_property(tower_id, CsvProperty.SCRIPT_PATH)\n\n\treturn script_path\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(tower_id: int, csv_property: CsvProperty) -> String:\n\tif !_properties.has(tower_id):\n\t\tpush_error(\"No properties for tower: \", tower_id)\n\n\t\treturn \"\"\n\t\n\tvar properties: Dictionary = _properties[tower_id]\n\tvar value: String = properties[csv_property]\n\n\treturn value\n"
  },
  {
    "path": "src/singletons/properties/tutorial_properties.gd",
    "content": "extends Node\n\n\nenum TutorialId {\n\tINTRO_FOR_RANDOM_MODE = 0,\n\tINTRO_FOR_BUILD_MODE,\n\tRESEARCH_ELEMENTS,\n\tROLL_TOWERS,\n\tTOWER_STASH,\n\tBUILD_TOWER,\n\tRESOURCES,\n\tTOWER_INFO,\n\tITEMS,\n\tTOWER_LEVELS,\n\tPORTAL_DAMAGE,\n\tWAVE_1_FINISHED,\n\tCHALLENGE_WAVE,\n\tUPGRADING,\n\tTRANSFORMING,\n\t\n\tCOUNT,\n}\n\nenum CsvProperty {\n\tTITLE_ENGLISH,\n\tTITLE,\n\tTEXT,\n}\n\nconst PROPERTIES_PATH = \"res://data/hints/tutorial.csv\"\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties_with_automatic_ids(PROPERTIES_PATH, _properties)\n\t\n\tfor id in range(1, TutorialId.COUNT):\n\t\tvar id_exists: bool = _properties.has(id)\n\t\t\n\t\tif !id_exists:\n\t\t\tpush_error(\"Missing tutorial with id %s\" % id)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_title(id: int) -> String:\n\tvar title_text_id: String = _get_property(id, CsvProperty.TITLE)\n\tvar title: String = tr(title_text_id)\n\t\n\treturn title\n\n\nfunc get_text(id: int) -> String:\n\tvar text_text_id: String = _get_property(id, CsvProperty.TEXT)\n\tvar text: String = tr(text_text_id)\n\t\n\treturn text\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(id: int, property: CsvProperty) -> String:\n\tif !_properties.has(id):\n\t\tpush_error(\"No properties for id: \", id)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[id]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n"
  },
  {
    "path": "src/singletons/properties/wave_special_properties.gd",
    "content": "extends Node\n\n\nconst PROPERTIES_PATH: String = \"res://data/wave_special_properties.csv\"\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tHP_MODIFIER,\n\tREQUIRED_WAVE_LEVEL,\n\tFREQUENCY,\n\tAPPLICABLE_SIZES,\n\tCHAMPION_OR_BOSS_WAVE_ONLY,\n\tGROUP_LIST,\n\tUSES_MANA,\n\tCOLOR,\n\tNAME,\n\tSHORT_NAME,\n\tDESCRIPTION,\n\tENABLED,\n\tSCRIPT_PATH,\n\tICON_PATH,\n}\n\nvar FLOCK: int\n\nvar _properties: Dictionary = {}\n# Map of group [String] to special [int]\nvar _group_to_special_map: Dictionary = {}\nvar _buff_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\t_group_to_special_map = _make_group_to_special_map()\n\n\tprint_verbose(\"_group_to_special_map = \", _group_to_special_map)\n\n#\tCheck paths\n\tvar id_list: Array = WaveSpecialProperties.get_all_specials_list()\n\tfor id in id_list:\n\t\tvar script_path: String = WaveSpecialProperties.get_script_path(id)\n\t\tvar script_path_is_valid: bool = ResourceLoader.exists(script_path)\n\t\tif !script_path_is_valid:\n\t\t\tpush_error(\"Invalid wave special script path: %s\" % script_path)\n\n\t\tvar icon_path: String = WaveSpecialProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid wave special icon path: %s\" % icon_path)\n\n#\tLoad buff types\n\tvar special_list: Array = WaveSpecialProperties.get_all_specials_list()\n\n\tfor special in special_list:\n\t\tvar script_path: String = WaveSpecialProperties.get_script_path(special)\n\n\t\tvar script: Script = load(script_path)\n\t\tvar special_bt: BuffType = script.new(self)\n\t\tvar special_name: String = WaveSpecialProperties.get_special_name(special)\n\t\tvar description: String = WaveSpecialProperties.get_description(special)\n\t\tvar tooltip: String = \"%s\\n%s\" % [special_name, description]\n\t\tspecial_bt.set_buff_tooltip(tooltip)\n\t\t\n\t\tspecial_bt.set_hidden()\n\t\t\n\t\t_buff_map[special] = special_bt\n\n\tFLOCK = _find_flock_id()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_all_specials_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_name_english(special: int) -> String:\n\tvar string: String = _get_property(special, CsvProperty.NAME_ENGLISH)\n\n\treturn string\n\n\nfunc get_special_name(special: int) -> String:\n\tvar string_text_id: String = _get_property(special, CsvProperty.NAME)\n\tvar string: String = tr(string_text_id)\n\n\treturn string\n\n\nfunc get_short_name(special: int) -> String:\n\tvar string_text_id: String = _get_property(special, CsvProperty.SHORT_NAME)\n\tvar string: String = tr(string_text_id)\n\n\treturn string\n\n\nfunc get_script_path(special: int) -> String:\n\tvar script_path: String = _get_property(special, CsvProperty.SCRIPT_PATH)\n\n\treturn script_path\n\n\nfunc get_icon_path(special: int) -> String:\n\tvar icon_path: String = _get_property(special, CsvProperty.ICON_PATH)\n\n\treturn icon_path\n\n\nfunc get_required_wave_level(special: int) -> int:\n\tvar level: int = _get_property(special, CsvProperty.REQUIRED_WAVE_LEVEL).to_int()\n\n\treturn level\n\n\nfunc get_frequency(special: int) -> int:\n\tvar frequency: int = _get_property(special, CsvProperty.FREQUENCY).to_int()\n\n\treturn frequency\n\n\n# NOTE: in case creep has multiple specials, we return color\n# of the first one. Mixing colors wouldn't look good.\nfunc get_base_color(special_list: Array[int]) -> Color:\n\tif special_list.is_empty():\n\t\treturn Color.WHITE\n\t\n\tvar first_special: int = special_list[0]\n\tvar color_html: String = _get_property(first_special, CsvProperty.COLOR)\n\tvar color: Color = Color.html(color_html)\n\n\treturn color\n\n\nfunc get_description(special: int) -> String:\n\tvar description_text_id: String = _get_property(special, CsvProperty.DESCRIPTION)\n\tvar description: String = tr(description_text_id)\n\n\treturn description\n\n\nfunc get_enabled(special: int) -> bool:\n\tvar enabled: bool = _get_property(special, CsvProperty.ENABLED) == \"TRUE\"\n\n\treturn enabled\n\n\nfunc get_applicable_sizes(special: int) -> Array[CreepSize.enm]:\n\tvar size_list_string: String = _get_property(special, CsvProperty.APPLICABLE_SIZES)\n\n\tif size_list_string == \"all\":\n\t\treturn [CreepSize.enm.MASS, CreepSize.enm.NORMAL, CreepSize.enm.AIR, CreepSize.enm.BOSS]\n\n\tvar size_list: Array[CreepSize.enm] = []\n\n\tvar size_string_list: Array = size_list_string.split(\",\")\n\n\tfor size_string in size_string_list:\n\t\tvar creep_size: CreepSize.enm = CreepSize.from_string(size_string)\n\t\tsize_list.append(creep_size)\n\n\treturn size_list\n\n\n# NOTE: this is separate from \"applicable sizes\" because\n# this defines if wave buff can apply to specific creep, not\n# the whole wave. For example if the wave is 10 normal + 1\n# champion, then special can apply to whole wave but the\n# buff portion will apply only to the champion. Note that\n# health modifiers still apply to whole wave.\nfunc get_champion_or_boss_wave_only(special: int) -> bool:\n\tvar champion_or_boss_wave_only: bool = _get_property(special, CsvProperty.CHAMPION_OR_BOSS_WAVE_ONLY) == \"TRUE\"\n\n\treturn champion_or_boss_wave_only\n\n\nfunc get_group_list(special: int) -> Array[String]:\n\tvar group_list_packed: PackedStringArray = _get_property(special, CsvProperty.GROUP_LIST).split(\",\")\n\t\n\tvar group_list: Array[String] = []\n\t\n\tfor group in group_list_packed:\n\t\tgroup_list.append(group)\n\n\treturn group_list\n\n\nfunc get_uses_mana(special: int) -> bool:\n\tvar uses_mana: bool = _get_property(special, CsvProperty.USES_MANA) == \"TRUE\"\n\n\treturn uses_mana\n\n\nfunc get_hp_modifier(special: int) -> float:\n\tvar hp_modifier: float = _get_property(special, CsvProperty.HP_MODIFIER) as float\n\n\treturn hp_modifier\n\n\nfunc get_specials_in_group(group: String) -> Array:\n\tvar special_list: Array = _group_to_special_map[group]\n\n\treturn special_list\n\n\nfunc get_special_buff(special_id: int) -> BuffType:\n\treturn _buff_map[special_id]\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(special: int, property: CsvProperty) -> String:\n\tif !_properties.has(special):\n\t\tpush_error(\"No properties for special: \", special)\n\n\t\treturn \"\"\n\n\tvar map: Dictionary = _properties[special]\n\tvar property_value: String = map[property]\n\n\treturn property_value\n\n\nfunc _make_group_to_special_map() -> Dictionary:\n\tvar result: Dictionary = {}\n\n\tvar special_list: Array = _properties.keys()\n\n\tfor special in special_list:\n\t\tvar group_list: Array[String] = get_group_list(special)\n\n\t\tfor group in group_list:\n\t\t\tif !result.has(group):\n\t\t\t\tresult[group] = []\n\n\t\t\tresult[group].append(special)\n\n\treturn result\n\n\nfunc _find_flock_id() -> int:\n\tvar flock_id: int = -1\n\tvar special_list: Array = WaveSpecialProperties.get_all_specials_list()\n\n\tfor special in special_list:\n\t\tvar special_name: String = WaveSpecialProperties.get_name_english(special)\n\n\t\tif special_name == \"Flock\":\n\t\t\tflock_id = special\n\n\t\t\tbreak\n\n\tif flock_id == -1:\n\t\tpush_error(\"Failed to find flock special and map it to id.\")\n\n\t\tflock_id = 0\n\n\treturn flock_id\n"
  },
  {
    "path": "src/singletons/properties/wisdom_upgrade_properties.gd",
    "content": "extends Node\n\n\nenum CsvProperty {\n\tID,\n\tNAME_ENGLISH,\n\tTOOLTIP,\n\tICON,\n}\n\nenum Id {\n\tADVANCED_FORTUNE,\n\tELEMENT_MASTERY,\n\tSWIFTNESS_MASTERY,\n\tCOMBAT_MASTERY,\n\tMASTERY_OF_PAIN,\n\tADVANCED_SORCERY,\n\tMASTERY_OF_MAGIC,\n\tMASTERY_OF_LOGISTICS,\n\tLOOT_MASTERY,\n\tADVANCED_WISDOM,\n\tPILLAGE_MASTERY,\n\tFORTIFIED_WILL,\n\tINNER_FOCUS,\n\tBOND_OF_UNITY,\n\tFOUNDATION_OF_KNOWLEDGE,\n\tDEADLY_STRIKES,\n\tFORTUNES_FAVOR,\n\tCHALLENGE_CONQUEROR,\n\tMASTER_OF_DESTRUCTION,\n\tADVANCED_OPTICS,\n\tELEMENTAL_OVERLOAD,\n\tPINNACLE_OF_POWER,\n\tADVANCED_SYNERGY,\n\tTHE_PATH_OF_ASCENSION,\n}\n\nconst _plus_mode_upgrade_list: Array[WisdomUpgradeProperties.Id] = [\n\tId.PILLAGE_MASTERY,\n\tId.FORTIFIED_WILL,\n\tId.INNER_FOCUS,\n\tId.BOND_OF_UNITY,\n\tId.FOUNDATION_OF_KNOWLEDGE,\n\tId.DEADLY_STRIKES,\n\tId.FORTUNES_FAVOR,\n\tId.CHALLENGE_CONQUEROR,\n\tId.MASTER_OF_DESTRUCTION,\n\tId.ADVANCED_OPTICS,\n\tId.ELEMENTAL_OVERLOAD,\n\tId.PINNACLE_OF_POWER,\n\tId.ADVANCED_SYNERGY,\n\tId.THE_PATH_OF_ASCENSION,\n]\n\n\nconst PROPERTIES_PATH = \"res://data/wisdom_upgrades.csv\"\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties(PROPERTIES_PATH, _properties, CsvProperty.ID)\n\n#\tCheck paths\n\tvar id_list: Array = WisdomUpgradeProperties.get_id_list()\n\tfor id in id_list:\n\t\tvar icon_path: String = WisdomUpgradeProperties.get_icon_path(id)\n\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\t\tif !icon_path_is_valid:\n\t\t\tpush_error(\"Invalid wisdom upgrade icon path: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id_list() -> Array:\n\treturn _properties.keys()\n\n\nfunc get_tooltip(tower_id: int) -> String:\n\tvar tooltip_text_id: String = _get_property(tower_id, CsvProperty.TOOLTIP)\n\tvar tooltip: String = tr(tooltip_text_id)\n\n\treturn tooltip\n\n\nfunc get_icon_path(tower_id: int) -> String:\n\tvar icon_path: String = _get_property(tower_id, CsvProperty.ICON)\n\n\treturn icon_path\n\n\nfunc get_plus_mode_upgrade_list() -> Array[WisdomUpgradeProperties.Id]:\n\treturn _plus_mode_upgrade_list.duplicate()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_property(tower_id: int, csv_property: CsvProperty) -> String:\n\tif !_properties.has(tower_id):\n\t\tpush_error(\"No properties for tower: \", tower_id)\n\n\t\treturn \"\"\n\t\n\tvar properties: Dictionary = _properties[tower_id]\n\tvar value: String = properties[csv_property]\n\n\treturn value\n"
  },
  {
    "path": "src/singletons/rich_texts.gd",
    "content": "extends Node\n\n\n# This class contains various functions which generate rich\n# texts for RichTextLabel's.\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_tower_specials_text(tower_id: int) -> String:\n\tvar text: String = \"\"\n\n\tvar attack_target_type: TargetType = TowerProperties.get_attack_target_type(tower_id)\n\tvar attacks_ground_only: bool = attack_target_type.equals_to(Tower.TARGET_TYPE_GROUND_ONLY)\n\tvar attacks_air_only: bool = attack_target_type.equals_to(Tower.TARGET_TYPE_AIR_ONLY)\n\tif attacks_ground_only:\n\t\ttext += \"[color=RED]%s[/color]\\n\" % tr(\"TOWER_SPECIAL_ATTACKS_GROUND_ONLY\")\n\telif attacks_air_only:\n\t\ttext += \"[color=RED]%s[/color]\\n\" % tr(\"TOWER_SPECIAL_ATTACKS_AIR_ONLY\")\n\n\tvar specials_modifier: Modifier = TowerProperties.get_specials_modifier(tower_id)\n\tvar modifier_text: String = specials_modifier.get_tooltip_text()\n\tmodifier_text = RichTexts.add_color_to_numbers(modifier_text)\n\n\tif !modifier_text.is_empty():\n\t\ttext += modifier_text \\\n\t\t+ \" \\n\"\n\n\ttext = text.trim_suffix(\" \\n\")\n\n\treturn text\n\n\nfunc get_tower_multishot_text(tower_id: int) -> String:\n\tvar multishot_count: int = TowerProperties.get_multishot(tower_id)\n\t\n\tif multishot_count <= 1:\n\t\treturn \"\"\n\n\tvar text: String = tr(\"TOWER_MULTISHOT_TEXT\").format({TARGET_COUNT = multishot_count})\n\ttext += \"\\n\"\n\n\treturn text\n\n\nfunc get_tower_splash_attack_text(tower_id: int) -> String:\n\tvar splash_attack_map: Dictionary = TowerProperties.get_splash_attack(tower_id)\n\n\tif splash_attack_map.is_empty():\n\t\treturn \"\"\n\n\tvar text: String = \"\"\n\n\tvar splash_range_list: Array = splash_attack_map.keys()\n\tsplash_range_list.sort()\n\n\tfor splash_range in splash_range_list:\n\t\tvar splash_ratio: float = splash_attack_map[splash_range]\n\t\tvar splash_percentage: String = Utils.format_percent(splash_ratio, 0)\n\t\ttext += tr(\"TOWER_SPLASH_ATTACK_LINE\").format({RANGE = splash_range, DAMAGE_RATIO = splash_percentage})\n\t\ttext += \"\\n\"\n\n\treturn text\n\n\nfunc get_tower_bounce_attack_text(tower_id: int) -> String:\n\tvar bounce_attack_values: Array = TowerProperties.get_bounce_attack(tower_id)\n\n\tif bounce_attack_values.is_empty():\n\t\treturn \"\"\n\n\tvar bounce_count: int = bounce_attack_values[0]\n\tvar bounce_multiplier: int = bounce_attack_values[1]\n\n\tvar text: String = \"\"\n\t\n\tif bounce_multiplier != 0:\n\t\tvar bounce_dmg_percent: String = Utils.format_percent(bounce_multiplier, 0)\n\t\ttext = tr(\"TOWER_BOUNCE_ATTACK_TEXT_NORMAL\").format({BOUNCE_COUNT = bounce_count, DAMAGE_RATIO = bounce_dmg_percent})\n\t\ttext += \"\\n\"\n\telse:\n\t\ttext = tr(\"TOWER_BOUNCE_ATTACK_TEXT_WITHOUT_DAMAGE_RATIO\").format({BOUNCE_COUNT = bounce_count})\n\t\ttext += \"\\n\"\n\n\treturn text\n\n\nfunc get_research_text(element: Element.enm, player: Player) -> String:\n\tvar text: String = \"\"\n\t\n\tvar current_element_level = player.get_element_level(element)\n\tvar reached_max_level: bool = current_element_level == player.get_max_element_level()\n\tif reached_max_level:\n\t\treturn tr(\"RESEARCH_ELEMENT_CANT_RESEARCH_FURTHER\") + \"\\n\"\n\n\tvar element_string: String = Element.convert_to_colored_string(element)\n\tvar flavor_text: String = Element.get_flavor_text(element)\n\tvar main_attack_types: String = Element.get_main_attack_types(element)\n\tvar research_level: String = get_research_level_label(element, player)\n\tvar cost: int = player.get_research_cost(element)\n\tvar can_afford: bool = player.can_afford_research(element)\n\tvar cost_string: String = get_colored_requirement_number(cost, can_afford)\n\n\tvar explanation_text: String = \"\"\n\tmatch Globals.get_game_mode():\n\t\tGameMode.enm.BUILD: explanation_text = tr(\"RESEARCH_ELEMENT_EXPLANATION_FOR_BUILD\")\n\t\tGameMode.enm.RANDOM_WITH_UPGRADES: explanation_text = tr(\"RESEARCH_ELEMENT_EXPLANATION_FOR_RANDOM_WITH_UPGRADES\")\n\t\tGameMode.enm.TOTALLY_RANDOM: explanation_text = tr(\"RESEARCH_ELEMENT_EXPLANATION_FOR_TOTALLY_RANDOM\")\n\n\ttext += tr(\"RESEARCH_ELEMENT_INFO\").format({ELEMENT = element_string, LEVEL = research_level}) + \"\\n\" \\\n\t+ \"[img=32x32]res://resources/icons/hud/knowledge_tome.tres[/img] %s\\n\" % cost_string \\\n\t+ \" \\n\" \\\n\t+ explanation_text + \"\\n\" \\\n\t+ \"[color=LIGHTBLUE]%s[/color]\\n\" % flavor_text \\\n\t+ \" \\n\" \\\n\t+ \"[color=GOLD]%s[/color] %s\\n\" % [tr(\"RESEARCH_ELEMENT_MAIN_ATTACK_TYPES\"), main_attack_types]\n\n\treturn text\n\n\nfunc get_research_level_label(element: Element.enm, player: Player) -> String:\n\tvar text: String = \"\"\n\t\n\tvar current_element_level = player.get_element_level(element)\n\tvar max_element_level = player.get_max_element_level()\n\tif current_element_level >= max_element_level:\n\t\ttext += \" [color=GOLD]%s[/color] \" % tr(\"RESEARCH_ELEMENT_LEVEL_MAX\")\n\telse:\n\t\ttext += \"[color=GOLD]%s[/color]\" % [current_element_level + 1]\n\t\n\treturn text\n\n\nfunc get_tower_text(tower_id: int, player: Player) -> String:\n\tvar description: String = TowerProperties.get_description(tower_id)\n\tvar author: String = TowerProperties.get_author(tower_id)\n\tvar element: Element.enm = TowerProperties.get_element(tower_id)\n\tvar element_string: String = Element.convert_to_colored_string(element)\n\tvar dps: int = floori(TowerProperties.get_dps(tower_id))\n\tvar attack_enabled: bool = TowerProperties.get_attack_enabled(tower_id)\n\tvar attack_type: AttackType.enm = TowerProperties.get_attack_type(tower_id)\n\tvar attack_type_string: String = AttackType.convert_to_colored_string(attack_type)\n\tvar attack_range: int = floor(TowerProperties.get_range(tower_id))\n\tvar mana: int = floor(TowerProperties.get_mana(tower_id))\n\tvar mana_regen: int = floor(TowerProperties.get_mana_regen(tower_id))\n\n\tvar ability_text = get_tower_ability_text_short(tower_id)\n\tvar requirements_text = get_tower_requirements_text(tower_id, player)\n\tvar display_name: String = TowerProperties.get_display_name(tower_id)\n\tvar gold_cost: int = TowerProperties.get_cost(tower_id)\n\tvar tome_cost: int = TowerProperties.get_tome_cost(tower_id)\n\tvar food_cost: int = TowerProperties.get_food_cost(tower_id)\n\tvar gold_cost_ok: bool = player.enough_gold_for_tower(tower_id)\n\tvar tome_cost_ok: bool = player.enough_tomes_for_tower(tower_id)\n\tvar food_cost_ok: bool = player.enough_food_for_tower(tower_id)\n\tvar gold_cost_string: String = get_colored_requirement_number(gold_cost, gold_cost_ok)\n\tvar tome_cost_string: String = get_colored_requirement_number(tome_cost, tome_cost_ok)\n\tvar food_cost_string: String = get_colored_requirement_number(food_cost, food_cost_ok)\n\t\n\tvar text = \"\"\n\t\n\tif !requirements_text.is_empty():\n\t\ttext += \"%s\\n\" % requirements_text\n\t\ttext += \" \\n\"\n\n\ttext += \"[b]%s[/b]\\n\" % display_name\n\n\tif tome_cost != 0:\n\t\ttext += \"[img=32x32]res://resources/icons/hud/gold.tres[/img] %s [img=32x32]res://resources/icons/hud/knowledge_tome.tres[/img] %s [img=32x32]res://resources/icons/hud/tower_food.tres[/img] %s\\n\" % [gold_cost_string, tome_cost_string, food_cost_string]\n\telse:\n\t\ttext += \"[img=32x32]res://resources/icons/hud/gold.tres[/img] %s [img=32x32]res://resources/icons/hud/tower_food.tres[/img] %s\\n\" % [gold_cost_string, food_cost_string]\n\t\n\ttext += \"[color=LIGHT_BLUE]%s[/color]\\n\" % description\n\ttext += \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"TOWER_TOOLTIP_AUTHOR\"), author]\n\ttext += \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"TOWER_TOOLTIP_ELEMENT\"), element_string]\n\tif attack_enabled:\n\t\ttext += tr(\"TOWER_TOOLTIP_ATTACK\").format({DPS = dps, ATTACK_TYPE = attack_type_string, RANGE = attack_range})\n\t\ttext += \"\\n\"\n\n\tif mana > 0:\n\t\ttext += tr(\"TOWER_TOOLTIP_MANA\").format({MANA_MAX = mana, MANA_REGEN = mana_regen})\n\t\ttext += \"\\n\"\n\t\n\ttext += \" \\n\"\n\n\tif !ability_text.is_empty():\n\t\ttext += ability_text \\\n\t\t+ \" \\n\"\n\t\n\ttext = text.trim_suffix(\" \\n\")\n\n\treturn text\n\n\nfunc get_tower_specials_and_extra_text(tower_id: int) -> String:\n\tvar text: String = \"\"\n\n\tvar specials_text: String = get_tower_specials_text(tower_id)\n\tif !specials_text.is_empty():\n\t\ttext += \"[color=GOLD]%s[/color]\\n\" % tr(\"TOWER_SPECIALS_TITLE\") \\\n\t\t+ specials_text \\\n\t\t+ \" \\n\"\n\n\tvar splash_text: String = get_tower_splash_attack_text(tower_id)\n\tif !splash_text.is_empty():\n\t\ttext += \"[color=GOLD]%s[/color]\\n\" % tr(\"TOWER_SPLASH_ATTACK_TITLE\") \\\n\t\t+ splash_text \\\n\t\t+ \" \\n\"\n\n\tvar bounce_text: String = get_tower_bounce_attack_text(tower_id)\n\tif !bounce_text.is_empty():\n\t\ttext += \"[color=GOLD]%s[/color]\\n\" % tr(\"TOWER_BOUNCE_ATTACK_TITLE\") \\\n\t\t+ bounce_text \\\n\t\t+ \" \\n\"\n\n\tvar multishot_text: String = get_tower_multishot_text(tower_id)\n\tif !multishot_text.is_empty():\n\t\ttext += \"[color=GOLD]%s[/color]\\n\" % tr(\"TOWER_MULTISHOT_TITLE\") \\\n\t\t+ multishot_text \\\n\t\t+ \" \\n\"\n\n\ttext = text.trim_suffix(\" \\n\")\n\n\treturn text\n\n\nfunc get_tower_ability_text_short(tower_id: int) -> String:\n\tvar text: String = \"\"\n\n\tvar specials_and_extra_text: String = get_tower_specials_and_extra_text(tower_id)\n\tif !specials_and_extra_text.is_empty():\n\t\ttext += specials_and_extra_text \\\n\t\t+ \" \\n\"\n\n\tvar ability_id_list: Array = TowerProperties.get_ability_id_list(tower_id)\n\tfor ability_id in ability_id_list:\n\t\tvar ability_text: String = get_ability_text_short(ability_id)\n\t\ttext += ability_text \\\n\t\t+ \" \\n\"\n\n\tvar aura_id_list: Array = TowerProperties.get_aura_id_list(tower_id)\n\tfor aura_id in aura_id_list:\n\t\tvar aura_is_hidden: bool = AuraProperties.get_is_hidden(aura_id)\n\t\tif aura_is_hidden:\n\t\t\tcontinue\n\n\t\tvar aura_text: String = get_aura_text_short(aura_id)\n\t\ttext += aura_text \\\n\t\t+ \" \\n\"\n\n\tvar autocast_id_list: Array = TowerProperties.get_autocast_id_list(tower_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast_text: String = get_autocast_text_short(autocast_id)\n\t\ttext += autocast_text \\\n\t\t+ \" \\n\"\n\n\ttext = text.trim_suffix(\" \\n\")\n\t\n\treturn text\n\n\nfunc get_tower_requirements_text(tower_id: int, player: Player) -> String:\n\tvar text: String = \"\"\n\n\tvar requirements_are_satisfied: bool = TowerProperties.requirements_are_satisfied(tower_id, player)\n\n\tif requirements_are_satisfied:\n\t\treturn \"\"\n\n\tvar required_wave_level: int = TowerProperties.get_required_wave_level(tower_id)\n\tvar wave_level_ok: bool = TowerProperties.wave_level_foo(tower_id, player)\n\tvar wave_level_string: String = get_colored_requirement_number(required_wave_level, wave_level_ok)\n\n\tvar required_element_level: int = TowerProperties.get_required_element_level(tower_id)\n\tvar element_level_ok: bool = TowerProperties.element_level_foo(tower_id, player)\n\tvar element_level_string: String = get_colored_requirement_number(required_element_level, element_level_ok)\n\n\tvar element: Element.enm = TowerProperties.get_element(tower_id)\n\tvar element_string: String = Element.get_display_string(element)\n\n\ttext += tr(\"TOWER_TOOLTIP_REQUIREMENTS\").format({WAVE_LEVEL = wave_level_string, ELEMENT = element_string, ELEMENT_LEVEL = element_level_string})\n\ttext += \"\\n\"\n\t\n\treturn text\n\n\nfunc get_item_text(item: Item) -> String:\n\tvar text: String = \"\"\n\n\tvar item_id: int = item.get_id()\n\tvar display_name: String = ItemProperties.get_display_name(item_id)\n\tvar rarity: Rarity.enm = ItemProperties.get_rarity(item_id)\n\tvar rarity_color: Color = Rarity.get_color(rarity)\n\tvar display_name_colored: String = Utils.get_colored_string(display_name, rarity_color)\n\tvar description: String = ItemProperties.get_description(item_id)\n\tvar level: int = ItemProperties.get_required_wave_level(item_id)\n\tvar author: String = ItemProperties.get_author(item_id)\n\tvar is_oil: bool = ItemProperties.get_is_oil(item_id)\n\tvar is_consumable: bool = ItemProperties.is_consumable(item_id)\n\n\tvar specials_text: String = item.get_specials_tooltip_text()\n\tspecials_text = add_color_to_numbers(specials_text)\n\n\ttext += \"[b]%s[/b]\\n\" % display_name_colored \\\n\t+ \"[color=LIGHT_BLUE]%s[/color]\\n\" % description \\\n\t+ \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"ITEM_TOOLTIP_LEVEL\"), level] \\\n\t+ \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"TOWER_TOOLTIP_AUTHOR\"), author] \\\n\t+ \" \\n\"\n\n\tif !specials_text.is_empty():\n\t\ttext += \"[color=YELLOW]%s[/color]\\n\" % tr(\"ITEM_TOOLTIP_EFFECTS\") \\\n\t\t+ specials_text \\\n\t\t+ \" \\n\"\n\n\tvar ability_id_list: Array = ItemProperties.get_ability_id_list(item_id)\n\tfor ability_id in ability_id_list:\n\t\tvar ability_text: String = get_ability_text_short(ability_id)\n\t\ttext += ability_text \\\n\t\t+ \" \\n\"\n\n\tvar aura_id_list: Array = ItemProperties.get_aura_id_list(item_id)\n\tfor aura_id in aura_id_list:\n\t\tvar aura_is_hidden: bool = AuraProperties.get_is_hidden(aura_id)\n\t\tif aura_is_hidden:\n\t\t\tcontinue\n\n\t\tvar aura_text: String = get_aura_text_short(aura_id)\n\t\ttext += aura_text \\\n\t\t+ \" \\n\"\n\n\tvar autocast_id_list: Array = ItemProperties.get_autocast_id_list(item_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast_text: String = get_autocast_text_short(autocast_id)\n\t\ttext += autocast_text \\\n\t\t+ \" \\n\"\n\n\tvar item_is_on_tower: bool = item.get_carrier() != null\n\n\tif !autocast_id_list.is_empty() && item_is_on_tower:\n\t\tvar autocast_id: int = autocast_id_list[0]\n\t\t\n\t\tvar can_use_auto_mode: bool = Autocast.can_use_auto_mode_for_id(autocast_id)\n\t\tif can_use_auto_mode:\n\t\t\ttext += \"[color=YELLOW]%s[/color]\\n\" % tr(\"ITEM_TOOLTIP_TOGGLE_CAST\")\n\t\t\n\t\ttext += \"[color=YELLOW]%s[/color]\\n\" % tr(\"ITEM_TOOLTIP_USE_ITEM\") \\\n\t\t+ \" \\n\"\n\n\tif is_consumable:\n\t\ttext += \"[color=ORANGE]%s[/color]\\n\" % tr(\"ITEM_TOOLTIP_USE_CONSUMABLE\") \\\n\t\t+ \" \\n\"\n\n\tif is_oil:\n\t\ttext += \"[color=ORANGE]%s[/color]\\n\" % tr(\"ITEM_TOOLTIP_USE_OIL\") \\\n\t\t+ \" \\n\"\n\n\ttext = text.trim_suffix(\" \\n\")\n\n\treturn text\n\n\n# Adds gold color to all ints and floats in the text.\n# NOTE: cases like these need to be colored:\n# \"15%\"\n# \"3s\"\n# \"x0.04\" (for crit damage)\n# \"+x0.04\"\nfunc add_color_to_numbers(text: String) -> String:\n\tvar colored_text: String = text\n\n\tvar index: int = 0\n\tvar tag_open: String = \"[color=GOLD]\"\n\tvar tag_close: String = \"[/color]\"\n\tvar tag_is_opened: bool = false\n\tvar inside_existing_tag: bool = false\n\n\twhile index < colored_text.length():\n\t\tvar c: String = colored_text[index]\n\t\tvar string_before_c: String = colored_text.substr(0, index)\n\n\t\tif !inside_existing_tag && string_before_c.ends_with(\"[color=\"):\n\t\t\tinside_existing_tag = true\n\n\t\tvar next: String\n\t\tif index + 1 < colored_text.length():\n\t\t\tnext = colored_text[index + 1]\n\t\telse:\n\t\t\tnext = \"\"\n\n\t\tif inside_existing_tag:\n#\t\t\tNOTE: color tags can contain numbers, for\n#\t\t\texample: [color=1e90ffff]foo[/color]. In such\n#\t\t\tcases, we do not color these numbers because\n#\t\t\tthat would break the existing color tag.\n\t\t\tif string_before_c.ends_with(\"[/color]\"):\n\t\t\t\tinside_existing_tag = false\n\t\telif tag_is_opened:\n\t\t\tvar c_is_valid_part_of_number: bool = c.is_valid_int() || c == \"%\" || c == \"s\" || c == \"x\"\n\n\t\t\tif c == \".\":\n\t\t\t\tvar dot_is_part_of_float: bool = next.is_valid_int()\n\t\t\t\tif !dot_is_part_of_float:\n\t\t\t\t\tcolored_text = colored_text.insert(index, tag_close)\n\t\t\t\t\tindex += tag_close.length()\n\t\t\t\t\ttag_is_opened = false\n\t\t\telif !c_is_valid_part_of_number:\n\t\t\t\tcolored_text = colored_text.insert(index, tag_close)\n\t\t\t\tindex += tag_close.length()\n\t\t\t\ttag_is_opened = false\n\t\telse:\n\t\t\tvar c_is_valid_start_of_number: bool = c.is_valid_int() || ((c == \"+\" || c == \"-\" || c == \"x\") && (next.is_valid_int() || next == \"x\"))\n\n\t\t\tif c_is_valid_start_of_number:\n\t\t\t\tcolored_text = colored_text.insert(index, tag_open)\n\t\t\t\tindex += tag_open.length()\n\t\t\t\ttag_is_opened = true\n\n\t\tindex += 1\n\n\tif tag_is_opened:\n\t\tcolored_text = colored_text.insert(index, tag_close)\n\n\treturn colored_text\n\n\nfunc get_colored_requirement_number(value: int, requirement_satisfied: bool) -> String:\n\tvar color: Color\n\tif requirement_satisfied:\n\t\tcolor = Color.GOLD\n\telse:\n\t\tcolor = Color.ORANGE_RED\n\n\tvar string: String = \"[color=%s]%d[/color]\" % [color.to_html(), value]\n\n\treturn string\n\n\nfunc get_ability_text_short(ability_id: int) -> String:\n\tvar ability_name: String = AbilityProperties.get_ability_name(ability_id)\n\tvar description: String = AbilityProperties.get_description_short(ability_id)\n\tdescription = add_color_to_numbers(description)\n\n\tvar text: String = \"\"\n\ttext += \"[color=GOLD]%s[/color]\\n\" % ability_name\n\ttext += \"%s\\n\" % description\n\n\treturn text\n\n\nfunc get_ability_text_long(ability_id: int) -> String:\n\tvar ability_name: String = AbilityProperties.get_ability_name(ability_id)\n\tvar description: String = AbilityProperties.get_description_long(ability_id)\n\tdescription = add_color_to_numbers(description)\n\n\tvar text: String = \"\"\n\ttext += \"[color=GOLD]%s[/color]\\n\" % ability_name\n\ttext += \"%s\\n\" % description\n\n\treturn text\n\n\nfunc get_aura_text_short(aura_id: int) -> String:\n\tvar aura_name: String = AuraProperties.get_aura_name(aura_id)\n\tvar description: String = AuraProperties.get_description_short(aura_id)\n\tdescription = add_color_to_numbers(description)\n\n\tvar text: String = \"\"\n\ttext += \"[color=GOLD]%s - %s[/color]\\n\" % [aura_name, tr(\"AURA_WORD_IN_TITLE\")]\n\ttext += \"%s\\n\" % description\n\n\treturn text\n\n\nfunc get_aura_text_long(aura_id: int) -> String:\n\tvar aura_name: String = AuraProperties.get_aura_name(aura_id)\n\tvar description: String = AuraProperties.get_description_long(aura_id)\n\tdescription = add_color_to_numbers(description)\n\n\tvar text: String = \"\"\n\ttext += \"[color=GOLD]%s - %s[/color]\\n\" % [aura_name, tr(\"AURA_WORD_IN_TITLE\")]\n\ttext += \"%s\\n\" % description\n\n\treturn text\n\n\nfunc get_autocast_text_long(autocast_id: int) -> String:\n\tvar autocast_name: String = AutocastProperties.get_autocast_name(autocast_id)\n\tvar autocast_description_long: String = AutocastProperties.get_description_long(autocast_id)\n\tautocast_description_long = add_color_to_numbers(autocast_description_long)\n\tvar stats_text: String = get_autocast_stats_text(autocast_id)\n\n\tvar text: String = \"\"\n\ttext += \"[color=GOLD]%s[/color]\\n\" % autocast_name\n\ttext += \"%s\\n\" % autocast_description_long\n\ttext += \" \\n\"\n\ttext += \"%s\\n\" % stats_text\n\n\treturn text\n\n\nfunc get_autocast_text_short(autocast_id: int) -> String:\n\tvar autocast_name: String = AutocastProperties.get_autocast_name(autocast_id)\n\tvar autocast_description_short: String = AutocastProperties.get_description_short(autocast_id)\n\tautocast_description_short = add_color_to_numbers(autocast_description_short)\n\tvar stats_text: String = get_autocast_stats_text(autocast_id)\n\n\tvar text: String = \"[color=GOLD]%s[/color]\\n\" % autocast_name \\\n\t+ \"%s\\n\" % autocast_description_short \\\n\t+ \" \\n\" \\\n\t+ \"%s\" % stats_text\n\n\treturn text\n\n\nfunc get_autocast_tooltip(autocast: Autocast) -> String:\n\tvar text: String = \"\"\n\n\ttext += RichTexts.get_autocast_text_long(autocast.get_id())\n\ttext += \" \\n\"\n\n\tif autocast.can_use_auto_mode():\n\t\ttext += \"[color=YELLOW]%s[/color]\\n\" % tr(\"AUTOCAST_TOOLTIP_TOGGLE_CAST\")\n\t\ttext += \" \\n\"\n\n\ttext += \"[color=YELLOW]%s[/color]\\n\" % tr(\"AUTOCAST_TOOLTIP_CAST\")\n\n\treturn text\n\n\nfunc get_autocast_stats_text(autocast_id: int) -> String:\n\tvar mana_cost: int = AutocastProperties.get_mana_cost(autocast_id)\n\tvar cast_range: float = AutocastProperties.get_cast_range(autocast_id)\n\tvar cooldown: float = AutocastProperties.get_cooldown(autocast_id)\n\tvar mana_cost_string: String = tr(\"AUTOCAST_TOOLTIP_MANA_COST\").format({MANA_COST = str(mana_cost)})\n\tvar cast_range_string: String = tr(\"AUTOCAST_TOOLTIP_RANGE\").format({RANGE = str(cast_range)})\n\tvar cooldown_string: String = tr(\"AUTOCAST_TOOLTIP_COOLDOWN\").format({COOLDOWN = str(cooldown)})\n\n\tvar text: String = \"\"\n\n\tvar stats_list: Array[String] = []\n\tif mana_cost > 0:\n\t\tstats_list.append(mana_cost_string)\n\tif cast_range > 0:\n\t\tstats_list.append(cast_range_string)\n\tif cooldown > 0:\n\t\tstats_list.append(cooldown_string)\n\n\tif !stats_list.is_empty():\n\t\tvar stats_line: String = \", \".join(stats_list)\n\t\tstats_line = add_color_to_numbers(stats_line)\n\t\ttext += \"%s\\n\" % stats_line\n\n\treturn text\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_creep_health_string(creep: Creep) -> String:\n\tvar health_color: Color\n\tvar health_ratio: float = creep.get_health_ratio()\n\tif health_ratio > 0.3:\n\t\thealth_color = Color.GREEN\n\telse:\n\t\thealth_color = Color.RED\n\n\tvar health: int = floor(creep.get_health())\n\tvar overall_health: int = floor(creep.get_overall_health())\n\tvar health_string: String = \"%d/%d\" % [health, overall_health]\n\tvar health_string_colored: String = Utils.get_colored_string(health_string, health_color)\n\n\treturn health_string_colored\n"
  },
  {
    "path": "src/singletons/sanitize_text.gd",
    "content": "extends Node\n\n\nconst BADWORDS_CSV_PATH: String = \"res://assets/secrets/badwords.csv\"\n\n\nvar _bad_words_pattern: String\nvar _regex_allowed_chars: RegEx\nvar _regex_replace: RegEx\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_regex_allowed_chars = RegEx.new()\n\t_regex_allowed_chars.compile(Constants.PLAYER_NAME_ALLOWED_CHARS)\n\n\t_bad_words_pattern = _create_bad_words_pattern()\n\t_regex_replace = RegEx.new()\n\t_regex_replace.compile(_bad_words_pattern)\n\t\n\n#########################\n###       Public      ###\n#########################\n\n# Removes invalid chars, removes bad words and applies\n# length limits.\nfunc sanitize_player_name(text: String) -> String:\n\ttext = text.substr(0, Constants.PLAYER_NAME_LENGTH_MAX)\n\n#\tRemove invalid chars\n#\tNOTE: invalid chars are not allowed in player name\n#\teditor, but it's still possible for bad actors to put\n#\tthem here\n\tvar regexed_text: String = \"\"\n\tfor valid_character in _regex_allowed_chars.search_all(text):\n\t\tregexed_text += valid_character.get_string()\n\n\ttext = regexed_text\n\n#\tRemove out bad words\n\tvar replace_all: bool = true\n\ttext = _regex_replace.sub(text, \"o\", replace_all)\n\n\twhile text.length() < Constants.PLAYER_NAME_LENGTH_MIN:\n\t\ttext += \"o\"\n\n\treturn text\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _create_bad_words_pattern() -> String:\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(BADWORDS_CSV_PATH)\n\t\n\tif csv.is_empty():\n\t\tpush_error(\"Failed to load badwords csv from: %s\" % BADWORDS_CSV_PATH)\n\t\t\n\t\treturn \"()\"\n\n\tvar word_list: Array[String] = []\n\n\tfor csv_line in csv:\n\t\tif csv_line.size() != 1:\n\t\t\tpush_error(\"Badwords csv is malformed. Size = %s\" % csv_line.size())\n\n\t\t\tcontinue\n\n\t\tvar word: String = csv_line[0]\n\t\tword_list.append(word)\n\n\tvar pattern: String = \"(\"\n\n\tfor i in range(0, word_list.size()):\n\t\tif i > 0:\n\t\t\tpattern += \"|\"\n\t\t\t\n\t\tvar word: String = word_list[i]\n\t\tpattern += word\n\n\tpattern += \")\"\n\n\treturn pattern\n"
  },
  {
    "path": "src/singletons/secrets.gd",
    "content": "extends Node\n\n\n# This class manages \"secrets\", which are loaded from csv\n# file. Each secret is mapped to a key.\n\n\nconst SECRETS_CSV_PATH: String = \"res://assets/secrets/secrets.csv\"\n\n\nclass Key:\n\tconst SERVER_KEY: String = \"socket.server_key\"\n\tconst ICE_USERNAME: String = \"ice.username\"\n\tconst ICE_CREDENTIAL: String = \"ice.credential\"\n\n\nvar KEY_LIST: Array[String] = [\n\tSecrets.Key.SERVER_KEY,\n\tSecrets.Key.ICE_USERNAME,\n\tSecrets.Key.ICE_CREDENTIAL,\n]\n\nvar _csv_dict: Dictionary = {}\n\n\nfunc _ready():\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(SECRETS_CSV_PATH)\n\t\n\tif csv.is_empty():\n\t\tpush_error(\"Failed to load secrets csv from: %s\" % SECRETS_CSV_PATH)\n\t\t\n\t\treturn\n\n\tfor csv_line in csv:\n\t\tif csv_line.size() != 2:\n\t\t\tpush_error(\"Secrets csv is malformed\")\n\n\t\t\tcontinue\n\n\t\tvar key: String = csv_line[0]\n\t\tvar value: String = csv_line[1]\n\t\t_csv_dict[key] = value\n\n\tfor key in KEY_LIST:\n\t\tif !_csv_dict.has(key):\n\t\t\tpush_error(\"Failed to load secret: %s\" % key)\n\n\nfunc get_secret(key: String):\n\tvar value: String = _csv_dict.get(key, \"\")\n\n\treturn value\n"
  },
  {
    "path": "src/singletons/settings.gd",
    "content": "extends Node\n\n\n# Allows getting and setting persistent settings. Intended\n# to be used by settings which are editable by the player\n# ingame. Settings are saved to a file on hard drive. For\n# example, on Windows the path would be:\n# %appdata%/Roaming/Godot/...\n\nsignal changed()\n\nconst SETTINGS_PATH: String = \"user://settings.save\"\n\nenum InterfaceSize {\n\tSMALL,\n\tMEDIUM,\n\tLARGE\n}\n\n# List of setting names\nconst ENABLE_PLUS_MODE: String = \"enable_plus_mode\"\nconst SHOW_ALL_DAMAGE_NUMBERS: String = \"show_all_damage_numbers\"\nconst ENABLE_FLOATING_TEXT: String = \"enable_floating_text\"\nconst ENABLE_VFX: String = \"enable_vfx\"\nconst ENABLE_SFX: String = \"enable_sfx\"\nconst PROJECTILE_DENSITY: String = \"projectile_density\"\nconst MOUSE_SCROLL: String = \"mouse_scroll\"\nconst KEYBOARD_SCROLL: String = \"keyboard_scroll\"\nconst ENABLE_MOUSE_SCROLL: String = \"enable_mouse_scroll\"\nconst SHOW_COMBAT_LOG: String = \"show_combat_log\"\n# NOTE: storing x and y separately instead of Vector2\n# because Vector2 can't be deserialized from JSON\nconst COMBAT_LOG_X: String = \"combat_log_x\"\nconst COMBAT_LOG_Y: String = \"combat_log_y\"\nconst INTERFACE_SIZE: String = \"interface_size\"\nconst INTERFACE_SIZE_DICT: Dictionary = {\n\tInterfaceSize.SMALL: 0.75,\n\tInterfaceSize.MEDIUM: 1.0,\n\tInterfaceSize.LARGE: 1.25\n}\nconst SHOW_TUTORIAL_ON_START: String = \"show_tutorial_on_start\"\nconst CACHED_GAME_DIFFICULTY: String = \"CACHED_GAME_DIFFICULTY\"\nconst CACHED_GAME_MODE: String = \"CACHED_GAME_MODE\"\nconst CACHED_GAME_LENGTH: String = \"CACHED_GAME_LENGTH\"\nconst PLAYER_NAME: String = \"PLAYER_NAME\"\nconst EXP_PASSWORD: String = \"EXP_PASSWORD\"\nconst WISDOM_UPGRADES_CACHED: String = \"WISDOM_UPGRADES_CACHED\"\nconst DISPLAY_MODE: String = \"DISPLAY_MODE\"\nconst MISSION_STATUS: String = \"MISSION_STATUS\"\nconst SHOWED_ONE_TIME_HELP_POPUP: String = \"SHOWED_ONE_TIME_HELP_POPUP\"\nconst LANGUAGE: String = \"LANGUAGE\"\n\n\nvar _cache: Dictionary = {}\n\n\n# NOTE: need to convert enum values to floats because JSON\n# only supports floats. If we don't do this, then the type\n# checking of cache will fail.\nvar _default_value_map: Dictionary = {\n\tENABLE_PLUS_MODE: false,\n\tSHOW_ALL_DAMAGE_NUMBERS: false,\n\tENABLE_FLOATING_TEXT: true,\n\tENABLE_VFX: true,\n\tENABLE_SFX: true,\n\tPROJECTILE_DENSITY: 1.0,\n\tMOUSE_SCROLL: 0.5,\n\tKEYBOARD_SCROLL: 0.5,\n\tENABLE_MOUSE_SCROLL: false,\n\tSHOW_COMBAT_LOG: false,\n\tCOMBAT_LOG_X: 20.0,\n\tCOMBAT_LOG_Y: 600.0,\n\tINTERFACE_SIZE: InterfaceSize.MEDIUM as float,\n\tSHOW_TUTORIAL_ON_START: true,\n\tCACHED_GAME_DIFFICULTY: \"beginner\",\n\tCACHED_GAME_MODE: \"random_with_upgrades\",\n\tCACHED_GAME_LENGTH: Constants.WAVE_COUNT_TRIAL as float,\n\tPLAYER_NAME: \"Player\",\n\tEXP_PASSWORD: \"\",\n\tWISDOM_UPGRADES_CACHED: {},\n\tDISPLAY_MODE: DisplayMode.enm.FULLSCREEN as float,\n\tMISSION_STATUS: {},\n\tSHOWED_ONE_TIME_HELP_POPUP: false,\n\tLANGUAGE: OS.get_locale_language(),\n}\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# NOTE: it is intentional that changed() signal is not\n# emitted at the end of _ready(). This is because\n# Settings._ready() is called before the majority of the\n# game nodes are created (Settings is a singleton). Nodes\n# must load initial values manually instead of relying on\n# Settings.changed() signal.\nfunc _ready():\n\tvar settings_file: FileAccess = FileAccess.open(SETTINGS_PATH, FileAccess.READ)\n\n\tif settings_file != null and settings_file.get_length() > 0:\n\t\tvar cache_string: String = settings_file.get_as_text()\n\t\t_cache = JSON.parse_string(cache_string) as Dictionary\n\t\t_validate_cache()\n\t\t\n\t\tprint_verbose(\"Opened settings file at path:\", settings_file.get_path_absolute())\n\telse:\n\t\tvar open_error: Error = FileAccess.get_open_error()\n\t\tif open_error == Error.ERR_FILE_NOT_FOUND:\n\t\t\tprint_verbose(\"No settings file found. Will create new one from scratch.\")\n\t\telse:\n\t\t\tpush_error(\"Failed to open settings file. Error:\", error_string(open_error))\n\n\t\t_cache = _default_value_map\n\n#\t\tNOTE: call flush() to save default settings to file.\n#\t\tThis will create settings file for the first time.\n\t\tflush()\n\n\t_load_window_settings()\n\t\n\tload_language_setting()\n\n\n# NOTE: need to switch fonts when switching languages\n# because the English \"Friz\" font doesn't support Chinese\n# characters. If we don't switch, then on desktop the game\n# will fallback to system font and Chinese will render ok.\n# On html5, system fonts are not available and Chinese\n# characters won't draw at all - that's why this step is\n# necessary.\nfunc load_language_setting():\n\tvar selected_language: String = get_setting(Settings.LANGUAGE)\n\tTranslationServer.set_locale(selected_language)\n\t\n\tvar chinese_locale: String = Language.get_locale_from_enum(Language.enm.CHINESE)\n\tvar font_for_selected_language: Font\n\tif selected_language == chinese_locale:\n\t\tfont_for_selected_language = Preloads.noto_sans_chinese_font\n\telse:\n\t\tfont_for_selected_language = Preloads.friz_font\n\t\n\tvar theme: Theme = preload(\"res://resources/theme/wc3_theme.tres\")\n\ttheme.default_font = font_for_selected_language\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_setting(setting: String) -> Variant:\n\tif !_default_value_map.has(setting):\n\t\tpush_error(\"No such setting exists:\" % setting)\n\n\t\treturn null\n\n\tvar default_value: Variant = _default_value_map[setting]\n\tvar value: Variant = _cache.get(setting, default_value)\n\n\treturn value\n\n\nfunc get_bool_setting(setting: String) -> bool:\n\tvar value: bool = get_setting(setting) as bool\n\n\treturn value\n\n\nfunc set_setting(setting: String, value: Variant):\n\t_cache[setting] = value\n\t\n\tif setting == Settings.LANGUAGE:\n\t\tload_language_setting()\n\n\n# Save all changes to file\nfunc flush():\n\tvar settings_file: FileAccess = FileAccess.open(SETTINGS_PATH, FileAccess.WRITE)\n\tvar cache_string: String = JSON.stringify(_cache, \"    \")\n\tsettings_file.store_line(cache_string)\n\n\t_load_window_settings()\n\t\n\tchanged.emit()\n\n\nfunc get_interface_size_enum() -> Settings.InterfaceSize:\n\tvar interface_size_int: int = Settings.get_setting(Settings.INTERFACE_SIZE) as int\n\tvar interface_size_enum: Settings.InterfaceSize = interface_size_int as Settings.InterfaceSize\n\t\n\treturn interface_size_enum\n\n\nfunc get_interface_size() -> float:\n\tvar interface_size_enum: Settings.InterfaceSize = get_interface_size_enum()\n\tvar interface_size: float = INTERFACE_SIZE_DICT[interface_size_enum]\n\n\treturn interface_size\n\n\n# NOTE: need to convert keys to ints because JSON dicts\n# forces keys to be strings.\nfunc get_wisdom_upgrades() -> Dictionary:\n\tvar upgrades_from_file: Dictionary = Settings.get_setting(Settings.WISDOM_UPGRADES_CACHED) as Dictionary\n\t\n\tvar result: Dictionary = {}\n\n\tvar upgrade_id_list: Array = WisdomUpgradeProperties.get_id_list()\n\tfor upgrade_id in upgrade_id_list:\n\t\tif upgrades_from_file.has(upgrade_id):\n\t\t\tresult[upgrade_id] = upgrades_from_file[upgrade_id]\n\t\telif upgrades_from_file.has(str(upgrade_id)):\n\t\t\tresult[upgrade_id] = upgrades_from_file[str(upgrade_id)]\n\t\telse:\n\t\t\tresult[upgrade_id] = false\n\n\treturn result\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _validate_cache():\n\tvar cache_was_fixed: bool = false\n\n\tfor _cache_key in _default_value_map.keys():\n\t\tif !_cache.has(_cache_key):\n\t\t\tpush_error(\"Settings file doesn't have value for [%s]. Loading default value instead.\" % _cache_key)\n\t\t\t_cache[_cache_key] = _default_value_map[_cache_key]\n\t\t\tcache_was_fixed = true\n\n#\t\tCache should have comparable types with the default map\n\t\tif typeof(_default_value_map[_cache_key]) != typeof(_cache[_cache_key]):\n\t\t\tpush_error(\"Saved setting [%s] has incorrect type. Loading default value instead.\" % _cache_key)\n\t\t\t_cache[_cache_key] = _default_value_map[_cache_key]\n\t\t\tcache_was_fixed = true\n\n#\tNOTE: need to flush settings if cache was fixed to save\n#\tfixed settings to file\n\tif cache_was_fixed:\n\t\tflush()\n\n\nfunc _load_window_settings():\n\tvar window: Window = get_window()\n\n\tvar interface_size: float = Settings.get_interface_size()\n\twindow.content_scale_factor = interface_size\n\n\tvar display_mode_int: int = Settings.get_setting(Settings.DISPLAY_MODE) as int\n\tvar display_mode: DisplayMode.enm = display_mode_int as DisplayMode.enm\n\tvar window_mode: Window.Mode = DisplayMode.convert_to_window_mode(display_mode)\n\twindow.set_mode(window_mode)\n"
  },
  {
    "path": "src/singletons/sfx.gd",
    "content": "extends Node\n\n\n# Functions for playing sound effects.\n\n\nvar _loaded_sfx_map: Dictionary = {}\nvar _2d_sfx_player_list: Array = []\nvar _sfx_player_list: Array = []\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc play_sfx_for_team(team: Team, sfx_path: String, volume_db: float = 0.0, pitch_scale: float = 1.0):\n\tvar player_list: Array[Player] = team.get_players()\n\n\tfor player in player_list:\n\t\tSFX.play_sfx_for_player(player, sfx_path, volume_db, pitch_scale)\n\n\nfunc play_sfx_for_player(player: Player, sfx_path: String, volume_db: float = 0.0, pitch_scale: float = 1.0):\n\tvar player_is_local_player: bool = player == PlayerManager.get_local_player()\n\n\tif player_is_local_player:\n\t\tSFX.play_sfx(sfx_path, volume_db, pitch_scale)\n\n\nfunc play_sfx_random_pitch(sfx_path: String, volume_db: float = 0.0, pitch_scale_min: float = 0.95, pitch_scale_max: float = 1.05):\n\tvar random_pitch: float = Globals.local_rng.randf_range(pitch_scale_min, pitch_scale_max)\n\t\n\tSFX.play_sfx(sfx_path, volume_db, random_pitch)\n\n\n# NOTE: this f-n is non-positional. Current viewport\n# position doesn't affect the sfx.\nfunc play_sfx(sfx_path: String, volume_db: float = 0.0, pitch_scale: float = 1.0):\n\tif !Settings.get_bool_setting(Settings.ENABLE_SFX):\n\t\treturn\n\n\tvar sfx_player: AudioStreamPlayer = _get_sfx_player()\n\tsfx_player.pitch_scale = pitch_scale\n\tsfx_player.volume_db = volume_db\n\tvar sfx_stream: AudioStream = _get_sfx(sfx_path)\n\n\tvar invalid_sfx: bool = sfx_stream == null || sfx_stream.get_length() == 0\n\n\tif invalid_sfx:\n\t\tpush_error(\"SFX [%s] doesn't exist.\" % sfx_path)\n\t\t\n\t\treturn\n\n\tsfx_player.set_stream(sfx_stream)\n\tsfx_player.play()\n\n\nfunc sfx_at_pos(sfx_path: String, sfx_position: Vector2, volume_db: float = 0.0, pitch_scale: float = 1.0):\n\tif !Settings.get_bool_setting(Settings.ENABLE_SFX):\n\t\treturn\n\n\tvar sfx_player: AudioStreamPlayer2D = _get_2d_sfx_player()\n\tsfx_player.pitch_scale = pitch_scale\n\tsfx_player.volume_db = volume_db\n\tvar sfx_stream: AudioStream = _get_sfx(sfx_path)\n\n\tvar invalid_sfx: bool = sfx_stream.get_length() == 0\n\n\tif invalid_sfx:\n\t\treturn\n\n\tsfx_player.set_stream(sfx_stream)\n\tsfx_player.global_position = sfx_position\n\tsfx_player.play()\n\n\n# NOTE: this f-n is *not* the same thing as SFXAtUnit() in\n# JASS.\n# This function plays a sound effect.\n# SFXAtUnit() from JASS creates a \"simple effect\" (SFX),\n# where \"effect\" is visual, not sound.\nfunc sfx_at_unit(sfx_path: String, unit: Unit, volume_db: float = 0.0, pitch_scale: float = 1.0):\n\tif unit == null:\n\t\tpush_error(\"null unit passed to SFX.sfx_at_unit()\")\n\t\t\n\t\treturn\n\n\tvar sfx_position: Vector2 = unit.get_visual_position()\n\tsfx_at_pos(sfx_path, sfx_position, volume_db, pitch_scale)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_sfx(sfx_path: String) -> AudioStream:\n\tif _loaded_sfx_map.has(sfx_path):\n\t\treturn _loaded_sfx_map[sfx_path]\n\n\tif !sfx_path.ends_with(\".mp3\") && !sfx_path.ends_with(\".wav\") && !sfx_path.ends_with(\".ogg\"):\n\t\tpush_error(\"Sfx must be mp3, wav or ogg:\", sfx_path)\n\n\t\treturn AudioStreamMP3.new()\n\n\tvar file_exists: bool = ResourceLoader.exists(sfx_path)\n\n\tif !file_exists:\n\t\tpush_error(\"Failed to find sfx at:\", sfx_path)\n\n\t\treturn AudioStreamMP3.new()\n\n\tvar stream: AudioStream = load(sfx_path)\n\n#\tNOTE: turn off looping in case it was turned on in sfx's\n#\t.import file.\n\tif stream is AudioStreamMP3:\n\t\tvar stream_mp3: AudioStreamMP3 = stream as AudioStreamMP3\n\t\tstream_mp3.loop = false\n\telif stream is AudioStreamOggVorbis:\n\t\tvar stream_ogg: AudioStreamOggVorbis = stream as AudioStreamOggVorbis\n\t\tstream_ogg.loop = false\n\n\t_loaded_sfx_map[sfx_path] = stream\n\n\treturn stream\n\n\n# This function either returns a newly created\n# AudioStreamPlayer or reuses a previously created one.\nfunc _get_sfx_player() -> AudioStreamPlayer:\n\tvar idle_player: AudioStreamPlayer = null\n\n\tfor sfx_player in _sfx_player_list:\n\t\tif !sfx_player.playing:\n\t\t\tidle_player = sfx_player\n\n\t\t\tbreak\n\n\tif idle_player != null:\n\t\treturn idle_player\n\n\tvar new_player: AudioStreamPlayer = AudioStreamPlayer.new()\n\t_sfx_player_list.append(new_player)\n\tadd_child(new_player)\n\n\treturn new_player\n\n\n# Same as _get_sfx_player() but for AudioStreamPlayer2D\nfunc _get_2d_sfx_player() -> AudioStreamPlayer2D:\n\tvar idle_player: AudioStreamPlayer2D = null\n\n\tfor sfx_player in _2d_sfx_player_list:\n\t\tif !sfx_player.playing:\n\t\t\tidle_player = sfx_player\n\n\t\t\tbreak\n\n\tif idle_player != null:\n\t\treturn idle_player\n\n\tvar new_player: AudioStreamPlayer2D = AudioStreamPlayer2D.new()\n\t_2d_sfx_player_list.append(new_player)\n\tadd_child(new_player)\n\n\treturn new_player\n"
  },
  {
    "path": "src/singletons/sfx_paths.gd",
    "content": "extends Node\n\n\nconst BUILD_TOWER: String = \"res://assets/sfx/683044__brettrader__stomp-soft.ogg\"\nconst PICKUP_ITEM: String = \"res://assets/sfx/411177__silverillusionist__pick-up-item-1-short.ogg\"\nconst DROP_ITEM: String = \"res://assets/sfx/michel_baradari_jump.ogg\"\nconst PICKUP_GOLD: String = \"res://assets/sfx/734247__noisyredfox__coins3.ogg\"\nconst HUMAN_DEATH_EXPLODE: String = \"res://assets/sfx/442903__qubodup__slash-remix.ogg\"\nconst START_WAVE: String = \"res://assets/sfx/161654__qubodup__war-game-battle-level-up-remix.ogg\"\nconst LEVEL_UP: String = \"res://assets/sfx/kevl_level_up.ogg\"\n\nconst TOWER_ATTACK_MAP: Dictionary = {\n\tElement.enm.NATURE: \"res://assets/sfx/unknown_swosh-08.ogg\",\n\tElement.enm.STORM: \"res://assets/sfx/bart_foom_0.ogg\",\n\tElement.enm.FIRE: \"res://assets/sfx/unknown_fire_attack1.ogg\",\n\tElement.enm.ICE: \"res://assets/sfx/unknown_iceball.ogg\",\n\tElement.enm.ASTRAL: \"res://assets/sfx/unknown_attack_sound1.ogg\",\n\tElement.enm.DARKNESS: \"res://assets/sfx/unknown_swosh-11.ogg\",\n\tElement.enm.IRON: \"res://assets/sfx/unknown_iron_attack1.ogg\",\n}\n\nconst UI_ERROR: String = \"res://assets/sfx/665082__sunflora__thud.ogg\"\nconst ORC_GRUNT: String = \"res://assets/sfx/738438__qubodup__orc-grunt-2.ogg\"\nconst ARCHERS_SHOOTING: String = \"res://assets/sfx/copyc4t_Archers-shooting.ogg\"\nconst FLIES_BUZZING: String = \"res://assets/sfx/p0ss_pestilence.ogg\"\nconst SAND_RUB: String = \"res://assets/sfx/p0ss_sand.ogg\"\nconst CURSE_NOISE: String = \"res://assets/sfx/p0ss_curse5.ogg\"\nconst GHOST_EXHALE: String = \"res://assets/sfx/p0ss_spell.ogg\"\nconst BAM_ECHO: String = \"res://assets/sfx/p0ss_explode4.ogg\"\nconst POW: String = \"res://assets/sfx/p0ss_shot.ogg\"\nconst CLOUD_POOF: String = \"res://assets/sfx/714258__qubodup__cloud-poof.ogg\"\nconst SPIT: String = \"res://assets/sfx/spit_01.ogg\"\n\nconst EXPLOSION: String = \"res://assets/sfx/745156__tigreplayz__blast-explosion.ogg\"\nconst EXPLOSION_MUFFLED_BOUNCING: String = \"res://assets/sfx/p0ss_explode2.ogg\"\n\nconst ENCHANT_LONG: String = \"res://assets/sfx/202147__qubodup__enchant.ogg\"\nconst ENCHANT_SHORT: String = \"res://assets/sfx/p0ss_enchant.ogg\"\nconst ENCHANT_DRONE: String = \"res://assets/sfx/p0ss_enchant2.ogg\"\n\nconst MAGIC_STROBE: String = \"res://assets/sfx/682635__bastianhallo__magic-spell.ogg\"\nconst MAGIC_HIGH_TONE: String = \"res://assets/sfx/420676__sypherzent__spell-cast-buff-high-tone.ogg\"\nconst MAGIC_CHANNEL: String = \"res://assets/sfx/little_robot_Spell_00.ogg\"\nconst MAGIC_FIZZLE: String = \"res://assets/sfx/little_robot_Spell_01.ogg\"\nconst MAGIC_CONFUSE: String = \"res://assets/sfx/p0ss_confusion.ogg\"\n\nconst TELEPORT: String = \"res://assets/sfx/p0ss_teleport.ogg\"\nconst TELEPORT_BASS: String = \"res://assets/sfx/michel_baradari_teleport.ogg\"\n\nconst WARP: String = \"res://assets/sfx/p0ss_warp.ogg\"\nconst WARP_LONG: String = \"res://assets/sfx/p0ss_warp2.ogg\"\n\nconst ELECTRIC_BUZZ: String = \"res://assets/sfx/little_robot_UI_Electric_00.ogg\"\nconst ELECTRIC_BUMP: String = \"res://assets/sfx/little_robot_Whoosh_Electric_01.ogg\"\nconst ELECTRIC_WHOOSH: String = \"res://assets/sfx/little_robot_Whoosh_Electric_00.ogg\"\nconst ELECTRIC_WHOOSH_UP: String = \"res://assets/sfx/little_robot_Whoosh_Electric_02.ogg\"\nconst ELECTRIC_WHOOSH_DOWN: String = \"res://assets/sfx/little_robot_Whoosh_Electric_03.ogg\"\n\nconst ZAP_HIGH_PITCH: String = \"res://assets/sfx/p0ss_zap.ogg\"\nconst ZAP_LOW: String = \"res://assets/sfx/p0ss_zap5a.ogg\"\nconst ZAP_LONG: String = \"res://assets/sfx/p0ss_zap10.ogg\"\n\nconst WATER_SLASH: String = \"res://assets/sfx/649359__sonofxaudio__sword_water01.ogg\"\nconst WATER_STEAM: String = \"res://assets/sfx/p0ss_steam.ogg\"\nconst WATER_HISS: String = \"res://assets/sfx/p0ss_water.ogg\"\n\nconst ICE_CRACKLE: String = \"res://assets/sfx/artisticdude_freeze.ogg\"\nconst ICE_HISS: String = \"res://assets/sfx/p0ss_freeze2.ogg\"\n\nconst HEAL: String = \"res://assets/sfx/DoKashiteru_healspell1.ogg\"\nconst HEAL_DEEP: String = \"res://assets/sfx/DoKashiteru_healspell2.ogg\"\nconst HEAL_REVERB: String = \"res://assets/sfx/DoKashiteru_healspell3.ogg\"\n\nconst SPARKLE_SHORT: String = \"res://assets/sfx/562292__colorscrimsontears__heal-rpg.ogg\"\nconst SPARKLE_LONG: String = \"res://assets/sfx/p0ss_heal.ogg\"\n\nconst FIRE_BALL: String = \"res://assets/sfx/442827__qubodup__fireball.ogg\"\nconst FIRE_PUNCH: String = \"res://assets/sfx/541478__eminyildirim__magic-fire-spell-impact-punch.ogg\"\nconst FIRE_SPLASH: String = \"res://assets/sfx/michel_baradari_lava.ogg\"\n"
  },
  {
    "path": "src/singletons/tower_distribution.gd",
    "content": "extends Node\n\n\n# Generates random towers, based on current element levels.\n# This happens after every wave and also at the start of the\n# game when player rolls the first towers.\n\n# NOTE: this code is convoluted because it attempts to\n# accurately reproduce the algorithm from the original game.\n# There are some differences in the implementation but final\n# behavior is the same. Make sure that any changes you make\n# to this code do not cause unintentional changes to\n# behavior.\n\n\n# Tower groups are lists of towers mapped by element and\n# rarity:\n# Element -> Rarity -> Array of tower id's\nvar _tower_groups_all_tiers: Dictionary\nvar _tower_groups_first_tier_only: Dictionary\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_tower_groups_all_tiers = _generate_tower_groups(false)\n\t_tower_groups_first_tier_only = _generate_tower_groups(true)\n\n\n#########################\n###       Public      ###\n#########################\n\n# Called after each wave.\nfunc roll_towers(player: Player) -> Array[int]:\n\tvar tower_list: Array[int] = _generate_random_towers(player)\n\n\treturn tower_list\n\n\n#########################\n###      Private      ###\n#########################\n\n# Adds random towers. The amount will be at least one and\n# more towers will be added for higher wave levels.\nfunc _generate_random_towers(player: Player) -> Array[int]:\n\tvar tower_list: Array[int] = []\n\n\tvar element_list: Array[Element.enm] = _get_possible_element_list(player)\n\tUtils.shuffle(Globals.synced_rng, element_list)\n\n\tif element_list.is_empty():\n\t\treturn []\n\n\tvar plus_mode_is_enabled: bool = Settings.get_bool_setting(Settings.ENABLE_PLUS_MODE)\n\n#\tOn first pass, try to roll each element once. This is\n#\tlikely to not result in any towers at low element\n#\tlevels.\n\tfor element in element_list:\n\t\tvar chance_for_element: float = _get_chance_for_element(player, element)\n\n\t\t# NOTE: plus mode introduces a concept of \"benefit\n\t\t# from >100%\" chance. In original game >100% chance\n\t\t# did not give benefits, so disable it if plus mode\n\t\t# is disabled.\n\t\tif !plus_mode_is_enabled:\n\t\t\tchance_for_element = clampf(chance_for_element, 0.0, 1.0)\n\n\t\twhile chance_for_element > 0:\n\t\t\tvar tower: int = _generate_random_tower_for_element(player, element, chance_for_element)\n\n\t\t\tif tower != 0:\n\t\t\t\ttower_list.append(tower)\n\t\t\t\n\t\t\tchance_for_element -= 1.0\n\n#\tIf first pass rolled 0 towers, we do a second pass where\n#\twe roll 1 tower by brute force. This pass will happen\n#\tfor majority of early waves.\n\tif tower_list.size() == 0:\n\t\ttower_list = generate_random_towers_with_count(player, 1)\n\n\treturn tower_list\n\n\n# Adds the given amount of towers.\nfunc generate_random_towers_with_count(player: Player, count: int) -> Array[int]:\n\tvar tower_list: Array[int] = []\n\n\tvar element_list: Array[Element.enm] = _get_possible_element_list(player)\n\n\tif element_list.is_empty():\n\t\treturn []\n\n#\tNOTE: original algorithm doesn't do this and iterates\n#\tover elements in same order every time. I'm pretty sure\n#\tthat causes some elements to incorrectly have higher\n#\tprobability. Therefore, we shuffle the elements before\n#\titerating over them.\n\tUtils.shuffle(Globals.synced_rng, element_list)\n\n\tvar brute_force_count: int = 0\n\n#\tIterate over all elements in a loop until the required\n#\tamount of towers has been rolled. This is a \"brute\n#\tforce\" approach.\n\twhile true:\n\t\tvar element: Element.enm = element_list.pop_front()\n\t\telement_list.push_back(element)\n\n\t\tvar chance_for_element: float = _get_chance_for_element(player, element)\n\t\tvar tower: int = _generate_random_tower_for_element(player, element, chance_for_element)\n\n\t\tif tower != 0:\n\t\t\ttower_list.append(tower)\n\n\t\tvar rolled_enough_towers: bool = tower_list.size() == count\n\n\t\tif rolled_enough_towers:\n\t\t\tbreak\n\n\t\tbrute_force_count += 1\n\n\t\tif brute_force_count == 1000:\n\t\t\tpush_error(\"Tried to roll tower 1000 times. Giving up - something might be wrong with tower groups.\")\n\n\t\t\tbreak\n\n\treturn tower_list\n\n\n# Returns list of elements with non-zero chances. Useful to\n# reduce the amount of brute forcing.\nfunc _get_possible_element_list(player: Player) -> Array[Element.enm]:\n\tvar element_list: Array[Element.enm] = []\n\n\tfor element in Element.get_list():\n\t\tvar chance_for_element: float = _get_chance_for_element(player, element)\n\n\t\tif chance_for_element > 0:\n\t\t\telement_list.append(element)\n\n\treturn element_list\n\n\n# Returns chance for rolling a tower of a given element.\n# Increasing element level increases this chance.\nfunc _get_chance_for_element(player: Player, element: Element.enm) -> float:\n\tvar base: float = 0.0\n\n\tvar add: float\n\tmatch Globals.get_game_mode():\n\t\tGameMode.enm.RANDOM_WITH_UPGRADES: add = 0.075\n\t\tGameMode.enm.TOTALLY_RANDOM: add = 0.1\n\t\t_: add = 0.0\n\n\tvar level: int = player.get_element_level(element)\n\tvar chance: float = base + add * level\n\n\treturn chance\n\n\n# Returns chance for rolling a tower in a given \"group\" of\n# element and rarity. Is affected by current element level.\n# Increasing element level increases chances for all\n# rarities, except for common, which gets decreased.\nfunc _get_chance_for_group(player: Player, element: Element.enm, rarity: Rarity.enm) -> float:\n\tvar base_map: Dictionary = {\n\t\tRarity.enm.COMMON: 0.76,\n\t\tRarity.enm.UNCOMMON: 0.18,\n\t\tRarity.enm.RARE: 0.06,\n\t\tRarity.enm.UNIQUE: 0.0,\n\t}\n#\tNOTE: chance for common rarity decreases\n\tvar add_map: Dictionary = {\n\t\tRarity.enm.COMMON: -0.018,\n\t\tRarity.enm.UNCOMMON: 0.008,\n\t\tRarity.enm.RARE: 0.006,\n\t\tRarity.enm.UNIQUE: 0.004,\n\t}\n\n\tvar level: int = player.get_element_level(element)\n\tvar base: float = base_map[rarity]\n\tvar add: float = add_map[rarity]\n\tvar chance: float = base + add * level\n\tchance = clampf(chance, 0.0, 1.0)\n\n\treturn chance\n\n\nfunc _generate_tower_groups(first_tier_only: bool) -> Dictionary:\n\tvar result: Dictionary = {}\n\n\tfor element in Element.get_list():\n\t\tresult[element] = Dictionary()\n\n\t\tfor rarity in Rarity.get_list():\n\t\t\tresult[element][rarity] = Array()\n\n\tvar all_towers: Array = TowerProperties.get_tower_id_list()\n\n#\tSort tower list by cost so that all resulting tower\n#\tgroups are also sorted by cost\n\tall_towers.sort_custom(func(a, b): \n\t\tvar cost_a: int = TowerProperties.get_cost(a)\n\t\tvar cost_b: int = TowerProperties.get_cost(b)\n\t\treturn cost_a < cost_b)\n\n\tfor tower in all_towers:\n\t\tvar element: Element.enm = TowerProperties.get_element(tower)\n\t\tvar rarity: Rarity.enm = TowerProperties.get_rarity(tower)\n\t\tvar tier: int = TowerProperties.get_tier(tower)\n\n\t\tif first_tier_only && tier > 1:\n\t\t\tcontinue\n\n\t\tresult[element][rarity].append(tower)\n\n\treturn result\n\n\n# Returns 0 if failed to generate\nfunc _generate_random_tower_for_element(player: Player, element: Element.enm, chance_for_element: float) -> int:\n\tvar roll_success: bool = Utils.rand_chance(Globals.synced_rng, chance_for_element)\n\tif !roll_success:\n\t\treturn 0\n\n\tvar max_cost: float = _get_max_cost(player, element)\n\n\tvar rarity: Rarity.enm = _roll_rarity_for_element(player, element, max_cost)\n\n\tvar cost_multiplier_for_rarity: float = _get_cost_multiplier_for_rarity(rarity)\n\tmax_cost *= cost_multiplier_for_rarity\n\n\tvar group_map: Dictionary\n\tvar weight_cost_power: float\n\tmatch Globals.get_game_mode():\n\t\tGameMode.enm.RANDOM_WITH_UPGRADES: \n\t\t\tgroup_map = _tower_groups_first_tier_only\n\t\t\tweight_cost_power = 0.25\n\t\tGameMode.enm.TOTALLY_RANDOM: \n\t\t\tgroup_map = _tower_groups_all_tiers\n\t\t\tweight_cost_power = 0.8\n\t\t_: \n\t\t\tgroup_map = {}\n\t\t\tweight_cost_power = 0.0\n\n#\tRemove all towers which are above max cost. If group\n#\tends up being empty, reduce rarity.\n\tvar group: Array\n\twhile true:\n\t\tgroup = group_map[element][rarity]\n\t\tgroup = group.filter(func(tower) -> bool:\n\t\t\tvar cost: int = TowerProperties.get_cost(tower)\n\t\t\tvar below_max_cost: bool = cost < max_cost\n\n\t\t\treturn below_max_cost)\n\n\t\tif !group.is_empty() || rarity == 0:\n\t\t\tbreak\n\t\telse:\n\t\t\trarity = (rarity - 1) as Rarity.enm\n\t\n\tif group.is_empty():\n\t\tpush_error(\"Tower group is empty for:\", player.get_team().get_level(), element, rarity)\n\n\t\treturn 0\n\n#\tNOTE: adjust chance of picking a tower based on it's\n#\tcost\n#\tfor total random:\n#\t- if cost is 50, then weight is ~22.87\n#\t- if cost is 100, then weight is ~39.81\n#\t- that means for if tower is 2x more expensive it is x1.741 likelier to appear\n#\tfor random with upgrade:\n#\t- if cost is 50, then weight is ~2.659\n#\t- if cost is 100, then weight is ~3.162\n#\t- that means for if tower is 2x more expensive it is x1.189 likelier to appear\n#\tThis means that we will pick towers with higher costs\n#\tmore often. This way, the player will get the most\n#\tpowerful towers available at the moment.\n\tvar group_weights: Dictionary = {}\n\tfor tower in group:\n\t\tvar cost: int = TowerProperties.get_cost(tower)\n\t\tvar weight: float = pow(cost, weight_cost_power)\n\t\tgroup_weights[tower] = weight\n\n\tvar random_tower: int = Utils.random_weighted_pick(Globals.synced_rng, group_weights)\n\n\treturn random_tower\n\n\n# Returns max cost for rolling towers. All rolled towers\n# will be below this cost. Researching elements unlocks more\n# expensive towers.\nfunc _get_max_cost(player: Player, element: Element.enm) -> float:\n\tvar wave_level: int = player.get_team().get_level()\n\tvar max_cost: float = floorf(70 + wave_level * (5 + wave_level * 0.6))\n\n\tvar cost_multiplier: float = _get_cost_multiplier_for_element(player, element)\n\tmax_cost = max_cost * cost_multiplier\n\t\n\tmax_cost = floori(max_cost * Globals.synced_rng.randf_range(1.0, 1.1))\n\n\treturn max_cost\n\n\nfunc _get_cost_multiplier_for_element(player: Player, element: Element.enm) -> float:\n\tvar base: float = 0.75\n\tvar add: float = 0.03\n\tvar level: int = player.get_element_level(element)\n\tvar multiplier: float = base + add * level\n\n\treturn multiplier\n\n\n# Rolls random rarity for element. Depends on current\n# element level and max cost. Rarity will be picked so that\n# towers of rarity are below max cost. Researching elements\n# unlocks towers with higher rarity.\nfunc _roll_rarity_for_element(player: Player, element: Element.enm, max_cost: float) -> Rarity.enm:\n\tvar cost_threshold_map: Dictionary = {\n\t\tRarity.enm.COMMON: 0,\n\t\tRarity.enm.UNCOMMON: 0,\n\t\tRarity.enm.RARE: 500,\n\t\tRarity.enm.UNIQUE: 1500,\n\t}\n\n\tvar rarity_list: Array = Rarity.get_list()\n\n#\tNOTE: have to generate chance map here because it\n#\tchanges based on current element level\n\tvar rarity_chance_map: Dictionary = {}\n\n\tfor rarity in rarity_list:\n\t\tvar chance: float = _get_chance_for_group(player, element, rarity)\n\t\trarity_chance_map[rarity] = chance\n\n#\tRemove rarities whose cost thresholds are above max cost\n\tfor rarity in rarity_list:\n\t\tvar cost_threshold: int = cost_threshold_map[rarity]\n\n\t\tif cost_threshold > max_cost:\n\t\t\trarity_chance_map.erase(rarity)\n\n\tvar random_rarity: Rarity.enm = Utils.random_weighted_pick(Globals.synced_rng, rarity_chance_map)\n\n\treturn random_rarity\n\n\nfunc _get_cost_multiplier_for_rarity(rarity: Rarity.enm) -> float:\n\tvar rarity_multiplier_map: Dictionary = {\n\t\tRarity.enm.COMMON: 1.0,\n\t\tRarity.enm.UNCOMMON: 1.05,\n\t\tRarity.enm.RARE: 1.12,\n\t\tRarity.enm.UNIQUE: 1.2,\n\t}\n\tvar multiplier: float = rarity_multiplier_map[rarity]\n\n\treturn multiplier\n"
  },
  {
    "path": "src/singletons/tower_sprites.gd",
    "content": "extends Node\n\n\n# Stores loaded tower sprites. Can either load all sprites\n# on game startup or load sprites dynamically when they\n# become needed. Behavior depends on game config.\n\n\nvar _sprite_scene_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar preload_towers: bool = Config.preload_all_towers_on_startup()\n\n\tif !preload_towers:\n\t\treturn\n\n\tprint_verbose(\"Start loading tower sprites.\")\n\n\tvar tower_id_list: Array = TowerProperties.get_tower_id_list()\n\n\tfor tower_id in tower_id_list:\n\t\t_load_tower_sprite_scene(tower_id)\n\n\tprint_verbose(\"Finished loading tower sprites.\")\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_sprite(tower_id: int) -> Sprite2D:\n\tif !_sprite_scene_map.has(tower_id):\n\t\t_load_tower_sprite_scene(tower_id)\n\n\tvar sprite_scene: PackedScene = _sprite_scene_map[tower_id]\n\tvar sprite: Sprite2D = sprite_scene.instantiate()\n\n\treturn sprite\n\n\n#########################\n###      Private      ###\n#########################\n\n# Scene filename = [name of first tier tower in family] +\n# tier.\n# Examples:\n# \"Tiny Shrub\" -> \"TinyShrub1.tscn\"\n# \"Greater Shrub\" -> \"TinyShrub3.tscn\"\nfunc _load_tower_sprite_scene(tower_id: int):\n\tvar sprite_path: String = TowerProperties.get_sprite_path(tower_id)\n\tvar sprite_scene: PackedScene = load(sprite_path)\n\t_sprite_scene_map[tower_id] = sprite_scene\n\n\tvar tower_name: String = TowerProperties.get_display_name(tower_id)\n\tprint_verbose(\"Loaded tower [%s] with ID [%s]\" % [tower_name, tower_id])\n"
  },
  {
    "path": "src/singletons/unit_icons.gd",
    "content": "extends Node\n\n\n# Creates icons for towers and creeps.\n\n\nconst ICON_SIZE = 128\nconst TIER_ICON_SIZE = 64\n\nconst _placeholder_tower_icon: Texture2D = preload(\"res://resources/icons/tower_icons/obelisk_of_fortuity.tres\")\nconst CREEP_ICON_DIR: String = \"res://resources/icons/creep_icons\"\nconst TIER_ICON_DIR: String = \"res://resources/icons/tier_icons\"\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n#\tCheck icon paths\n\tvar creep_category_list: Array[CreepCategory.enm] = CreepCategory.get_list()\n\tvar creep_size_list: Array[CreepSize.enm] = CreepSize.get_list()\n\n\tfor creep_category in creep_category_list:\n\t\tfor creep_size in creep_size_list:\n\t\t\tvar size_is_challenge: bool = CreepSize.is_challenge(creep_size)\n\t\t\tvar category_is_challenge: bool = creep_category == CreepCategory.enm.CHALLENGE\n\t\t\tvar invalid_challenge_combo: bool = (size_is_challenge && !category_is_challenge) || (!size_is_challenge && category_is_challenge) \n\t\n\t\t\tif invalid_challenge_combo:\n\t\t\t\tcontinue\n\n\t\t\tvar icon_path: String = UnitIcons._get_creep_icon_path(creep_category, creep_size)\n\t\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\t\t\tif !icon_path_is_valid:\n\t\t\t\tpush_error(\"Invalid creep icon path: %s\" % icon_path)\n\n\tvar rarity_list: Array[Rarity.enm] = Rarity.get_list()\n\tvar tier_list: Array[int] = [1, 2, 3, 4, 5, 6, 7]\n\n\tfor rarity in rarity_list:\n\t\tfor tier in tier_list:\n\t\t\tvar icon_path: String = _get_tier_icon_path(rarity, tier)\n\t\t\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\t\t\tif !icon_path_is_valid:\n\t\t\t\tpush_error(\"Invalid tier icon path: %s\" % icon_path)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_tower_tier_icon(tower_id: int) -> Texture2D:\n\tvar tower_rarity: Rarity.enm = TowerProperties.get_rarity(tower_id)\n\tvar tower_tier: int = TowerProperties.get_tier(tower_id)\n\tvar icon_path: String = _get_tier_icon_path(tower_rarity, tower_tier)\n\tvar icon_path_exists: bool = ResourceLoader.exists(icon_path)\n\n\tif !icon_path_exists:\n\t\tpush_error(\"Tier icon path doesn't exist\")\n\n\t\treturn Texture2D.new()\n\n\tvar icon: Texture2D = load(icon_path)\n\n\treturn icon\n\n\nfunc get_creep_icon(creep: Creep) -> Texture2D:\n\tvar creep_size: CreepSize.enm = creep.get_size_including_challenge_sizes()\n\tvar creep_category: CreepCategory.enm = creep.get_category()\n\tvar icon_path: String = _get_creep_icon_path(creep_category, creep_size)\n\tvar icon_path_exists: bool = ResourceLoader.exists(icon_path)\n\n\tif !icon_path_exists:\n\t\tpush_error(\"Icon path doesn't exist: %s\", icon_path)\n\n\t\treturn Texture2D.new()\n\n\tvar icon: Texture2D = load(icon_path)\n\n\treturn icon\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_tier_icon_path(rarity: Rarity.enm, tier: int) -> String:\n\tvar rarity_string: String = Rarity.convert_to_string(rarity)\n\tvar tier_string: String = str(tier)\n\tvar icon_path: String = \"%s/%s_%s.tres\" % [TIER_ICON_DIR, rarity_string, tier_string]\n\n\treturn icon_path\n\n\n# NOTE: must use convert_to_string() which is non-display\n# string here because this is for filename, so no\n# translation needed!\nfunc _get_creep_icon_path(creep_category: CreepCategory.enm, creep_size: CreepSize.enm) -> String:\n\tvar creep_category_string: String = CreepCategory.convert_to_string(creep_category)\n\tvar creep_size_string: String = CreepSize.convert_to_string(creep_size)\n\tvar icon_path: String = \"%s/%s_%s.tres\" % [CREEP_ICON_DIR, creep_category_string, creep_size_string]\n\ticon_path = icon_path.replace(\" \", \"_\")\n\n\treturn icon_path\n"
  },
  {
    "path": "src/singletons/utils.gd",
    "content": "class_name UtilsStatic extends Node\n\n\n# NOTE: about Utils.tr() calls in other scripts. tr() is a\n# f-n from Object base class. These calls are necessary in\n# cases where a translation is needed from inside a static\n# f-n where no Object is available. Using Utils as that\n# Object solves the problem.\n\n\nstatic func convert_string_to_id_list(string: String) -> Array[int]:\n\tvar id_list: Array[int] = []\n\n\tif string.is_empty():\n\t\treturn id_list\n\n\tvar id_string_list: Array = string.split(\",\")\n\tid_string_list.erase(\"\")\n\tfor id_string in id_string_list:\n\t\tvar id: int = id_string.to_int()\n\t\tid_list.append(id)\n\n\treturn id_list\n\n\n# Takes in a \"x_properties\" csv and outputs modified version\n# of columns + translation map of id->text. \nfunc setup_translation_map_from_csv(csv_path: String, column_list: Array):\n\tvar csv_contents: Array[PackedStringArray] = UtilsStatic.load_csv(csv_path)\n\t\n\tvar modified_csv_contents: String = \"\"\n\tvar translation_map_contents: String = \"\"\n\n\tvar column_count: int = column_list.size()\n\tvar row_count: int = csv_contents.size()\n\tvar translation_id_count: int = column_count * row_count\n\tvar new_translation_ids: Array = Utils.generate_new_translation_ids(translation_id_count)\n\n\tfor line in csv_contents:\n\t\tvar source_text_list: Array[String] = []\n\n\t\tfor column in column_list:\n\t\t\tvar source_text: String = line[column]\n\t\t\tsource_text_list.append(source_text)\n\n\t\tvar text_id_list: Array = []\n\t\tfor i in range(column_list.size()):\n\t\t\tvar text_id: String = new_translation_ids.pop_front()\n\t\t\ttext_id_list.append(text_id)\n\n#\t\tAdd new lines to texts csv\n\t\tfor i in range(column_list.size()):\n\t\t\tvar text_id: String = text_id_list[i]\n\t\t\tvar source_text: String = source_text_list[i]\n\t\t\ttranslation_map_contents += \"\\\"%s\\\",\\\"%s\\\"\\n\" % [text_id, source_text]\n\n#\t\tAdd new line to props csv\n\t\tfor text_id in text_id_list:\n\t\t\tmodified_csv_contents += \"\\\"%s\\\",\" % text_id\n\t\tmodified_csv_contents.trim_suffix(\",\")\n\t\tmodified_csv_contents += \"\\n\"\n\n\tvar modified_csv: FileAccess = FileAccess.open(\"user://modified_csv.csv\", FileAccess.WRITE)\n\tmodified_csv.store_string(modified_csv_contents)\n\n\tvar translation_map_csv: FileAccess = FileAccess.open(\"user://translation_map_csv.csv\", FileAccess.WRITE)\n\ttranslation_map_csv.store_string(translation_map_contents)\n\n\nfunc bool_to_string(value: bool) -> String:\n\tvar result: String\n\tif value == true:\n\t\tresult = \"TRUE\"\n\telse:\n\t\tresult = \"FALSE\"\n\t\n\treturn result\n\n\nfunc string_to_bool(bool_string: String) -> bool:\n\tvar result: bool\n\tif bool_string == \"TRUE\":\n\t\tresult = true\n\telse:\n\t\tresult = false\n\t\n\treturn result\n\n\nfunc print_new_translation_ids(amount: int):\n\tvar id_list = Utils.generate_new_translation_ids(amount)\n\n\tfor id in id_list:\n\t\tprint(id)\n\n\nfunc generate_new_translation_ids(amount: int):\n\tvar chars_for_id: Array = []\n\tvar chars_for_id_only_letters: Array = []\n\t\n#\tDigits\n\tfor char_int in range(48, 57 + 1):\n\t\tvar char_str: String = String.chr(char_int)\n\t\tchars_for_id.append(char_str)\n\n#\tUpper-case letters\n\tfor char_int in range(65, 90 + 1):\n\t\tvar char_str: String = String.chr(char_int)\n\t\tchars_for_id.append(char_str)\n\t\tchars_for_id_only_letters.append(char_str)\n\n\tvar existing_key_list: Array[String] = []\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(\"res://assets/texts/texts.csv\")\n\tfor csv_line in csv:\n\t\tvar key: String = csv_line[0]\n\t\texisting_key_list.append(key)\n\t\n\tvar generated_key_list: Array[String] = []\n\n#\tNOTE: repeat multiple times in case there are too many collisions with existing keys\n\tfor i in range(0, 10):\n\t\tfor j in range(0, amount):\n\t\t\tvar generated_key: String = \"\"\n\t\t\tfor k in range(0, 4):\n\t\t\t\tvar random_char: String\n\n#\t\t\t\tNOTE: need to force first char to be letter\n#\t\t\t\tand not digit to avoid issues caused by\n#\t\t\t\tExcel recognizing the id as a number.\n\t\t\t\tif k == 0:\n\t\t\t\t\trandom_char = chars_for_id_only_letters.pick_random()\n\t\t\t\telse:\n\t\t\t\t\trandom_char = chars_for_id.pick_random()\n\n\t\t\t\tgenerated_key += random_char\n\t\t\t\n\t\t\tgenerated_key_list.append(generated_key)\n\t\n\t\tfor existing_key in existing_key_list:\n\t\t\tgenerated_key_list.erase(existing_key)\n\t\t\t\n\t\tif generated_key_list.size() >= amount:\n\t\t\tbreak\n\t\n\treturn generated_key_list\n\n\n# NOTE: in original youtd, range checks for abilities are\n# extended slightly so that range check is done from the\n# edge of a small circle around the unit instead of the\n# center. For abilities casted on towers, the edge is\n# roughly at the \"edge\" of the average sprite. For creeps,\n# the extension is much smaller but it's still there in\n# original, so it's replicated here as well.\nfunc apply_unit_range_extension(range_original: float, target_type: TargetType) -> float:\n\tif target_type == null:\n\t\tpush_error(\"apply_unit_range_extension() received null target_type\")\n\n\t\treturn range_original\n\n\tvar unit_type: TargetType.UnitType = target_type.get_unit_type()\n\tvar target_is_tower: bool = unit_type == TargetType.UnitType.TOWERS\n\t\n\tvar range_bonus: float\n\tif target_is_tower:\n\t\trange_bonus = Constants.RANGE_CHECK_BONUS_FOR_TOWERS\n\telse:\n\t\trange_bonus = Constants.RANGE_CHECK_BONUS_FOR_OTHER_UNITS\n\n\tvar range_extended: float = range_original + range_bonus\n\n\treturn range_extended\n\n\n# This function is needed to prevent user inputted strings\n# from being parsed. Should be applied to all strings coming\n# from players: user names, chat messages, etc.\n# \n# If this is not done, then players can do stuff like send\n# giant full screen chat messages.\nfunc escape_bbcode(string: String) -> String:\n\treturn string.replace(\"[\", \"[lb]\")\n\n\nfunc get_turn_length() -> int:\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\t\n\tif player_mode == PlayerMode.enm.SINGLEPLAYER:\n\t\treturn GameHost.SINGLEPLAYER_TURN_LENGTH\n\telse:\n\t\treturn GameHost.MULTIPLAYER_TURN_LENGTH\n\n\n# Adds a red color error text in the middle of the screen\n# and plays an error sound.\nfunc add_ui_error(player: Player, text: String):\n\tMessages.add_error(player, text)\n\tSFX.play_sfx_for_player(player, SfxPaths.UI_ERROR)\n\n\nfunc get_polygon_bounding_box(poly: Polygon2D) -> Rect2:\n\tvar float_max: float = pow(2, 31) - 1\n\tvar float_min: float = -float_max\n\tvar vec_min: Vector2 = Vector2(float_max, float_max)\n\tvar vec_max: Vector2 = Vector2(float_min, float_min)\n\tvar vertice_list: Array = poly.polygon\n\t\n\tfor vertice in vertice_list:\n\t\tvec_min.x = min(vec_min.x, vertice.x)\n\t\tvec_min.y = min(vec_min.y, vertice.y)\n\t\t\n\t\tvec_max.x = max(vec_max.x, vertice.x)\n\t\tvec_max.y = max(vec_max.y, vertice.y)\n\t\n\tvar bbox_pos: Vector2 = vec_min\n\tvar bbox_size: Vector2 = (vec_max - vec_min).abs()\n\tvar bounding_box: Rect2 = Rect2(bbox_pos, bbox_size)\n\t\n\treturn bounding_box\n\n\nfunc show_popup_message(node: Node, title: String, message: String):\n\tif !node.is_inside_tree():\n\t\tpush_error(\"Node must inside scene tree\")\n\n\t\treturn\n\t\n\tvar popup_text: String = \"\"\n\tif !title.is_empty():\n\t\tpopup_text += \"[center]%s[/center]\\n \\n\" % title\n\tpopup_text += message\n\n#\tNOTE: the top node is last in order, after autoload nodes\n\tvar root = node.get_tree().root\n\tvar top_node: Node = root.get_child(root.get_child_count() - 1)\n\tvar popup: MessagePopup = MessagePopup.make(popup_text)\n\ttop_node.add_child(popup)\n\n\n# Converts unix time UTC (seconds) into local time string\nfunc convert_unix_time_to_string(time_utc: float) -> String:\n\tvar time_zone: Dictionary = Time.get_time_zone_from_system()\n\tvar bias_minutes: float = time_zone.get(\"bias\", 0)\n\tvar bias_seconds: float = bias_minutes * 60\n\tvar time_local: float = time_utc + bias_seconds\n\tvar time_string: String = Time.get_time_string_from_unix_time(int(time_local))\n\t\n\treturn time_string\n\n\nfunc check_dict_has_fields(dict: Dictionary, field_count: int) -> bool:\n\tvar dict_has_keys: bool = true\n\t\n\tfor key in range(0, field_count):\n\t\tif !dict.has(key):\n\t\t\tdict_has_keys = false\n\t\t\t\n\t\t\tbreak\n\t\n\treturn dict_has_keys\n\n\nfunc convert_bytes_to_dict(bytes: PackedByteArray) -> Dictionary:\n\tvar variant: Variant = bytes_to_var(bytes)\n\n\tif variant is Dictionary:\n\t\tvar dict: Dictionary = variant as Dictionary\n\n\t\treturn dict\n\telse:\n\t\treturn {}\n\n\nfunc get_path_point_wc3(path: Path2D, index: int) -> Vector2:\n\tvar curve: Curve2D = path.get_curve()\n\tvar point_canvas: Vector2 = curve.get_point_position(index)\n\tvar point_wc3: Vector2 = VectorUtils.canvas_to_wc3_2d(point_canvas)\n\n\treturn point_wc3\n\n\nfunc wave_is_bonus(level: int) -> bool:\n\treturn level > Constants.WAVE_COUNT_NEVERENDING\t\n\n\nfunc create_message_label(text: String) -> RichTextLabel:\n\tvar label: RichTextLabel = RichTextLabel.new()\n\tlabel.append_text(text)\n\tlabel.fit_content = true\n\tlabel.mouse_filter = Control.MOUSE_FILTER_IGNORE\n\tlabel.set_theme_type_variation(\"MessageLabel\")\n\n\treturn label\n\n\nfunc get_wisdom_upgrade_count_for_player_level(player_level: int) -> int:\n\tvar upgrade_id_list: Array = WisdomUpgradeProperties.get_id_list()\n\tvar upgrade_count_max: int = upgrade_id_list.size()\n\tvar upgrade_count: int = min(upgrade_count_max, floori(player_level * Constants.PLAYER_LEVEL_TO_WISDOM_UPGRADE_COUNT))\n\n\treturn upgrade_count\n\n\n# returns an additive bonus to wisdom multiplier\nfunc get_wisdom_multiplier_bonus_from_upgrades(wisdom_upgrades: Dictionary) -> float:\n\tvar player_level: int = Utils.get_local_player_level()\n\tvar wisdom_multiplier_bonus: float = 0.0\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.ADVANCED_SYNERGY]:\n\t\twisdom_multiplier_bonus += 0.06\n\t\n\tif wisdom_upgrades[WisdomUpgradeProperties.Id.THE_PATH_OF_ASCENSION]:\n\t\tvar levels_spent = wisdom_upgrades.values().count(true) / Constants.PLAYER_LEVEL_TO_WISDOM_UPGRADE_COUNT\n\t\tvar levels_left: int = int(player_level - levels_spent)\n\t\twisdom_multiplier_bonus += 0.001 * levels_left\n\treturn wisdom_multiplier_bonus\n\n\nfunc get_local_player_level() -> int:\n\tvar exp_password: String = Settings.get_setting(Settings.EXP_PASSWORD)\n\tvar player_exp: int = ExperiencePassword.decode(exp_password)\n\tvar player_exp_is_valid: bool = player_exp != -1\n\t\n\tif !player_exp_is_valid:\n\t\tpush_warning(\"Experience password is invalid, resetting level to 0.\")\n\t\t\n\t\treturn 0\n\t\n\tvar player_lvl: int = PlayerExperience.get_level_at_exp(player_exp)\n\t\n\treturn player_lvl\n\n\n# Example: 93 -> \"01:33\"\nfunc convert_time_to_string(time_total_seconds: float):\n\tvar time_hours: int = floori(time_total_seconds / 3600)\n\tvar time_minutes: int = floori((time_total_seconds - time_hours * 3600) / 60)\n\tvar time_seconds: int = floori(time_total_seconds - time_hours * 3600 - time_minutes * 60)\n\tvar time_string: String\n\tif time_hours > 0:\n\t\ttime_string = \"%02d:%02d:%02d\" % [time_hours, time_minutes, time_seconds]\n\telse:\n\t\ttime_string = \"%02d:%02d\" % [time_minutes, time_seconds]\n\t\n\treturn time_string\n\n\n# NOTE: you MUST use create_manual_timer() instead of\n# get_tree().create_timer() for gameplay code.\n# \n# - create_timer() uses Godot Timer class which runs based\n#   on real life time.\n# - create_manual_timer() uses ManualTimer runs based on\n#   game time which takes into account game pause and\n#   adjusting game speed.\n# \n# Using Godot Timers in gameplay code also causes desyncs\n# in multiplayer.\n#\n# Example: if you were to mistakenly use Godot Timer from\n# create_timer() to add delay to a tower spell, then the\n# spell would not function as expected and would cause\n# desyncs in multiplayer.\n#  \n# NOTE: another caveat is that you MUST NOT use\n# create_manual_timer() for things which are not part of the\n# synchronized multiplayer client. If you\n# create_manual_timer() for one player but not the others,\n# you will mess up the order of updating timers and cause a\n# multiplayer desync.\n# - Use create_manual_timer() only for code which runs for\n#   all players in multiplayer.\n# - Use create_timer() for UI and visual code. Also for code\n#   which specifically doesn't run in multiplayer, for\n#   example title screen code.\nfunc create_manual_timer(duration: float, parent: Node) -> ManualTimer:\n\tvar timer: ManualTimer = ManualTimer.new()\n\n\tvar parent_is_active: bool = parent.is_inside_tree() && !parent.is_queued_for_deletion()\n\tif parent_is_active:\n\t\tadd_child(timer)\n\t\ttimer.one_shot = true\n\t\ttimer.timeout.connect(timer.queue_free)\n\t\ttimer.start(duration)\n\telse:\n\t\ttimer.queue_free()\n\n\treturn timer\n\n\nfunc get_tower_at_canvas_pos(pos_canvas_2nd_floor: Vector2) -> Tower:\n\tvar pos_canvas_2nd_floor_snapped: Vector2 = VectorUtils.snap_canvas_pos_to_buildable_pos(pos_canvas_2nd_floor)\n\tvar pos_canvas: Vector2 = pos_canvas_2nd_floor_snapped + Vector2(0, Constants.TILE_SIZE.y)\n\tvar pos_wc3: Vector2 = VectorUtils.canvas_to_wc3_2d(pos_canvas)\n\tvar tower: Tower = Utils.get_tower_at_position(pos_wc3)\n\n\treturn tower\n\n\nfunc get_tower_at_position(position_wc3: Vector2) -> Tower:\n\tvar tower_node_list: Array = get_tree().get_nodes_in_group(\"towers\")\n\n\tfor tower_node in tower_node_list:\n\t\tvar tower: Tower = tower_node as Tower\n\t\tvar this_position: Vector2 = tower.get_position_wc3_2d()\n\t\tvar position_match: bool = position_wc3.is_equal_approx(this_position)\n\n\t\tif position_match:\n\t\t\treturn tower\n\n\treturn null\n\n\n# NOTE: Game.getGameTime() in JASS\nfunc get_time() -> float:\n\tvar game_time: Node = get_tree().get_root().get_node_or_null(\"GameScene/Gameplay/GameTime\")\n\n\tif game_time == null:\n\t\tpush_warning(\"game_time is null. You can ignore this warning during game restart.\")\n\n\t\treturn 0.0\n\n\tvar time: float = game_time.get_time()\n\n\treturn time\n\n\n# Returns current game tick. Used for deterministic calculations\n# in multiplayer to avoid float precision drift issues.\nfunc get_current_tick() -> int:\n\tvar game_client: Node = get_tree().get_root().get_node_or_null(\"GameScene/Gameplay/GameClient\")\n\n\tif game_client == null:\n\t\tpush_warning(\"game_client is null. You can ignore this warning during game restart.\")\n\n\t\treturn 0\n\n\tvar tick: int = game_client.get_current_tick()\n\n\treturn tick\n\n\n# Returns current time of day in the game world, in hours.\n# Between 0.0 and 24.0.\n# NOTE: this function works as intended but the day/night\n# cycle is not supported visually so don't use this in scripts.\n# NOTE: GetFloatGameState(GAME_STATE_TIME_OF_DAY) in JASS\nfunc get_time_of_day() -> float:\n\tvar irl_seconds: float = get_time()\n\tvar game_world_hours: float = Constants.INITIAL_TIME_OF_DAY + irl_seconds * Constants.IRL_SECONDS_TO_GAME_WORLD_HOURS\n\tvar time_of_day: float = fmod(game_world_hours, 24.0)\n\n\treturn time_of_day\n\n\nfunc filter_item_list(item_list: Array[Item], rarity_filter: Array = [], type_filter: Array = []) -> Array[Item]:\n\tvar filtered_list: Array = item_list.filter(\n\t\tfunc(item: Item) -> bool:\n\t\t\tvar rarity_ok: bool = rarity_filter.has(item.get_rarity()) || rarity_filter.is_empty()\n\t\t\tvar type_ok: bool = type_filter.has(item.get_item_type()) || type_filter.is_empty()\n\n\t\t\treturn rarity_ok && type_ok\n\t)\n\n\treturn filtered_list\n\n\nfunc add_object_to_world(object: Node):\n\tvar object_container: Node = get_tree().get_root().get_node_or_null(\"GameScene/World/ObjectContainer\")\n\t\n\tif object_container == null:\n\t\tpush_warning(\"object_container is null. You can ignore this warning during game restart.\")\n\t\t\n\t\treturn\n\n\tobject_container.add_child(object, true)\n\n\n# NOTE: currently, we assure that text fits inside the\n# richtextlabel tooltip by setting the minimum size. If all\n# lines in the text are shorter than the minimum size, there\n# will be extra empty space to the right of the text. It\n# looks bad. Would like the tooltip width to automatically\n# shrink in such cases so that tooltip size fits text size\n# without any empty space. Couldn't figure out how to do\n# that. There also seems to be a bug with RichTextLabel,\n# fit_content and embedding a RichTextLabel in tooltip which\n# stands in the way of implementing such behavior.\nfunc make_rich_text_tooltip(for_text: String) -> RichTextLabel:\n\tvar label: RichTextLabel = RichTextLabel.new()\n\tlabel.custom_minimum_size = Vector2(500, 50)\n\tlabel.fit_content  = true\n\tlabel.append_text(for_text)\n\n\treturn label\n\n\nfunc find_creep_path(player: Player, for_air_creeps: bool) -> Path2D:\n\tvar wave_path_list: Array = get_tree().get_nodes_in_group(\"wave_paths\")\n\n\tfor path in wave_path_list:\n\t\tvar player_match: bool = path.player_id == player.get_id()\n\t\tvar type_match: bool = (path.is_air && for_air_creeps) || (!path.is_air && !for_air_creeps)\n\n\t\tif player_match && type_match:\n\t\t\treturn path\n\n\treturn null\n\n\nfunc is_point_on_creep_path(point_wc3: Vector2, player: Player) -> bool:\n\tvar point_wc3_3d: Vector3 = Vector3(point_wc3.x, point_wc3.y, 0)\n\tvar point: Vector2 = VectorUtils.wc3_to_canvas(point_wc3_3d)\n\tvar creep_path_ground: Path2D = Utils.find_creep_path(player, false)\n\n\tif creep_path_ground == null:\n\t\tpush_error(\"Failed to find creep path.\")\n\n\t\treturn false\n\n\tvar curve: Curve2D = creep_path_ground.curve\n\n\tvar min_distance: float = 10000.0\n\tvar prev: Vector2 = curve.get_point_position(0)\n\n\tfor i in range(1, curve.point_count):\n\t\tvar curr: Vector2 = curve.get_point_position(i)\n\n\t\tvar closest_point: Vector2 = Geometry2D.get_closest_point_to_segment(point, prev, curr)\n\t\tvar distance: float = closest_point.distance_to(point)\n\n\t\tmin_distance = min(min_distance, distance)\n\n\t\tprev = curr\n\n\treturn min_distance < 100\n\n\n# Returns a list of lines, each line is a list of strings.\n# It's assumed that the first row is title row and it is\n# skipped.\nstatic func load_csv(path: String) -> Array[PackedStringArray]:\n\tvar file_exists: bool = FileAccess.file_exists(path)\n\n\tif !file_exists:\n\t\tprint_debug(\"Failed to load CSV because file doesn't exist. Path: %s\", path)\n\n\t\treturn []\n\n\tvar list: Array[PackedStringArray] = []\n\n\tvar file: FileAccess = FileAccess.open(path, FileAccess.READ)\n\n\tvar skip_title_row: bool = true\n\twhile !file.eof_reached():\n\t\tvar csv_line: PackedStringArray = file.get_csv_line()\n\n\t\tif skip_title_row:\n\t\t\tskip_title_row = false\n\t\t\tcontinue\n\n\t\tvar is_last_line: bool = csv_line.size() == 0 || (csv_line.size() == 1 && csv_line[0].is_empty())\n\t\tif is_last_line:\n\t\t\tcontinue\n\n\t\tlist.append(csv_line)\n\n\tfile.close()\n\n\treturn list\n\n\n# Loads properties from a csv file.\n# Transforms rows of \"id1, prop1, prop2...\"\n# Into a list of maps of [id1: {prop1: \"prop1 value\", prop2: \"prop2 value\"...\nstatic func load_csv_properties(properties_path: String, properties_dict: Dictionary, id_column: int):\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(properties_path)\n\n\tfor csv_line in csv:\n\t\tvar properties: Dictionary = UtilsStatic.load_csv_line(csv_line)\n\t\tvar id: int = properties[id_column].to_int()\n\t\tproperties_dict[id] = properties\n\n\n# Same as load_csv_properties(), but for property csv's\n# without an id column.\nstatic func load_csv_properties_with_automatic_ids(properties_path: String, properties_dict: Dictionary):\n\tvar csv: Array[PackedStringArray] = UtilsStatic.load_csv(properties_path)\n\n\tfor id in range(0, csv.size()):\n\t\tvar csv_line: PackedStringArray = csv[id]\n\t\tvar properties: Dictionary = UtilsStatic.load_csv_line(csv_line)\n\t\tproperties_dict[id] = properties\n\n\nstatic func load_csv_line(csv_line) -> Dictionary:\n\tvar out: Dictionary = {}\n\n\tfor property in range(csv_line.size()):\n\t\tvar csv_string: String = csv_line[property]\n\t\tout[property] = csv_string\n\n\treturn out\n\n\n# NOTE: can't use get_used_rect() here because creep atlases\n# are compressed.\nfunc get_sprite_dimensions(sprite: Sprite2D) -> Vector2:\n\tvar texture: Texture2D = sprite.texture\n\tvar texture_size: Vector2 = texture.get_size()\n\tvar sprite_dimensions: Vector2 = texture_size * sprite.scale\n\n\treturn sprite_dimensions\n\n\n# NOTE: can't use get_used_rect() here because creep atlases\n# are compressed.\nfunc get_animated_sprite_dimensions(sprite: AnimatedSprite2D, animation_name: String) -> Vector2:\n\tvar sprite_frames: SpriteFrames = sprite.sprite_frames\n\tvar texture: Texture2D = sprite_frames.get_frame_texture(animation_name, 0)\n\tvar sprite_dimensions: Vector2 = texture.get_size()\n\n\treturn sprite_dimensions\n\n\n# NOTE: Game.getMaxLevel() in JASS\nfunc get_max_level() -> int:\n\treturn Globals.get_wave_count()\n\n\nfunc get_colored_string(string: String, color: Color) -> String:\n\tvar out: String = \"[color=%s]%s[/color]\" % [color.to_html(), string]\n\n\treturn out\n\n\n# Divides two floats. In case of division by 0, returns\n# \"result_when_divide_by_zero\" arg, 0 by default.\n# NOTE: this function must be used instead of \"/\" whenever\n# there's division by variable which has any chance of\n# being 0.\nfunc divide_safe(a: float, b: float, result_when_divide_by_zero: float = 0.0) -> float:\n\tif b != 0.0:\n\t\tvar ratio: float = a / b\n\n\t\treturn ratio\n\telse:\n\t\treturn result_when_divide_by_zero\n\n\nfunc pick_random(rng: RandomNumberGenerator, array: Array) -> Variant:\n\tif array.is_empty():\n\t\treturn null\n\t\t\n\tvar random_element: Variant = array[rng.randi() % array.size()]\n\t\n\treturn random_element\n\n\nfunc shuffle(rng: RandomNumberGenerator, array: Array):\n\tfor i in array.size():\n\t\tvar random_index: int = rng.randi_range(0, array.size() - 1)\n\n\t\tif random_index == i:\n\t\t\tcontinue\n\t\telse:\n\t\t\tvar temp = array[random_index]\n\t\t\tarray[random_index] = array[i]\n\t\t\tarray[i] = temp\n\n\n# Accepts a map of elements to weights and returns a random\n# element. For example:\n# { \"a\": 10, \"b\": 20, \"c\": 70 }\n# will result in 10% a, 20% b, 70% c.\n# Note that weights don't have to add up to 100!\n# { \"a\": 1, \"b\": 2}\n# Will result in 1/3 a, 2/3 b.\nfunc random_weighted_pick(rng: RandomNumberGenerator, element_to_weight_map: Dictionary) -> Variant:\n\tif element_to_weight_map.is_empty():\n\t\tpush_error(\"Argument is empty\")\n\n\t\treturn null\n\n\tvar pair_list: Array = []\n\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_element_keys: Array = element_to_weight_map.keys()\n\tsorted_element_keys.sort()\n\tfor element in sorted_element_keys:\n\t\tvar weight: float = element_to_weight_map[element]\n\t\tvar pair: Array = [element, weight]\n\n\t\tpair_list.append(pair)\n\n\tvar weight_total: float = 0\n\n\tfor pair in pair_list:\n\t\tvar weight: float = pair[1]\n\t\tweight_total += weight\n\n\tfor i in range(1, pair_list.size()):\n\t\tpair_list[i][1] += pair_list[i - 1][1]\n\n\tvar k: float = rng.randf_range(0, weight_total)\n\n\tfor pair in pair_list:\n\t\tvar element: Variant = pair[0]\n\t\tvar weight: float = pair[1]\n\n\t\tif k <= weight:\n\t\t\treturn element\n\n\tpush_error(\"Failed to generate random element\")\n\n#\tNOTE: return first sorted element for determinism\n\treturn sorted_element_keys[0]\n\n\n# Use this in cases where script stores references to units\n# over a long time. Units may become invalid if they are\n# killed or sold or upgraded. Note that calling any methods,\n# including is_queued_for_deletion(), on an invalid unit\n# will result in an error. Didn't define type for argument\n# on purpose because argument can be an invalid instance\n# without type.\nfunc unit_is_valid(unit) -> bool:\n\tvar is_valid: bool = unit != null && is_instance_valid(unit) && unit.is_inside_tree() && !unit.is_queued_for_deletion()\n\n\treturn is_valid\n\n\n# Chance should be in range [0.0, 1.0]\n# To get chance for event with 10% occurence, call rand_chance(0.1)\nfunc rand_chance(rng: RandomNumberGenerator, chance: float) -> bool:\n\tvar clamped_chance: float = clampf(chance, 0.0, 1.0)\n\tvar random_float: float = rng.randf()\n\tvar chance_success = random_float <= clamped_chance\n\n\treturn chance_success\n\n\n# NOTE: this f-n extends the range slightly from the center\n# of target unit\nfunc get_units_in_range(caster: Unit, type: TargetType, center: Vector2, radius: float) -> Array[Unit]:\n\tif type == null:\n\t\treturn []\n\n\tvar group_name: String\n\tvar target_unit_type: TargetType.UnitType = type.get_unit_type()\n\tmatch target_unit_type:\n\t\tTargetType.UnitType.TOWERS: group_name = \"towers\"\n\t\tTargetType.UnitType.CREEPS: group_name = \"creeps\"\n\t\tTargetType.UnitType.CORPSES: group_name = \"corpses\"\n\n\tvar node_list: Array[Node] = get_tree().get_nodes_in_group(group_name)\n\n\tradius = Utils.apply_unit_range_extension(radius, type)\n\n\tvar player_towers_is_set: bool = type.player_towers_is_set()\n\n#\tNOTE: not using Array.filter() here because it takes\n#\tmore time than for loop\n\tvar filtered_unit_list: Array[Unit] = []\n\t\n\tfor node in node_list:\n\t\tvar unit: Unit = node as Unit\n\n\t\tif unit.is_queued_for_deletion():\n\t\t\tcontinue\n\n\t\tvar type_match: bool = type.match(unit)\n\n\t\tif !type_match:\n\t\t\tcontinue\n\n\t\tvar unit_is_in_range = VectorUtils.in_range(center, unit.get_position_wc3_2d(), radius)\n\n\t\tif !unit_is_in_range:\n\t\t\tcontinue\n\n\t\tif player_towers_is_set:\n\t\t\tvar player_match: bool = caster.get_player() == unit.get_player()\n\n\t\t\tif !player_match:\n\t\t\t\tcontinue\n\n\t\tfiltered_unit_list.append(unit)\n\n\tUtils.sort_objects_for_multiplayer(filtered_unit_list)\n\n\treturn filtered_unit_list\n\n\n# NOTE: use squared distances to get better perfomance. Also\n# don't convert from WC3 to pixel units because it doesn't\n# matter for sorting purposes.\nclass DistanceSorter:\n\tvar origin = Vector2.ZERO\n\n\tfunc sort(a: Unit, b: Unit):\n\t\tvar a_pos: Vector2 = a.get_position_wc3_2d()\n\t\tvar distance_a: float = a_pos.distance_squared_to(origin)\n\t\tvar b_pos: Vector2 = b.get_position_wc3_2d()\n\t\tvar distance_b: float = b_pos.distance_squared_to(origin)\n\n\t\t# Use UID as tiebreaker for deterministic sorting when distances are equal\n\t\tvar less_than: bool\n\t\tif absf(distance_a - distance_b) < 0.01:\n\t\t\tless_than = a.get_uid() < b.get_uid()\n\t\telse:\n\t\t\tless_than = distance_a < distance_b\n\n\t\treturn less_than\n\n\nfunc sort_unit_list_by_distance(unit_list: Array, position: Vector2):\n\tvar sorter: DistanceSorter = DistanceSorter.new()\n\tsorter.origin = position\n\tunit_list.sort_custom(Callable(sorter,\"sort\"))\n\n\n# This sort implements \"smart\" targeting for towers. It\n# ensures that towers will try to finish an older wave\n# before switching to a new wave. The sort works like this:\n# \n# 1. If one wave is active, then towers will pick nearest\n#    targets.\n# \n# 2. If multiple waves are active, then towers will pick\n#    nearest target in the oldest wave nearby.\nclass AttackTargetSorter:\n\tvar origin = Vector2.ZERO\n\n\tfunc sort(a: Unit, b: Unit):\n\t\tvar level_a: float = a.get_spawn_level()\n\t\tvar level_b: float = b.get_spawn_level()\n\n\t\tvar less_than: bool\n\t\tif level_a == level_b:\n\t\t\tvar a_pos: Vector2 = a.get_position_wc3_2d()\n\t\t\tvar distance_a: float = a_pos.distance_to(origin)\n\t\t\tvar b_pos: Vector2 = b.get_position_wc3_2d()\n\t\t\tvar distance_b: float = b_pos.distance_to(origin)\n\n\t\t\t# Use UID as tiebreaker for deterministic sorting when distances are equal\n\t\t\tif absf(distance_a - distance_b) < 0.01:\n\t\t\t\tless_than = a.get_uid() < b.get_uid()\n\t\t\telse:\n\t\t\t\tless_than = distance_a < distance_b\n\t\telse:\n\t\t\tless_than = level_a < level_b\n\n\t\treturn less_than\n\nfunc sort_creep_list_for_targeting(unit_list: Array, position: Vector2):\n\tvar sorter: AttackTargetSorter = AttackTargetSorter.new()\n\tsorter.origin = position\n\tunit_list.sort_custom(sorter.sort)\n\n\n# Converts CamelCaseSTR_Name to camel_case_str_name\nfunc camel_to_snake(camel_string: String) -> String:\n\tvar snake_string = \"\"\n\tvar previous_char = \"\"\n\t\n\tfor c in camel_string:\n\t\tif c.to_upper() == c and previous_char != \"\" and previous_char.to_upper() != previous_char:\n\t\t\tsnake_string += \"_\"\n\t\tsnake_string += c.to_lower()\n\t\tprevious_char = c\n\t\n\treturn snake_string\n\n\nfunc screaming_snake_case_to_camel_case(screaming_snake_case: String) -> String:\n\tvar words = screaming_snake_case.split(\"_\")\n\tvar camel_case = \"\"\n\t\n\tfor i in range(words.size()):\n\t\tcamel_case += words[i].capitalize()\n\t\n\treturn camel_case\n\n\nstatic func bit_is_set(mask: int, bit: int) -> bool:\n\tvar is_set: bool = (mask & bit) != 0x0\n\n\treturn is_set\n\n\n# formatFloat() in JASS\nfunc format_float(x: float, digits: int) -> String:\n\tvar out: String = String.num(x, digits)\n\n\treturn out\n\n\n# formatPercent() in JASS\nfunc format_percent(x: float, digits: int) -> String:\n\tvar x_percent: float = x * 100\n\tvar out: String = \"%s%%\" % String.num(x_percent, digits)\n\n\treturn out\n\n\n# formatPercentAddColor() in JASS\nfunc format_percent_add_color(x: float, digits: int) -> String:\n\tvar uncolored: String = format_percent(x, digits)\n\tvar color: Color\n\tif x < 0:\n\t\tcolor = Color.RED\n\telse:\n\t\tcolor = Color.GREEN\n\tvar out: String = get_colored_string(uncolored, color)\n\n\treturn out\n\n\nfunc to_pixels(distance_wc3: float) -> float:\n\tvar distance_pixels: float = distance_wc3 * Constants.WC3_DISTANCE_TO_PIXELS\n\n\treturn distance_pixels\n\n\nfunc from_pixels(distance_pixels: float) -> float:\n\tvar distance: float = distance_pixels / Constants.WC3_DISTANCE_TO_PIXELS\n\n\treturn distance\n\n\nfunc reset_scroll_container(scroll_container: ScrollContainer):\n\tvar h_scroll_bar: HScrollBar = scroll_container.get_h_scroll_bar()\n\th_scroll_bar.set_value(0.0)\n\n\tvar v_scroll_bar: VScrollBar = scroll_container.get_v_scroll_bar()\n\tv_scroll_bar.set_value(0.0)\n\n\nfunc get_tower_list() -> Array[Tower]:\n\tvar tower_node_list: Array[Node] = get_tree().get_nodes_in_group(\"towers\")\n\tvar tower_list: Array[Tower] = []\n\n\tfor tower_node in tower_node_list:\n\t\tvar tower: Tower = tower_node as Tower\n\t\ttower_list.append(tower)\n\n\tUtils.sort_objects_for_multiplayer(tower_list)\n\n\treturn tower_list\n\n\nfunc get_creep_list() -> Array[Creep]:\n\tvar creep_node_list: Array[Node] = get_tree().get_nodes_in_group(\"creeps\")\n\tvar creep_list: Array[Creep] = []\n\n\tfor creep_node in creep_node_list:\n\t\tvar creep: Creep = creep_node as Creep\n\t\tcreep_list.append(creep)\n\n\tUtils.sort_objects_for_multiplayer(creep_list)\n\n\treturn creep_list\n\n\n# Setup range indicators for tower attack, auras and extra\n# abilities.\n# NOTE: tower stats must be initialized before calling this\nfunc setup_range_indicators(range_data_list: Array[RangeData], parent: Node2D, player: Player) -> Array[RangeIndicator]:\n\tvar indicator_list: Array[RangeIndicator] = []\n\n\tvar occupied_radius_list: Array = []\n\n\tfor i in range(0, range_data_list.size()):\n\t\tvar range_data: RangeData = range_data_list[i]\n\n#\t\tNOTE: if there are multiple ranges with same radius,\n#\t\tshift them slightly so that they don't get drawn on\n#\t\ttop of each other.\n\t\tvar indicator_radius: float = range_data.get_radius_with_builder_bonus(player)\n\n#\t\tNOTE: add this bonus because\n#\t\tUtils.get_units_in_range() adds it. Otherwise the\n#\t\trange would look like it's too small.\n\t\tif !range_data.targets_creeps:\n\t\t\tindicator_radius += Constants.RANGE_CHECK_BONUS_FOR_TOWERS\n\n\t\twhile occupied_radius_list.has(indicator_radius):\n\t\t\tindicator_radius -= 10\n\n#\t\t\tIt's theoretically possible for there to be no\n#\t\t\tavailable radius, in that case - give up\n\t\t\tif indicator_radius == 10:\n\t\t\t\tbreak\n\n\t\toccupied_radius_list.append(indicator_radius)\n\n\t\tvar range_indicator: RangeIndicator = RangeIndicator.make()\n#\t\tNOTE: enable floor collisions only for range\n#\t\tindicators intended for creeps. For other range\n#\t\tindicators, like tower auras, we should not do\n#\t\tfloor collisions because the range indicator may be\n#\t\tfully located on the second floor.\n\t\trange_indicator.ability_name_english = range_data.name_english\n\t\trange_indicator.enable_floor_collisions = range_data.targets_creeps\n\t\trange_indicator.set_radius(indicator_radius)\n\t\tvar range_color: Color = RangeData.get_color_for_index(i)\n\t\trange_indicator.color = range_color\n\n#\t\tNOTE: range indicators which affect towers will be\n#\t\tdrawn at same height as tower.\n#\t\t \n#\t\tRange indicators which affect creeps will be drawn\n#\t\tone level lower, so that the indicator is \"on the\n#\t\tground\".\n\t\tvar y_offset: float\n\t\tif range_data.targets_creeps:\n\t\t\ty_offset = Constants.TILE_SIZE.y\n\t\telse:\n\t\t\ty_offset = 0\n\n\t\trange_indicator.y_offset = y_offset\n\n\t\tparent.add_child(range_indicator)\n\t\tindicator_list.append(range_indicator)\n\n\treturn indicator_list\n\n\n# Returns AoE damage dealt to unit, taking into account how\n# far the unit is from the AoE center. Normally, all units\n# inside the AoE range will receive the same damage but if\n# the \"sides_ratio\" arg is not 0, units far away from center\n# will receive less damage. For example, if sides_ratio is\n# 0.10, then units far away from the center of aoe will\n# receive 10% less damage.\nfunc get_aoe_damage(aoe_center: Vector2, target: Unit, radius: float, damage: float, sides_ratio: float) -> float:\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\tvar distance: float = aoe_center.distance_to(target_pos)\n\tvar distance_ratio: float = Utils.divide_safe(distance, radius)\n\tvar target_is_on_the_sides: bool = distance_ratio > 0.5\n\n\tif target_is_on_the_sides:\n\t\treturn damage * (1.0 - sides_ratio)\n\telse:\n\t\treturn damage\n\n\nfunc item_id_list_to_item_list(item_id_list: Array[int], player: Player) -> Array[Item]:\n\tvar item_list: Array[Item] = []\n\n\tfor item_id in item_id_list:\n\t\tvar item: Item = Item.make(item_id, player)\n\t\titem_list.append(item)\n\n\treturn item_list\n\n\nfunc item_list_to_item_id_list(item_list: Array[Item]) -> Array[int]:\n\tvar item_id_list: Array[int] = []\n\n\tfor item in item_list:\n\t\tvar item_id: int = item.get_id()\n\t\titem_id_list.append(item_id)\n\n#\tNOTE: sort so that item lists can be compared\n\titem_id_list.sort()\n\n\treturn item_id_list\n\n\n# NOTE: this assumes that you got a sprite inside a sprite\n# parent and the scale value returned by this function will\n# multiply the sprite's scale.\nfunc get_scale_from_grows(sprite_scale_min: float, sprite_scale_max: float, current_grows: float, max_grows: float) -> float:\n\tvar scale_max: float = sprite_scale_max / sprite_scale_min\n\tvar grow_ratio: float = clampf(current_grows / max_grows, 0.0, 1.0)\n\tvar current_scale: float = 1.0 + (scale_max - 1.0) *grow_ratio\n\n\treturn current_scale\n\n\n# Sort objects by UID to ensure deterministic iteration\n# order. Default order from Godot cannot be relied upon.\n# \n# NOTE: the objects in the list must implement get_uid()\n# \n# NOTE: only sort if the game is actually in multiplayer.\n# Skip sorting for singleplayer because sorting reduces FPS\n# by a lot on high gamespeeds. Specifically for timer and\n# projectile objects.\n# \n# NOTE: must use custom UID system instead of Godot's\n# built-in get_instance_id(). get_instance_id() doesn't have\n# reliable order.\nfunc sort_objects_for_multiplayer(object_list: Array):\n\tvar player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tvar is_multiplayer: bool = player_mode == PlayerMode.enm.MULTIPLAYER\n\n\tif is_multiplayer:\n\t\tobject_list.sort_custom(func(a, b): return a.get_uid() < b.get_uid())\n\n\n# Converts time in seconds to game ticks\nfunc time_to_ticks(time: float) -> int:\n\tvar ticks: int = roundi(time * GameClient.TICKS_PER_SECOND)\n\n\treturn ticks\n\n\n# Converts time in seconds to game ticks\nfunc ticks_to_time(ticks: int) -> float:\n\tvar time: float = ticks * 1.0 / GameClient.TICKS_PER_SECOND\n\n\treturn time\n"
  },
  {
    "path": "src/singletons/vector_utils.gd",
    "content": "extends Node\n\n\nfunc canvas_to_top_down(pos_canvas: Vector2) -> Vector2:\n\tvar pos_top_down: Vector2 = pos_canvas * Vector2(1.0, 2.0)\n\n\treturn pos_top_down\n\n\nfunc top_down_to_canvas(pos_top_down: Vector2) -> Vector2:\n\tvar pos_canvas: Vector2 = pos_top_down * Vector2(1.0, 0.5)\n\n\treturn pos_canvas\n\n\nfunc vector3_to_vector2(vec3: Vector3) -> Vector2:\n\treturn Vector2(vec3.x, vec3.y)\n\n\nfunc canvas_to_wc3_2d(pos_canvas: Vector2) -> Vector2:\n\tvar pos_top_down_pixels: Vector2 = VectorUtils.canvas_to_top_down(pos_canvas)\n\tvar pos_wc3: Vector2 = pos_top_down_pixels / Constants.WC3_DISTANCE_TO_PIXELS\n\n\treturn pos_wc3\n\n\n# NOTE: need to use z without converting to pixels, this is\n# how it works in general\nfunc wc3_to_canvas(pos_wc3: Vector3) -> Vector2:\n\tvar pos_pixels: Vector3 = pos_wc3 * Constants.WC3_DISTANCE_TO_PIXELS\n\tvar canvas_x: float = pos_pixels.x\n\tvar canvas_y: float = pos_pixels.y * 0.5 - pos_wc3.z\n\tvar pos_canvas: Vector2 = Vector2(canvas_x, canvas_y)\n\n\treturn pos_canvas\n\n\nfunc wc3_2d_to_canvas(pos_wc3_2d: Vector2) -> Vector2:\n\tvar pos_wc3: Vector3 = Vector3(pos_wc3_2d.x, pos_wc3_2d.y, 0)\n\tvar pos_canvas: Vector2 = VectorUtils.wc3_to_canvas(pos_wc3)\n\n\treturn pos_canvas\n\n\nfunc in_range(start: Vector2, end: Vector2, radius: float) -> bool:\n\tvar distance_squared: float = start.distance_squared_to(end)\n\tvar radius_squared: float = radius * radius\n\tvar result: bool = distance_squared <= radius_squared\n\n\treturn result\n\n\n# Snaps canvas position to nearest buildable tile. Note that\n# buildable tile is one quarter of normal tile.\n# NOTE: this f-n needs to rotate the position because canvas\n# coordinates have North pointing to up-right direction\n# while top down map coordinates have North pointing to up\n# direction\nfunc snap_canvas_pos_to_buildable_pos(pos_canvas: Vector2) -> Vector2:\n\tvar pos_top_down: Vector2 = VectorUtils.canvas_to_top_down(pos_canvas)\n\tvar pos_top_down_rotated: Vector2 = Vector2(pos_top_down.rotated(deg_to_rad(-45)))\n\tvar pos_top_down_rotated_snapped: Vector2 = pos_top_down_rotated.snapped(Vector2(Constants.TILE_SIZE_PIXELS_HALF, Constants.TILE_SIZE_PIXELS_HALF))\n\tvar pos_top_down_snapped: Vector2 = pos_top_down_rotated_snapped.rotated(deg_to_rad(45))\n\tvar pos_canvas_snapped: Vector2 = VectorUtils.top_down_to_canvas(pos_top_down_snapped)\n\n\treturn pos_canvas_snapped\n"
  },
  {
    "path": "src/singletons/wave_special.gd",
    "content": "extends Node\n\n\n# Functions for dealing with specials that are applied to\n# creep waves. Note that getters for wave special properties\n# are located in as separate class WaveSpecialProperties.\n\n\nconst _special_count_chances: Dictionary = {\n\t0: 30,\n\t1: 50,\n\t2: 20,\n}\n\nconst _special_count_chances_for_bonus_waves: Dictionary = {\n\t0: 10,\n\t1: 60,\n\t2: 30,\n}\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_random(level: int, creep_size: CreepSize.enm, wave_has_champions: bool) -> Array[int]:\n\tvar override_wave_specials: Array[int] = Config.override_wave_specials()\n\tif !override_wave_specials.is_empty():\n\t\treturn override_wave_specials\n\n\tvar is_challenge: bool = CreepSize.is_challenge(creep_size)\n\n\tif is_challenge:\n\t\treturn []\n\n\tvar available_specials_for_first: Array[int] = _get_available_specials_for_first_special(level, creep_size, wave_has_champions)\n\tvar first_special: int = _get_random_special(available_specials_for_first)\n\n\tvar available_specials_for_second: Array[int] = _get_available_specials_for_second_special(first_special, available_specials_for_first)\n\tvar second_special: int = _get_random_special(available_specials_for_second)\n\n\tvar generated_specials: Array[int] = [first_special, second_special]\n\n\tvar special_count: int = get_random_special_count(level)\n\n\tvar random_special_list: Array[int] = []\n\n\tfor i in range(0, special_count):\n\t\tvar special: int = generated_specials[i]\n\n\t\tif special != -1:\n\t\t\trandom_special_list.append(special)\n\n\treturn random_special_list\n\n\nfunc apply_to_creep(special_list: Array[int], creep: Creep):\n#\tNOTE: need to filter specials because a special may not\n#\tapply to all creeps in wave. A common scenario is when a\n#\tspecial applies only to champions\n\tvar applied_list: Array[int] = special_list.filter(\n\t\tfunc(special: int) -> bool:\n\t\t\tvar special_applies: bool = _special_applies_to_creep(special, creep)\n\n\t\t\treturn special_applies\n\t)\n\n\tcreep.set_special_list(applied_list)\n\n\tvar hp_modifier: float = _get_hp_modifier(applied_list)\n\tcreep.modify_property(ModificationType.enm.MOD_HP_PERC, hp_modifier)\n\n#\tNOTE: creep needs mana only if the *applied* specials\n#\trequire mana.\n\tvar creep_base_mana: float = _get_creep_base_mana(applied_list, creep)\n\tcreep.set_base_mana(creep_base_mana)\n\tcreep.set_mana(creep_base_mana)\n\n\tvar base_color: Color = WaveSpecialProperties.get_base_color(applied_list)\n\tcreep.set_sprite_base_color(base_color)\n\n\tfor special in applied_list:\n\t\tvar buff: BuffType = WaveSpecialProperties.get_special_buff(special)\n\t\tbuff.apply_to_unit_permanent(creep, creep, 0)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc get_random_special_count(level: int) -> int:\n\tif level <= Constants.MIN_WAVE_FOR_SPECIAL:\n\t\treturn 0\n\n\tvar wave_is_bonus: bool = Utils.wave_is_bonus(level)\n\tvar count_chance_map: Dictionary\n\tif wave_is_bonus:\n\t\tcount_chance_map = _special_count_chances\n\telse:\n\t\tcount_chance_map = _special_count_chances_for_bonus_waves\n\n\tvar special_count: int = Utils.random_weighted_pick(Globals.synced_rng, count_chance_map)\n\n\treturn special_count\n\n\nfunc _get_random_special(available_special_list: Array[int]) -> int:\n\tif available_special_list.is_empty():\n\t\treturn -1\n\n\tvar special_to_frequency_map: Dictionary = {}\n\n\tfor special in available_special_list:\n\t\tvar frequency: int = WaveSpecialProperties.get_frequency(special)\n\t\tspecial_to_frequency_map[special] = frequency\n\n\tvar random_special: int = Utils.random_weighted_pick(Globals.synced_rng, special_to_frequency_map)\n\n\treturn random_special\n\n\nfunc _get_available_specials_for_first_special(level: int, creep_size: CreepSize.enm, wave_has_champions: bool) -> Array[int]:\n\tvar all_special_list: Array = WaveSpecialProperties.get_all_specials_list()\n\tvar available_special_list: Array[int] = []\n\n\tvar wave_level: int = level\n\n\tfor special in all_special_list:\n\t\tvar is_enabled: bool = WaveSpecialProperties.get_enabled(special)\n\n\t\tif !is_enabled:\n\t\t\tcontinue\n\n\t\tvar required_level: int = WaveSpecialProperties.get_required_wave_level(special)\n\t\tvar level_ok: bool = wave_level >= required_level\n\n\t\tvar applicable_sizes: Array[CreepSize.enm] = WaveSpecialProperties.get_applicable_sizes(special)\n\t\tvar size_ok: bool = applicable_sizes.has(creep_size)\n\n\t\tvar champion_or_boss_wave_only: bool = WaveSpecialProperties.get_champion_or_boss_wave_only(special)\n\t\tvar wave_is_champion_or_boss: bool = wave_has_champions || creep_size == CreepSize.enm.BOSS\n\t\tvar wave_power_ok: bool\n\t\tif champion_or_boss_wave_only:\n\t\t\twave_power_ok = wave_is_champion_or_boss\n\t\telse:\n\t\t\twave_power_ok = true\n\n\t\tvar is_available: bool = level_ok && size_ok && wave_power_ok\n\n\t\tif is_available:\n\t\t\tavailable_special_list.append(special)\n\n\treturn available_special_list\n\n\nfunc _get_available_specials_for_second_special(first_special: int, available_specials_for_first: Array[int]) -> Array[int]:\n\tif first_special == -1:\n\t\treturn []\n\n\tvar result: Array[int] = available_specials_for_first.duplicate()\n\n\tvar groups_of_first_special: Array[String] = WaveSpecialProperties.get_group_list(first_special)\n\n# \tFilter out specials which are in the same group as\n# \tthe first special\n\tfor group in groups_of_first_special:\n\t\tvar specials_in_group: Array = WaveSpecialProperties.get_specials_in_group(group)\n\n\t\tfor special in specials_in_group:\n\t\t\tresult.erase(special)\n\n#\tNOTE: don't pick same special twice\n\tresult.erase(first_special)\n\n\treturn result\n\n\nfunc _get_hp_modifier(special_list: Array[int]) -> float:\n\tif special_list.is_empty():\n\t\treturn 0.0\n\n\tvar hp_mod_list: Array[float] = []\n\n\tfor special in special_list:\n\t\tvar hp_modifier: float = WaveSpecialProperties.get_hp_modifier(special)\n\n\t\thp_mod_list.append(hp_modifier)\n\n\thp_mod_list.sort()\n\n\tif hp_mod_list.size() == 1:\n\t\treturn hp_mod_list.front()\n\telse:\n\t\tvar min_mod: float = hp_mod_list.front()\n\t\tvar max_mod: float = hp_mod_list.back()\n\n\t\tif min_mod <= 0 && max_mod >= 0:\n\t\t\tvar total_mod: float = min_mod + max_mod\n\n\t\t\treturn total_mod\n\t\telif min_mod < 0 && max_mod < 0:\n\t\t\treturn min_mod\n\t\telif min_mod > 0 && max_mod > 0:\n\t\t\treturn max_mod\n\t\telse:\n\t\t\treturn max_mod\n\n\nfunc _get_creep_base_mana(special_list: Array[int], creep: Creep) -> float:\n\tvar creep_should_have_mana: bool = false\n\n\tfor special in special_list:\n\t\tvar special_applies: bool = _special_applies_to_creep(special, creep)\n\t\tvar special_uses_mana: bool = WaveSpecialProperties.get_uses_mana(special)\n\n\t\tif special_applies && special_uses_mana:\n\t\t\tcreep_should_have_mana = true\n\n\tvar creep_base_mana: float\n\tif creep_should_have_mana:\n\t\tvar creep_size: CreepSize.enm = creep.get_size()\n\t\tcreep_base_mana = CreepSize.get_base_mana(creep_size)\n\telse:\n\t\tcreep_base_mana = 0\n\n\treturn creep_base_mana\n\n\nfunc _special_applies_to_creep(special: int, creep: Creep) -> bool:\n\tvar creep_size: CreepSize.enm = creep.get_size()\n\tvar special_only_for_champions_or_bosses: bool = WaveSpecialProperties.get_champion_or_boss_wave_only(special)\n\tvar special_applies: bool\n\tif special_only_for_champions_or_bosses:\n\t\tspecial_applies = creep_size == CreepSize.enm.BOSS || creep_size == CreepSize.enm.CHAMPION\n\telse:\n\t\tspecial_applies = true\n\n\treturn special_applies\n"
  },
  {
    "path": "src/spells/spell_blizzard.gd",
    "content": "extends SpellDummy\n\nconst WAVE_INTERVAL: float = 1.0\n\nvar _damage: float = 0.0\nvar _radius: float = 0.0\nvar _wave_count: int = 0\n\nvar _completed_wave_count: int = 0\n\n@export var _particles: CPUParticles2D\n@export var _wave_timer: ManualTimer\n\n\n# Called when the node enters the scene tree for the first time.\nfunc _ready():\n\tsuper()\n\n\t_wave_timer.start(WAVE_INTERVAL)\n\n#\tNOTE: do first wave on creation\n\t_on_wave_timer_timeout()\n\n#\tMove particles emitter so that they are above target position\n\tvar particles_pos_wc3: Vector3 = Vector3(_target_position.x, _target_position.y, Constants.TILE_SIZE_WC3 * 6)\n\tvar particles_pos_canvas: Vector2 = VectorUtils.wc3_to_canvas(particles_pos_wc3)\n\t_particles.global_position = particles_pos_canvas\n\n\nfunc _on_wave_timer_timeout():\n\tdo_spell_damage_aoe(_target_position, _radius, _damage, 0.0)\n\n\t_completed_wave_count += 1\n\n\tvar all_waves_done: bool = _completed_wave_count >= _wave_count\n\tif all_waves_done:\n\t\t_wave_timer.stop()\n\t\t_particles.set_emitting(false)\n\n\n# NOTE: subclasses override this to save data that is useful\n# for them\nfunc _set_subclass_data(data: SpellType.SpellData):\n\t_damage = data.blizzard.damage\n\t_radius = data.blizzard.radius\n\t_wave_count = data.blizzard.wave_count\n"
  },
  {
    "path": "src/spells/spell_blizzard.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://d4gxaau40jg0n\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://b14bbv4n46f1j\" path=\"res://src/spells/spell_dummy.tscn\" id=\"1_k5o08\"]\n[ext_resource type=\"Script\" path=\"res://src/spells/spell_blizzard.gd\" id=\"2_j1d1f\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cifmqgyviomde\" path=\"res://assets/misc/projectile.png\" id=\"3_6bej4\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"4_pu431\"]\n\n[node name=\"SpellBlizzard\" node_paths=PackedStringArray(\"_particles\", \"_wave_timer\") instance=ExtResource(\"1_k5o08\")]\nscript = ExtResource(\"2_j1d1f\")\n_particles = NodePath(\"CPUParticles2D\")\n_wave_timer = NodePath(\"WaveTimer\")\n\n[node name=\"CPUParticles2D\" type=\"CPUParticles2D\" parent=\".\" index=\"3\"]\nmodulate = Color(0.298039, 0.639216, 1, 0.784314)\nposition = Vector2(0, -500)\namount = 6\nlifetime = 0.4\nexplosiveness = 0.5\ntexture = ExtResource(\"3_6bej4\")\nemission_shape = 2\nemission_sphere_radius = 128.0\ndirection = Vector2(0, 1)\nspread = 5.0\ngravity = Vector2(0, 0)\ninitial_velocity_min = 800.0\ninitial_velocity_max = 800.0\nlinear_accel_min = 2000.0\nlinear_accel_max = 2000.0\n\n[node name=\"WaveTimer\" type=\"Node\" parent=\".\" index=\"4\"]\nscript = ExtResource(\"4_pu431\")\n\n[connection signal=\"timeout\" from=\"WaveTimer\" to=\".\" method=\"_on_wave_timer_timeout\"]\n"
  },
  {
    "path": "src/spells/spell_chain_lightning.gd",
    "content": "extends SpellDummy\n\nconst CHAIN_DISTANCE: float = 300.0\nconst VISUAL_LIFETIME: float = 0.4\nconst VISUAL_COLOR: Color = Color.SKY_BLUE\n\nvar _damage: float = 0.0\nvar _damage_reduction: float = 0.0\nvar _chain_count: int = 0\n\n\n# Called when the node enters the scene tree for the first time.\nfunc _ready():\n\tsuper()\n\n\tvar hit_list: Array[Unit] = _get_hit_list()\n\n\tif hit_list.is_empty():\n\t\treturn\n\n#\tAdd visual for chain lightning\n\tvar unit_list_for_visual: Array[Unit] = hit_list.duplicate()\n\t\n#\tNOTE: first chain needs to originate from the position\n#\tof the spell dummy NOT the caster. This is to correctly\n#\thandle target_cast_from_point() case.\n\tvar origin_pos: Vector3 = get_position_wc3()\n\tvar first_unit: Unit = hit_list[0]\n\t_create_lightning_section_from_pos(origin_pos, first_unit)\n\n\tfor i in range(0, unit_list_for_visual.size() - 1):\n\t\tvar start_unit: Unit = unit_list_for_visual[i]\n\t\tvar end_unit: Unit = unit_list_for_visual[i + 1]\n\t\t_create_lightning_section(start_unit, end_unit)\n\t\n# \tApply damage\n\tfor i in range(0, hit_list.size()):\n\t\tvar unit: Unit = hit_list[i]\n\t\tvar current_damage_reduction = max(0, 1.0 - _damage_reduction * i)\n\t\tvar current_damage: float = _damage * current_damage_reduction\n\n\t\tdo_spell_damage(unit, current_damage)\n\n\nfunc _get_hit_list() -> Array[Unit]:\n\tvar hit_unit_list: Array[Unit] = []\n\tvar current_position: Vector2 = _target_position\n\n\tfor i in range(0, _chain_count):\n\t\tvar unit_list: Array[Unit] = Utils.get_units_in_range(_caster, TargetType.new(TargetType.CREEPS), current_position, CHAIN_DISTANCE)\n\n\t\tfor unit in hit_unit_list:\n\t\t\tunit_list.erase(unit)\n\n\t\tif unit_list.is_empty():\n\t\t\tbreak\n\n\t\tUtils.sort_unit_list_by_distance(unit_list, current_position)\n\n\t\tvar hit_unit: Unit = unit_list[0]\n\t\thit_unit_list.append(hit_unit)\n\t\tcurrent_position = hit_unit.get_position_wc3_2d()\n\t\n\treturn hit_unit_list\n\n\nfunc _create_lightning_section(start_unit: Unit, end_unit: Unit):\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, start_unit, end_unit)\n\t_setup_chain(interpolated_sprite)\n\n\nfunc _create_lightning_section_from_pos(start_pos: Vector3, end_unit: Unit):\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, start_pos, end_unit)\n\t_setup_chain(interpolated_sprite)\n\t_setup_chain(interpolated_sprite)\n\n\nfunc _setup_chain(chain: InterpolatedSprite):\n\tchain.set_lifetime(VISUAL_LIFETIME)\n\n\tchain.modulate = VISUAL_COLOR.darkened(0.8)\n\n\tvar modulate_tween = create_tween()\n\tmodulate_tween.tween_property(chain, \"modulate\",\n\t\tVISUAL_COLOR,\n\t\t0.1 * VISUAL_LIFETIME)\n\tmodulate_tween.tween_property(chain, \"modulate\",\n\t\tColor.TRANSPARENT,\n\t\t0.1 * VISUAL_LIFETIME).set_delay(0.8 * VISUAL_LIFETIME)\n\n\n# NOTE: subclasses override this to save data that is useful\n# for them\nfunc _set_subclass_data(data: SpellType.SpellData):\n\t_damage = data.chain_lightning.damage\n\t_damage_reduction = data.chain_lightning.damage_reduction\n\t_chain_count = data.chain_lightning.chain_count\n"
  },
  {
    "path": "src/spells/spell_chain_lightning.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dd1gb6eskkg7k\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://b14bbv4n46f1j\" path=\"res://src/spells/spell_dummy.tscn\" id=\"1_bckeq\"]\n[ext_resource type=\"Script\" path=\"res://src/spells/spell_chain_lightning.gd\" id=\"2_o52yd\"]\n\n[node name=\"SpellChainLightning\" instance=ExtResource(\"1_bckeq\")]\nscript = ExtResource(\"2_o52yd\")\n"
  },
  {
    "path": "src/spells/spell_dummy.gd",
    "content": "class_name SpellDummy extends DummyUnit\n\n\n# Instance of a spell. Should be created using SpellType.\n\n\n# NOTE: target may be null if spell was cast on point\nvar _target: Unit = null\nvar _target_position: Vector2 = Vector2.ZERO\nvar _lifetime: float = 0.0\n\n\n@export var _debug_sprite: Sprite2D\n@export var _debug_sprite_target: Sprite2D\n@export var _lifetime_timer: ManualTimer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tsuper()\n\t\n\t_debug_sprite.visible = Config.visible_spell_dummys_enabled()\n\t_debug_sprite_target.visible = Config.visible_spell_dummys_enabled()\n\t\n\tvar debug_sprite_pos_canvas: Vector2 = VectorUtils.wc3_to_canvas(Vector3(_target_position.x, _target_position.y, 0))\n\t_debug_sprite_target.global_position = debug_sprite_pos_canvas\n\n\t_lifetime_timer.start(_lifetime)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc init_spell(caster: Unit, target: Unit, lifetime: float, data: SpellType.SpellData, damage_event_handler: Callable, target_pos: Vector2, damage_ratio: float, crit_ratio: float):\n\t_caster = caster\n\t_lifetime = lifetime\n\t_set_subclass_data(data)\n\n\tset_damage_event(damage_event_handler)\n\n\t_target = target\n\t_target_position = target_pos\n\t_damage_ratio = damage_ratio\n\t_crit_ratio = crit_ratio\n\n\nfunc get_lifetime() -> float:\n\treturn _lifetime\n\n\nfunc get_remaining_lifetime() -> float:\n\tvar remaining_lifetime: float = _lifetime_timer.get_time_left()\n\n\treturn remaining_lifetime\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: subclasses override this to save data that is useful\n# for them\nfunc _set_subclass_data(_data: SpellType.SpellData):\n\tpass\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_lifetime_timer_timeout():\n\t_cleanup()\n\n\nfunc _on_cast_type_tree_exited():\n\t_cleanup()\n"
  },
  {
    "path": "src/spells/spell_dummy.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://b14bbv4n46f1j\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://by01sg1a1yihc\" path=\"res://src/unit/dummy_unit.tscn\" id=\"1_r3nuv\"]\n[ext_resource type=\"Script\" path=\"res://src/spells/spell_dummy.gd\" id=\"2_l5ik5\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bte5c4ua8te4k\" path=\"res://assets/misc/icon.png\" id=\"3_20ho4\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"4_lr4lx\"]\n\n[node name=\"SpellDummy\" node_paths=PackedStringArray(\"_debug_sprite\", \"_debug_sprite_target\", \"_lifetime_timer\") instance=ExtResource(\"1_r3nuv\")]\nz_index = 100\nscript = ExtResource(\"2_l5ik5\")\n_debug_sprite = NodePath(\"DebugSprite\")\n_debug_sprite_target = NodePath(\"DebugSpriteTarget\")\n_lifetime_timer = NodePath(\"LifetimeTimer\")\n\n[node name=\"DebugSprite\" type=\"Sprite2D\" parent=\".\" index=\"0\"]\nmodulate = Color(0.827451, 0, 0.835294, 0.407843)\ntexture = ExtResource(\"3_20ho4\")\n\n[node name=\"LifetimeTimer\" type=\"Node\" parent=\".\" index=\"1\"]\nscript = ExtResource(\"4_lr4lx\")\none_shot = true\n\n[node name=\"DebugSpriteTarget\" type=\"Sprite2D\" parent=\".\" index=\"2\"]\nmodulate = Color(0.85098, 0.929412, 0.443137, 0.764706)\ntexture = ExtResource(\"3_20ho4\")\n\n[connection signal=\"timeout\" from=\"LifetimeTimer\" to=\".\" method=\"_on_lifetime_timer_timeout\"]\n"
  },
  {
    "path": "src/spells/spell_forked_lightning.gd",
    "content": "extends SpellDummy\n\n\nconst AOE_DISTANCE: float = 400.0\nconst VISUAL_LIFETIME: float = 0.4\nconst VISUAL_COLOR: Color = Color.SKY_BLUE\n\nvar _damage: float = 0.0\nvar _target_count: int = 0\n\n\nfunc _ready():\n\tsuper()\n\n\tif _target == null:\n\t\tpush_error(\"Forked lightning must be cast on target. Casting on point is not supported.\")\n\t\t\n\t\treturn\n\n\tvar hit_list: Array[Unit] = _get_hit_list()\n\n#\tAdd visual for chain lightning\n\tvar unit_list_for_visual: Array[Unit] = hit_list.duplicate()\n\tvar caster: Unit = get_caster()\n\tunit_list_for_visual.insert(0, caster)\n\t\n\tfor creep in hit_list:\n\t\tvar start_unit: Unit = get_caster()\n\t\tvar end_unit: Unit = creep\n\t\t_create_lightning_section(start_unit, end_unit)\n\t\n# \tApply damage\n\tfor creep in hit_list:\n\t\tdo_spell_damage(creep, _damage)\n\n\nfunc _get_hit_list() -> Array[Unit]:\n\tvar hit_unit_list: Array[Unit] = []\n\thit_unit_list.append(_target)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(_target, TargetType.new(TargetType.CREEPS), AOE_DISTANCE)\n\n\twhile true:\n\t\tvar next: Unit = it.next_random()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next == _target:\n\t\t\tcontinue\n\n\t\tif hit_unit_list.size() == _target_count:\n\t\t\tbreak\n\n\t\thit_unit_list.append(next)\n\t\n\treturn hit_unit_list\n\n\nfunc _create_lightning_section(start_unit: Unit, end_unit: Unit):\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, start_unit, end_unit)\n\tinterpolated_sprite.set_lifetime(VISUAL_LIFETIME)\n\n\tinterpolated_sprite.modulate = VISUAL_COLOR.darkened(0.8)\n\n\tvar modulate_tween = create_tween()\n\tmodulate_tween.tween_property(interpolated_sprite, \"modulate\",\n\t\tVISUAL_COLOR,\n\t\t0.1 * VISUAL_LIFETIME)\n\tmodulate_tween.tween_property(interpolated_sprite, \"modulate\",\n\t\tColor.TRANSPARENT,\n\t\t0.1 * VISUAL_LIFETIME).set_delay(0.8 * VISUAL_LIFETIME)\n\n\n# NOTE: subclasses override this to save data that is useful\n# for them\nfunc _set_subclass_data(data: SpellType.SpellData):\n\t_damage = data.forked_lightning.damage\n\t_target_count = data.forked_lightning.target_count\n"
  },
  {
    "path": "src/spells/spell_forked_lightning.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dtt1y06kkd14b\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://b14bbv4n46f1j\" path=\"res://src/spells/spell_dummy.tscn\" id=\"1_vvpme\"]\n[ext_resource type=\"Script\" path=\"res://src/spells/spell_forked_lightning.gd\" id=\"2_pwt26\"]\n\n[node name=\"SpellForkedLightning\" instance=ExtResource(\"1_vvpme\")]\nscript = ExtResource(\"2_pwt26\")\n"
  },
  {
    "path": "src/spells/spell_swarm.gd",
    "content": "extends SpellDummy\n\n\n# This spell implements the \"Carrion Swarm\" spell from WC3.\n# Deals damage in a cone from caster to target. Works as a\n# moving AoE which expands as it gets closer to target.\n# \n# The swarm moves in the direction of defined target\n# position but keeps going past the target position. It only\n# stops once the defined lifetime is over.\n\n\nconst MOVE_PERIOD: float = 0.2\n\nvar _current_swarm_pos: Vector2\nvar _already_damaged_list: Array[Unit] = []\n\n# Spell data\nvar _damage: float\nvar _start_pos: Vector2\nvar _start_radius: float\nvar _end_radius: float\nvar _travel_distance: float\nvar _effect_path: String\nvar _move_vector: Vector2\n\n@export var _move_timer: ManualTimer\n\n\nfunc _ready():\n\tsuper()\n\n\t_start_pos = get_position_wc3_2d()\n\n\t_current_swarm_pos = _start_pos\n\n#\tNOTE: need to subtract MOVE_PERIOD here so that the last\n#\tmove step is done before the spell expires due to\n#\tlifetime expiring. If this subtraction is not done, then\n#\tthe spell will not reach the max distance as it's\n#\tsupposed to.\n\tvar lifetime: float = get_lifetime()\n\tvar move_speed: float = _travel_distance / (lifetime - MOVE_PERIOD)\n\t_move_vector = (_target_position - _start_pos).normalized() * move_speed\n\n\nfunc _on_move_timer_timeout():\n#\tMove current position of spell\n\t_current_swarm_pos = _current_swarm_pos + _move_vector * MOVE_PERIOD\n\n# \tAdd visual effect\n\tvar effect: int = Effect.create_animated(_effect_path, Vector3(_current_swarm_pos.x, _current_swarm_pos.y, 0.0), 0.0)\n\tvar effect_scale: float = _get_effect_scale()\n\tEffect.set_scale(effect, effect_scale)\n\n# \tDeal damage\n\tvar current_radius: float = _get_current_radius()\n\tvar creep_list: Array = Utils.get_units_in_range(_caster, TargetType.new(TargetType.CREEPS), _current_swarm_pos, current_radius)\n\n#\tDeal damage once to each creep in path\n\tfor already_damaged_creep in _already_damaged_list:\n\t\tif !Utils.unit_is_valid(already_damaged_creep):\n\t\t\tcontinue\n\n\t\tcreep_list.erase(already_damaged_creep)\n\n\tfor creep in creep_list:\n\t\tdo_spell_damage(creep, _damage)\n\t\t_already_damaged_list.append(creep)\n\n\tvar _travel_distance_current: float = _start_pos.distance_to(_current_swarm_pos)\n\tvar reached_target: bool = round(_travel_distance_current) >= round(_travel_distance)\n\n\tif reached_target:\n\t\t_move_timer.stop()\n\n\nfunc _get_move_progress() -> float:\n\tvar start_pos: Vector2 = get_position_wc3_2d()\n\tvar distance_travelled: float = _current_swarm_pos.distance_to(start_pos)\n\tvar total_distance: float = start_pos.distance_to(_target_position)\n\tvar move_progress: float = Utils.divide_safe(distance_travelled, total_distance, 1.0)\n\n\treturn move_progress\n\n\nfunc _get_effect_scale() -> float:\n\tvar lifetime: float = get_lifetime()\n\tvar remaining_lifetime: float = get_remaining_lifetime()\n\tvar move_progress: float = 1.0 - Utils.divide_safe(remaining_lifetime, lifetime, 0.0)\n\tvar effect_scale: float = lerp(0.5, 2.0, move_progress)\n\n\treturn effect_scale\n\n\nfunc _get_current_radius() -> float:\n\tvar move_progress: float = _get_move_progress()\n\tvar current_radius: float = lerp(_start_radius, _end_radius, move_progress)\n\n\treturn current_radius\n\n\n# NOTE: subclasses override this to save data that is useful\n# for them\nfunc _set_subclass_data(data: SpellType.SpellData):\n\t_damage = data.swarm.damage\n\t_start_radius = data.swarm.start_radius\n\t_end_radius = data.swarm.end_radius\n\t_travel_distance = data.swarm.travel_distance\n\t_effect_path = data.swarm.effect_path\n"
  },
  {
    "path": "src/spells/spell_swarm.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://c3jynpcq4c1bb\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://b14bbv4n46f1j\" path=\"res://src/spells/spell_dummy.tscn\" id=\"1_54xre\"]\n[ext_resource type=\"Script\" path=\"res://src/spells/spell_swarm.gd\" id=\"2_uvcqe\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"3_kjb2g\"]\n\n[node name=\"SpellSwarm\" node_paths=PackedStringArray(\"_move_timer\") instance=ExtResource(\"1_54xre\")]\nscript = ExtResource(\"2_uvcqe\")\n_move_timer = NodePath(\"MoveTimer\")\n\n[node name=\"MoveTimer\" type=\"Node\" parent=\".\" index=\"2\"]\nscript = ExtResource(\"3_kjb2g\")\nwait_time = 0.2\nautostart = true\n\n[connection signal=\"timeout\" from=\"MoveTimer\" to=\".\" method=\"_on_move_timer_timeout\"]\n"
  },
  {
    "path": "src/spells/spell_type.gd",
    "content": "class_name SpellType extends Node\n\n# SpellType is used to store information about spells. Used to\n# create instances of SpellDummy.\n\n# NOTE: this class is called \"Cast\" in JASS\n\n\nenum Name {\n\tBLIZZARD,\n\tCHAIN_LIGHTNING,\n\tFORKED_LIGHTNING,\n\tCARRION_SWARM,\n}\n\n\nclass BlizzardData:\n\tvar damage: float = 0.0\n\tvar radius: float = 0.0\n\tvar wave_count: int = 0\n\n\nclass ChaingLightningData:\n\tvar damage: float = 0.0\n\tvar damage_reduction: float = 0.0\n\tvar chain_count: int = 0\n\n\nclass ForkedLightningData:\n\tvar damage: float = 0.0\n\tvar target_count: int = 0\n\n\nclass SwarmData:\n\tvar damage: float = 0.0\n\tvar start_radius: float = 0.0\n\tvar end_radius: float = 0\n\tvar travel_distance: float = 0.0\n\tvar effect_path: String = \"\"\n\n\nclass SpellData:\n\tvar blizzard: BlizzardData = BlizzardData.new()\n\tvar chain_lightning: ChaingLightningData = ChaingLightningData.new()\n\tvar forked_lightning: ForkedLightningData = ForkedLightningData.new()\n\tvar swarm: SwarmData = SwarmData.new()\n\n\nconst _spell_scene_map: Dictionary = {\n\tSpellType.Name.BLIZZARD: preload(\"res://src/spells/spell_blizzard.tscn\"),\n\tSpellType.Name.CHAIN_LIGHTNING: preload(\"res://src/spells/spell_chain_lightning.tscn\"),\n\tSpellType.Name.FORKED_LIGHTNING: preload(\"res://src/spells/spell_forked_lightning.tscn\"),\n\tSpellType.Name.CARRION_SWARM: preload(\"res://src/spells/spell_swarm.tscn\"),\n}\n\n\nvar data: SpellData = SpellData.new()\n\nvar _spell_name: SpellType.Name\nvar _lifetime: float\nvar _source_height: float = 0.0\nvar _damage_event_handler: Callable = Callable()\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(spell_name: SpellType.Name, lifetime: float, parent: Node):\n\tparent.add_child(self)\n\t_spell_name = spell_name\n\t_lifetime = lifetime\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: cast.setDamageEvent() in JASS\nfunc set_damage_event(handler: Callable):\n\t_damage_event_handler = handler\n\n\nfunc point_cast_from_unit_on_point(caster: Unit, origin_unit: Unit, target_pos: Vector2, damage_ratio: float, crit_ratio: float):\n\tvar target: Unit = null\n\tvar origin_pos: Vector3 = origin_unit.get_position_wc3()\n\t_cast_generic(caster, origin_pos, target, target_pos, damage_ratio, crit_ratio)\n\n\nfunc point_cast_from_caster_on_point(caster: Unit, target_pos: Vector2, damage_ratio: float, crit_ratio: float):\n\tvar origin_pos: Vector3 = caster.get_position_wc3()\n\tvar target: Unit = null\n\t_cast_generic(caster, origin_pos, target, target_pos, damage_ratio, crit_ratio)\n\n\n# NOTE: cast.targetCastFromCaster() in JASS\nfunc target_cast_from_caster(caster: Unit, target: Unit, damage_ratio: float, crit_ratio: float):\n\tvar origin_pos: Vector3 = caster.get_position_wc3()\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\t_cast_generic(caster, origin_pos, target, target_pos, damage_ratio, crit_ratio)\n\n\n# NOTE: cast.targetCastFromPoint() in JASS\nfunc target_cast_from_point(caster: Unit, target: Unit, origin_pos_2d: Vector2, damage_ratio: float, crit_ratio: float):\n\tvar origin_pos: Vector3 = Vector3(origin_pos_2d.x, origin_pos_2d.y, 0)\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\t_cast_generic(caster, origin_pos, target, target_pos, damage_ratio, crit_ratio)\n\n\n# NOTE: point_cast_from_target_on_target() and\n# target_cast_from_caster() are basically the same in\n# current implementation. In original game, there's more\n# nuance but for practical purposes there's no point in\n# implementing this nuance.\n# NOTE: cast.pointCastFromCasterOnTarget() in JASS\nfunc point_cast_from_target_on_target(caster: Unit, target: Unit, damage_ratio: float, crit_ratio: float):\n\tvar origin_pos: Vector3 = target.get_position_wc3()\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\t_cast_generic(caster, origin_pos, target, target_pos, damage_ratio, crit_ratio)\n\n\n# NOTE: cast.setSourceHeight() in JASS\nfunc set_source_height(value: float):\n\t_source_height = value\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _cast_generic(caster: Unit, origin_pos: Vector3, target: Unit, target_pos: Vector2, damage_ratio: float, crit_ratio: float):\n\tvar scene: PackedScene = _spell_scene_map[_spell_name]\n\tvar instance: SpellDummy = scene.instantiate()\n\torigin_pos.z += _source_height\n\tinstance.set_position_wc3(origin_pos)\n\tinstance.init_spell(caster, target, _lifetime, data, _damage_event_handler, target_pos, damage_ratio, crit_ratio)\n\ttree_exited.connect(instance._on_cast_type_tree_exited)\n\tUtils.add_object_to_world(instance)\n"
  },
  {
    "path": "src/sprites/lightning_animation.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://cwy7ctjsapvwn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dyle0v7ow0gxp\" path=\"res://assets/effects/lightning_long.png\" id=\"1_55au2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pj7nq\"]\natlas = ExtResource(\"1_55au2\")\nregion = Rect2(0, 0, 128, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hdaqw\"]\natlas = ExtResource(\"1_55au2\")\nregion = Rect2(0, 32, 128, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_blrc7\"]\natlas = ExtResource(\"1_55au2\")\nregion = Rect2(0, 64, 128, 32)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_am0oy\"]\natlas = ExtResource(\"1_55au2\")\nregion = Rect2(0, 96, 128, 32)\n\n[sub_resource type=\"SpriteFrames\" id=\"SpriteFrames_6f1bs\"]\nanimations = [{\n\"frames\": [{\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_pj7nq\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_hdaqw\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_blrc7\")\n}, {\n\"duration\": 1.0,\n\"texture\": SubResource(\"AtlasTexture_am0oy\")\n}],\n\"loop\": true,\n\"name\": &\"default\",\n\"speed\": 15.0\n}]\n\n[node name=\"LightningAnimation\" type=\"AnimatedSprite2D\"]\nsprite_frames = SubResource(\"SpriteFrames_6f1bs\")\nautoplay = \"default\"\nframe_progress = 0.398624\n"
  },
  {
    "path": "src/sprites/pulsing_dot.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://wrlhhkubvcp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://yn18gvcjmrkp\" path=\"res://resources/misc/pulsing_dot.tres\" id=\"1\"]\n\n[node name=\"AnimatedSprite2D\" type=\"Sprite2D\"]\ntexture = ExtResource(\"1\")\n"
  },
  {
    "path": "src/tests/README.md",
    "content": "This folder contains test suites. You can run the tests by enabling a corresponding config value and launching the game.\n"
  },
  {
    "path": "src/tests/playtest_bot.gd",
    "content": "class_name PlaytestBot extends Node\n\n\n# Performs a rough playtest. Builds random sets of towers\n# with random items and lets them attack some waves.\n# Rebuilds new towers periodically.\n\n# Increase config/update_ticks_per_physics_tick to run the\n# playtest at faster speed.\n\nenum TowerSelectType {\n\tRANDOM,\n\tMANUAL,\n}\n\nconst TOWER_SELECT_TYPE: TowerSelectType = TowerSelectType.MANUAL\nconst RANDOM_TOWER_COUNT: int = 30\nconst MANUAL_TOWER_LIST: Array[int] = [391, 115, 120, 360, 135, 149, 162, 269, 186, 192, 198, 209, 286, 233, 266, 279, 304, 307, 391, 115, 120]\n\nconst ADD_RANDOM_ITEMS: bool = true\nconst TIME_PER_SET: float = 5 * 60\n# NOTE: (2,2) is the tip of the corner of buildable area\nconst POSITIONS_ORIGIN: Vector2 = Vector2(500, 200)\nconst POSITIONS_X_RANGE: Array = [-10, 10]\nconst POSITIONS_Y_RANGE: Array = [-20, 15]\n\nstatic var item_id_list: Array\nstatic var oil_id_list: Array\nstatic var built_tower_list: Array[Tower] = []\nstatic var all_tower_id_list: Array\nstatic var position_list: Array\n\n\nstatic func run(build_space: BuildSpace):\n\tall_tower_id_list = TowerProperties.get_tower_id_list()\n\t\n\tvar regular_type_string: String = ItemType.convert_to_string(ItemType.enm.REGULAR)\n\tPlaytestBot.item_id_list = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, regular_type_string)\n\n\tvar oil_type_string: String = ItemType.convert_to_string(ItemType.enm.OIL)\n\toil_id_list = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, oil_type_string)\n\n\tvar position_count: int\n\tmatch TOWER_SELECT_TYPE:\n\t\tTowerSelectType.RANDOM: position_count = RANDOM_TOWER_COUNT\n\t\tTowerSelectType.MANUAL: position_count = MANUAL_TOWER_LIST.size()\n\n\tposition_list = PlaytestBot._generate_position_list(build_space, position_count)\n\n\twhile true:\n\t\trun_cycle()\n\t\t\n\t\tawait Utils.create_manual_timer(TIME_PER_SET, build_space).timeout\n\n\nstatic func run_cycle():\n\tfor tower in built_tower_list:\n\t\ttower.remove_from_game()\n\tbuilt_tower_list.clear()\n\n#\tNOTE: empty item stash to prevent overflow during testing\n\tvar player: Player = PlayerManager.get_local_player()\n\tvar item_stash: ItemContainer = player.get_item_stash()\n\tvar item_list: Array[Item] = item_stash.get_item_list()\n\tfor item in item_list:\n\t\titem_stash.remove_item(item)\n\t\titem.queue_free()\n\n\tvar tower_id_list: Array\n\tmatch TOWER_SELECT_TYPE:\n\t\tTowerSelectType.RANDOM:\n\t\t\ttower_id_list = _generate_random_tower_list()\n\t\t\tMANUAL_TOWER_LIST.duplicate()\n\t\tTowerSelectType.MANUAL: tower_id_list = MANUAL_TOWER_LIST.duplicate()\n\n\tfor i in range(0, tower_id_list.size()):\n\t\tvar tower_id: int = tower_id_list[i]\n\t\tvar build_pos: Vector2 = position_list[i]\n\t\tvar tower: Tower = PlaytestBot._build_random_tower(tower_id, build_pos)\n\t\tbuilt_tower_list.append(tower)\n\n\nstatic func _generate_random_tower_list() -> Array[int]:\n\tvar result: Array[int] = []\n\n\tfor i in range(0, RANDOM_TOWER_COUNT):\n\t\tvar tower_id: int = all_tower_id_list.pick_random()\n\t\tresult.append(tower_id)\n\n\treturn result\n\n\nstatic func _build_random_tower(tower_id: int, unclamped_pos: Vector2) -> Tower:\n\tvar player: Player = PlayerManager.get_local_player()\n\t\n\tvar tower: Tower = Tower.make(tower_id, player)\n\tvar build_pos_2nd_floor: Vector2 = VectorUtils.snap_canvas_pos_to_buildable_pos(unclamped_pos)\n\tvar build_pos_1st_floor_canvas: Vector2 = build_pos_2nd_floor + Vector2(0, Constants.TILE_SIZE.y)\n\tvar build_pos: Vector2 = VectorUtils.canvas_to_wc3_2d(build_pos_1st_floor_canvas)\n\ttower.set_position_wc3_2d(build_pos)\n\tUtils.add_object_to_world(tower)\n\n\tif ADD_RANDOM_ITEMS:\n\t\t_add_random_items_to_tower(tower)\n\t\n\treturn tower\n\n\n# NOTE: need to sometimes leave empty space in\n# tower inventory to test some abilities which\n# require non-full inventory\nstatic func _add_random_items_to_tower(tower: Tower):\n\tvar player: Player = PlayerManager.get_local_player()\n\tvar free_slots: int = tower.count_free_slots()\n\tvar item_count: int = randi_range(0, free_slots)\n\n\tfor j in range(0, item_count):\n\t\tvar random_item_id: int = PlaytestBot.item_id_list.pick_random()\n\t\tvar random_item: Item = Item.create(player, random_item_id, Vector3.ZERO)\n\t\trandom_item.pickup(tower)\n\n\tvar oil_count: int = randi_range(0, 3)\n\tfor j in range(0, oil_count):\n\t\tvar random_oil_id: int = PlaytestBot.oil_id_list.pick_random()\n\t\tvar random_oil: Item = Item.create(player, random_oil_id, Vector3.ZERO)\n\t\trandom_oil.pickup(tower)\n\n\nstatic func _generate_position_list(build_space: BuildSpace, count: int) -> Array[Vector2]:\n\tvar result: Array[Vector2] = []\n\n\tvar origin: Vector2 = POSITIONS_ORIGIN\n\n\tvar offset_list: Array[Vector2] = [Vector2(0, 0), Vector2(-0.5, -0.5)]\n\t\n\tvar local_player: Player = PlayerManager.get_local_player()\n\n\tfor x in range(POSITIONS_X_RANGE[0], POSITIONS_X_RANGE[1]):\n\t\tfor y in range(POSITIONS_Y_RANGE[0], POSITIONS_Y_RANGE[1]):\n\t\t\tfor offset in offset_list:\n\t\t\t\tvar position: Vector2 = origin + Constants.TILE_SIZE * (Vector2(x, y) + offset)\n\t\t\t\tvar can_build: bool = build_space.can_build_at_pos(local_player, position)\n\n\t\t\t\tif can_build:\n\t\t\t\t\tresult.append(position)\n\t\n\tresult.sort_custom(func (a, b) -> bool:\n\t\tvar dist_a: float = a.distance_to(origin)\n\t\tvar dist_b: float = b.distance_to(origin)\n\n\t\treturn dist_a < dist_b\n\t\t)\n\t\n\tprint(\"Found %d positions. Reducing to %d closest positions.\" % [result.size(), count])\n\t\n\tif result.size() > count:\n\t\tresult.resize(count)\n\n\treturn result\n"
  },
  {
    "path": "src/tests/test_horadric_tool.gd",
    "content": "class_name TestHoradricTool extends Node\n\n\n# Enable by adding \"config/run_test_horadric_tool=true\" to\n# override.cfg\n\nstatic var _player: Player = null\n\n\nstatic func run(player: Player):\n\tTestHoradricTool._player = player\n\ttestget_item_list_for_autofill()\n\ttest_get_result_item_for_recipe()\n\tTestTool.print_totals()\n\n\nclass TestCaseget_item_list_for_autofill extends TestTool.TestCase_base:\n\tvar recipe: HoradricCube.Recipe\n\tvar ingredient_list: Array[int] = []\n\tvar expected_result_list: Array[int] = []\n\n\tfunc _init(recipe_arg: HoradricCube.Recipe, ingredient_list_arg: Array[int], expected_result_list_arg: Array[int], description_arg: String):\n\t\trecipe = recipe_arg\n\t\tingredient_list = ingredient_list_arg\n\t\texpected_result_list = expected_result_list_arg\n\t\tdescription = description_arg\n\n\nstatic func testget_item_list_for_autofill():\n\tvar test_case_list: Array[TestCaseget_item_list_for_autofill] = [\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REBREW, [1001, 1001], [1001, 1001], \"2 oils.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REBREW, [1005, 1005, 1001, 1011, 1001, 1, 2, 3], [1001, 1001], \"2 oils mixed with items and other oils.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.NONE, [1, 1001], [], \"1 oil and 1 item.\"),\n\t\t\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.DISTILL, [1003, 1006, 1009, 1015], [1003, 1006, 1009, 1015], \"4 oils.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.DISTILL, [1003, 1006, 2004, 2004], [1003, 1006, 2004, 2004], \"2 oils and 2 consumables. Mixing should be allowed.\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REASSEMBLE, [3, 4, 5], [3, 4, 5], \"3 items.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REASSEMBLE, [3, 4, 5, 6, 7], [5, 6, 7], \"5 items. Lowest level should be picked.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REASSEMBLE, [3, 4, 5, 36, 37, 38], [36, 37, 38], \"3 uncommon items and 3 common items. Lowest rarity should be picked.\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PERFECT, [64, 65, 66, 67, 68], [64, 65, 66, 67, 68], \"5 items.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PERFECT, [1001, 1002, 1003, 10, 64, 65, 66, 198, 67, 68], [64, 65, 66, 67, 68], \"5 items mixed with other items and oils.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PERFECT, [64, 65, 66, 67], [], \"4 items. Not enough for Perfect\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PERFECT, [64, 65, 66, 67, 74], [], \"5 items but item74 is different rarity.\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REASSEMBLE, [], [], \"0 items for reassemble\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PERFECT, [], [], \"0 items for perfect\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.DISTILL, [], [], \"0 items for distill\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.REBREW, [], [], \"0 items for rebrew\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.DISTILL, [2008, 2008, 2008, 2008, 2008], [], \"4 unique oils for DISTILL. Invalid because can't raise rarity further.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PERFECT, [1, 1, 1, 1, 1], [], \"5 permanent items for PERFECT. Invalid because can't raise rarity further.\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.LIQUEFY, [8, 8], [8, 8], \"2 rare items for LIQUEFY\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.LIQUEFY, [3, 3], [], \"2 uncommon items for LIQUEFY. Invalid because LIEQUEFY needs to reduce rarity by 2.\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PRECIPITATE, [1001, 1001, 1001, 1001, 1001, 1001], [1001, 1001, 1001, 1001, 1001, 1001], \"PRECIPITATE 6 common oils.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.PRECIPITATE, [1003, 1003, 1003, 1003, 1003, 1003], [], \"PRECIPITATE 6 rare oils. Invalid because rarity too high.\"),\n\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.IMBUE, [2, 1001, 1001, 1001, 1001], [2, 1001, 1001, 1001, 1001], \"IMBUE 1 common item and 4 oils.\"),\n\t\tTestCaseget_item_list_for_autofill.new(HoradricCube.Recipe.IMBUE, [1, 1022, 1022, 1022, 1022], [], \"IMBUE 1 unique item and 4 oils. Invalid because rarity too high\"),\n\t]\n\n\tvar test_case_function: Callable = func(test_case: TestCaseget_item_list_for_autofill):\n\t\tvar recipe: HoradricCube.Recipe = test_case.recipe\n\t\tvar ingredient_list: Array[int] = test_case.ingredient_list\n\t\tvar ingredient_item_list: Array[Item] = Utils.item_id_list_to_item_list(ingredient_list, _player)\n\t\tvar expected_result_list: Array[int] = test_case.expected_result_list\n\t\tvar actual_result_item_list: Array[Item] = HoradricCube.get_item_list_for_autofill(recipe, ingredient_item_list)\n\t\tvar actual_result_list: Array[int] = Utils.item_list_to_item_id_list(actual_result_item_list)\n\n\t\tTestTool.compare(actual_result_list, expected_result_list, \"result list\")\n\n\tTestTool.run(\"get_item_list_for_autofill()\", test_case_list, test_case_function)\n\n\nclass TestCase_get_result_item_for_recipe extends TestTool.TestCase_base:\n\tvar recipe: HoradricCube.Recipe\n\tvar ingredient_list: Array[int] = []\n\tvar expected_result_rarity: Rarity.enm\n\tvar expected_result_item_type: Array[ItemType.enm] = []\n\tvar expected_result_count: int\n\n\tfunc _init(recipe_arg: HoradricCube.Recipe, ingredient_list_arg: Array[int], expected_result_rarity_arg: Rarity.enm, expected_result_item_type_arg: Array[ItemType.enm], expected_result_count_arg: int, description_arg: String):\n\t\trecipe = recipe_arg\n\t\tingredient_list = ingredient_list_arg\n\t\texpected_result_rarity = expected_result_rarity_arg\n\t\texpected_result_item_type = expected_result_item_type_arg\n\t\texpected_result_count = expected_result_count_arg\n\t\tdescription = description_arg\n\n\nstatic func test_get_result_item_for_recipe():\n\tvar test_case_list: Array[TestCase_get_result_item_for_recipe] = [\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.REBREW, [1001, 1001], Rarity.enm.COMMON, [ItemType.enm.OIL, ItemType.enm.CONSUMABLE], 1, \"rebrew 2 common oils\"),\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.DISTILL, [1001, 1001, 1001, 1001], Rarity.enm.UNCOMMON, [ItemType.enm.OIL, ItemType.enm.CONSUMABLE], 1, \"rebrew 4 common oils into uncommon oil\"),\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.REASSEMBLE, [64, 64, 64], Rarity.enm.COMMON, [ItemType.enm.REGULAR], 1, \"reassemble 3 common permanent items\"),\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.PERFECT, [64, 64, 64, 64, 64], Rarity.enm.UNCOMMON, [ItemType.enm.REGULAR], 1, \"perfect 5 common permanent items into uncommon item\"),\n\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.LIQUEFY, [8, 8], Rarity.enm.COMMON, [ItemType.enm.OIL, ItemType.enm.CONSUMABLE], 3, \"LIQUEFY 2 rare items into 3 common oils\"),\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.LIQUEFY, [1, 1], Rarity.enm.UNCOMMON, [ItemType.enm.OIL, ItemType.enm.CONSUMABLE], 3, \"LIQUEFY 2 unique items into 3 uncommon oils\"),\n\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.PRECIPITATE, [1001, 1001], Rarity.enm.RARE, [ItemType.enm.REGULAR], 1, \"PRECIPITATE 6 common oils\"),\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.PRECIPITATE, [1002, 1002], Rarity.enm.UNIQUE, [ItemType.enm.REGULAR], 1, \"PRECIPITATE 6 uncommon oils\"),\n\t\t\n\t\tTestCase_get_result_item_for_recipe.new(HoradricCube.Recipe.IMBUE, [2, 1001, 1001, 1001, 1001], Rarity.enm.UNCOMMON, [ItemType.enm.REGULAR], 1, \"IMBUE 1 common item and 4 common oils into 1 uncommon item\"),\n\n\t]\n\n\tvar test_case_function: Callable = func(test_case: TestCase_get_result_item_for_recipe):\n\t\tvar recipe: HoradricCube.Recipe = test_case.recipe\n\t\tvar ingredient_id_list: Array[int] = test_case.ingredient_list\n\t\tvar ingredient_item_list: Array[Item] = Utils.item_id_list_to_item_list(ingredient_id_list, _player)\n\t\tvar player: Player = null\n\t\tvar result_item_list: Array[int] = HoradricCube.get_result_item_for_recipe(player, recipe, ingredient_item_list)\n\n\t\tvar expected_result_count: int = test_case.expected_result_count\n\t\tvar actual_result_count: int = result_item_list.size()\n\t\tTestTool.compare(actual_result_count, expected_result_count, \"result count\")\n\n\t\tvar expected_result_rarity: Rarity.enm = test_case.expected_result_rarity\n\t\tfor result_item in result_item_list:\n\t\t\tvar actual_result_rarity: Rarity.enm = ItemProperties.get_rarity(result_item)\n\t\t\tTestTool.compare(actual_result_rarity, expected_result_rarity, \"result rarity\")\n\n\t\tvar expected_result_item_type: Array[ItemType.enm] = test_case.expected_result_item_type\n\t\tfor result_item in result_item_list:\n\t\t\tvar actual_result_item_type: ItemType.enm = ItemProperties.get_type(result_item)\n\t\t\tTestTool.verify(expected_result_item_type.has(actual_result_item_type), \"result item type\")\n\n\tTestTool.run(\"get_result_item_for_recipe()\", test_case_list, test_case_function)\n"
  },
  {
    "path": "src/tests/test_item_drop_chances.gd",
    "content": "class_name TestItemDropChances extends Node\n\n\n# Simulates multiple games and collects average counts of\n# item drops.\n\n\nconst SIMULATION_COUNT: int = 50\nconst FIRST_WAVE: int = 80\nconst LAST_WAVE: int = 200\n\n# NOTE: these values are for the carry tower during endgame\nconst TOWER_ITEM_CHANCE: float = 2.5\nconst CREEP_ITEM_CHANCE: float = 1.5\nconst TOWER_ITEM_QUALITY: float = 2.5\nconst CREEP_ITEM_QUALITY: float = 1.5\n\n# NOTE: these values are for \"normal\" creeps\nconst CREEPS_PER_WAVE: int = 10\nconst ITEM_ROLLS_PER_CREEP: int = 2\n\n# NOTE: stats for these items will be printed separatately\n# from the main list\nconst MARKED_ITEM_LIST: Array = [9, 140, 254]\n\n\nstatic func run():\n\tvar item_count_map: Dictionary = {}\n\n\tfor i in range(0, SIMULATION_COUNT):\n\t\tsimulate_one_game(item_count_map)\n\n\tvar rarity_count_map: Dictionary = {}\n\tfor item_id in item_count_map.keys():\n\t\tvar rarity: Rarity.enm = ItemProperties.get_rarity(item_id)\n\t\tvar item_count: int = item_count_map[item_id]\n\n\t\tif !rarity_count_map.has(rarity):\n\t\t\trarity_count_map[rarity] = 0\n\n\t\trarity_count_map[rarity] += item_count\n\n\tvar item_id_list: Array = item_count_map.keys()\n\titem_id_list.sort()\n\n\tprint(\" \\n\")\n\tprint(\"----------\")\n\tprint(\"Results of testing item drops\")\n\tprint(\" \\n\")\n\tprint(\"TOWER_ITEM_CHANCE = %s\" % Utils.format_percent(TOWER_ITEM_CHANCE, 0))\n\tprint(\"CREEP_ITEM_CHANCE = %s\" % Utils.format_percent(CREEP_ITEM_CHANCE, 0))\n\tprint(\"TOWER_ITEM_QUALITY = %s\" % Utils.format_percent(TOWER_ITEM_QUALITY, 0))\n\tprint(\"CREEP_ITEM_QUALITY = %s\" % Utils.format_percent(CREEP_ITEM_QUALITY, 0))\n\tprint(\" \\n\")\n\tprint(\" \\n\")\n\tprint(\"All items\")\n\tprint(\" \\n\")\n\n\tfor item_id in item_id_list:\n\t\tvar item_name: String = ItemProperties.get_display_name(item_id)\n\t\tvar item_count: float = item_count_map[item_id] * 1.0 / SIMULATION_COUNT\n\n\t\tprint(\"%s: %s\" % [item_name, item_count])\n\n\tprint(\" \\n\")\n\tprint(\"----------\")\n\tprint(\"Rarity stats\")\n\tprint(\" \\n\")\n\t\n\tfor rarity in Rarity.get_list():\n\t\tvar rarity_string: String = Rarity.convert_to_string(rarity)\n\t\tvar count: float = rarity_count_map.get(rarity, 0) * 1.0 / SIMULATION_COUNT\n\n\t\tprint(\"%s: %s\" % [rarity_string, count])\n\n\tprint(\" \\n\")\n\tprint(\"----------\")\n\tprint(\"Marked items\")\n\tprint(\" \\n\")\n\n\tfor item_id in MARKED_ITEM_LIST:\n\t\tvar item_name: String = ItemProperties.get_display_name(item_id)\n\t\tvar item_count: float = item_count_map.get(item_id, 0) * 1.0 / SIMULATION_COUNT\n\t\t\n\t\tprint(\"%s: %s\" % [item_name, item_count])\n\n\tprint(\" \\n\")\n\tprint(\" \\n\")\n\n\nstatic func simulate_one_game(item_count_map: Dictionary):\n\tvar item_chance: float = Constants.BASE_ITEM_DROP_CHANCE * TOWER_ITEM_CHANCE * CREEP_ITEM_CHANCE\n\tvar quality_multiplier: float = TOWER_ITEM_QUALITY * CREEP_ITEM_QUALITY\n\n\tfor wave in range(FIRST_WAVE, LAST_WAVE):\n\t\tvar creep_level: int = wave\n\n\t\tfor creep in range(0, CREEPS_PER_WAVE):\n\t\t\tfor i in range(0, ITEM_ROLLS_PER_CREEP):\n\t\t\t\tvar item_dropped: bool = Utils.rand_chance(Globals.synced_rng, item_chance)\n\t\t\t\t\n\t\t\t\tif !item_dropped:\n\t\t\t\t\tcontinue\n\n\t\t\t\tvar random_item: int = ItemDropCalc._calculate_item_drop(creep_level, quality_multiplier)\n\n\t\t\t\tif random_item == 0:\n\t\t\t\t\tcontinue\n\n\t\t\t\tif !item_count_map.has(random_item):\n\t\t\t\t\titem_count_map[random_item] = 0\n\t\t\t\t\n\t\t\t\titem_count_map[random_item] += 1\n"
  },
  {
    "path": "src/tests/test_items_tool.gd",
    "content": "class_name TestItemsTool extends Node\n\n\n# Tests items by creating all items.\n\n\nstatic func run(gamescene: Node, player: Player):\n\tvar scene_tree: SceneTree = gamescene.get_tree()\n\tvar item_id_list: Array = ItemProperties.get_item_id_list()\n\n\tvar i: int = 0\n\n\tvar tower: Tower = Tower.make(1, player)\n\ttower.set_position_wc3_2d(Vector2(123, 123))\n\tUtils.add_object_to_world(tower)\n\n\tfor item_id in item_id_list:\n\t\tvar item_name: String = ItemProperties.get_display_name(item_id)\n\t\tprint(\"(%d/%d) Testing item %d %s\" % [i + 1, item_id_list.size(), item_id, item_name])\n\n\t\tvar item: Item = Item.make(item_id, player)\n\t\tvar item_drop: ItemDrop = ItemDrop.make(item, Vector3.ZERO)\n\t\tUtils.add_object_to_world(item_drop)\n\t\titem.pickup(tower)\n\t\tawait scene_tree.create_timer(0.01).timeout\n\t\titem.drop()\n\t\tawait scene_tree.create_timer(0.01).timeout\n\t\titem.queue_free()\n\t\tawait scene_tree.create_timer(0.01).timeout\n\n\t\ti += 1\n"
  },
  {
    "path": "src/tests/test_tool.gd",
    "content": "class_name TestTool extends Node\n\n\n# Tool for implementing tests and test cases. Use by calling TestTool.run().\n\nstatic var _errors_for_current_test_case: Array[String]\nstatic var _passed_count: int = 0\nstatic var _failed_count: int = 0\n\n\nclass TestCase_base:\n\tvar description: String\n\n\n# NOTE: test_case_function accepts arg of TestCase and\n# returns TestCaseResult.\nstatic func run(test_name: String, test_case_list: Array, test_case_function: Callable):\n\tprint(\"--- Start testing of %s ---\" % test_name)\n\n\tfor i in test_case_list.size():\n\t\tvar test_case: TestCase_base = test_case_list[i]\n\t\tvar test_case_description: String = test_case.description\n\n#\t\tRun the test case\n\t\ttest_case_function.call(test_case)\n\n\t\tvar passed: bool = TestTool._errors_for_current_test_case.is_empty()\n\n# \t\tPrint PASS/FAIL message\n\t\tvar status_string: String\n\t\tif passed:\n\t\t\tstatus_string = \"PASS\"\n\t\telse:\n\t\t\tstatus_string = \"FAIL\"\n\n\t\tprint(\"%s\\t : %s - %s\" % [status_string, test_name, test_case_description])\n\n#\t\tPrint details about why this test case failed\n\t\tif !passed:\n\t\t\tfor error in TestTool._errors_for_current_test_case:\n\t\t\t\tprint(\"%s\" % error)\n\n\t\t\tTestTool._errors_for_current_test_case.clear()\n\t\t\n\t\tif passed:\n\t\t\tTestTool._passed_count += 1\n\t\telse:\n\t\t\tTestTool._failed_count += 1\n\n\tprint(\"--- Finished testing of %s ---\" % test_name)\n\n\nstatic func compare(actual, expected, description: String = \"\"):\n\tif actual != expected:\n\t\tvar fail_message: String = \"Compared values are not the same\\n\\tActual: %s\\n\\tExpected: %s.\" % [str(actual), str(expected)]\n\t\tif !description.is_empty():\n\t\t\tfail_message += \"\\n\\tDescription: \\\"%s\\\"\" % description\n\n\t\tTestTool._errors_for_current_test_case.append(fail_message)\n\n\nstatic func verify(condition: bool, message: String):\n\tif !condition:\n\t\tvar fail_message: String = \"Verify failed: %s\" % [message]\n\t\tTestTool._errors_for_current_test_case.append(fail_message)\n\n\nstatic func print_totals():\n\tprint(\"Totals: %d passed, %d failed\" % [TestTool._passed_count, TestTool._failed_count])\n"
  },
  {
    "path": "src/tests/test_tower_sprite_size.gd",
    "content": "class_name TestTowerSpriteSize extends Node\n\n\n# Checks if any tower sprite has abnormal size relative to\n# other towers of same cost.\n\n\nconst ABNORMAL_HEIGHT_THRESHOLD: float = 0.25\nconst COST_INTERVAL: int = 500\n\n\nstatic var height_map: Dictionary = {}\n\n\nstatic func run():\n\theight_map = generate_height_map()\n\t\n\tvar cost_list: Array = range(0, 5000, COST_INTERVAL)\n\n\tfor cost in cost_list:\n\t\tvar average_height: float = get_average_height_for_towers_of_cost(cost)\n\n\t\tprint(\" \\n \\n--------------------------------\")\n\t\tprint(\"COST = %d, average height = %d\" % [cost, average_height])\n\t\t\n\t\tvar tower_list: Array = get_tower_list_for_cost(cost)\n\n\t\tfor tower in tower_list:\n\t\t\tvar tower_name: String = TowerProperties.get_display_name(tower)\n\t\t\tvar tier: int = TowerProperties.get_tier(tower)\n\t\t\tvar element: Element.enm = TowerProperties.get_element(tower)\n\t\t\tvar element_string: String = Element.get_display_string(element)\n\t\t\tvar height: float = height_map[tower]\n\t\t\tvar diff_from_average: float = (height - average_height) / average_height\n\t\t\tvar height_is_abnormally_short: bool = diff_from_average < 0 && abs(diff_from_average) > ABNORMAL_HEIGHT_THRESHOLD\n\t\t\tvar height_is_abnormally_tall: bool = diff_from_average > 0 && abs(diff_from_average) > ABNORMAL_HEIGHT_THRESHOLD\n\n\t\t\tif height_is_abnormally_short:\n\t\t\t\tprint(\"Tower sprite for %s (tier %d, %s) is too short. Height of tower = %d.\" % [tower_name, tier, element_string, height])\n\t\t\telif height_is_abnormally_tall:\n\t\t\t\tprint(\"Tower sprite for %s (tier %d, %s) is too tall. Height of tower = %d.\" % [tower_name, tier, element_string, height])\n\n\nstatic func generate_height_map() -> Dictionary:\n\tvar result: Dictionary = {}\n\tvar tower_list: Array = TowerProperties.get_tower_id_list()\n\n\tfor tower in tower_list:\n\t\tvar tower_sprite: Sprite2D = TowerSprites.get_sprite(tower)\n\t\tvar sprite_dimensions: Vector2 = Utils.get_sprite_dimensions(tower_sprite)\n\t\tvar height: float = sprite_dimensions.y\n\n\t\tresult[tower] = height\n\t\n\treturn result\n\n\nstatic func get_tower_list_for_cost(cost: int) -> Array:\n\tvar all_towers: Array = TowerProperties.get_tower_id_list()\n\t\n\tvar towers_for_cost: Array = all_towers.filter(\n\t\tfunc(tower_id: int) -> bool:\n\t\t\tvar tower_cost: int = TowerProperties.get_cost(tower_id)\n\t\t\tvar cost_match: bool = cost <= tower_cost && tower_cost < cost + COST_INTERVAL\n\n\t\t\treturn cost_match\n\t)\n\t\n\treturn towers_for_cost\n\n\nstatic func get_average_height_for_towers_of_cost(cost: int) -> float:\n\tvar tower_list: Array = get_tower_list_for_cost(cost)\n\t\n\tif tower_list.is_empty():\n\t\treturn 0\n\t\n\tvar height_sum: float = 0\n\t\t\n\tfor tower in tower_list:\n\t\tvar height: float = height_map[tower]\n\t\theight_sum += height\n\t\n\tvar tower_count: int = tower_list.size()\n\tvar average_height: float = height_sum / tower_count\n\t\n\treturn average_height\n"
  },
  {
    "path": "src/tests/test_towers_tool.gd",
    "content": "class_name TestTowersTool extends Node\n\n\n# Tests towers by building and destroying all towers. This\n# can detect basic script errors which would otherwise\n# require opening each tower script in editor.\n\n\nstatic func run(gamescene: Node, player: Player):\n\tvar scene_tree: SceneTree = gamescene.get_tree()\n\tvar tower_id_list: Array = TowerProperties.get_tower_id_list()\n\n\tvar i: int = 0\n\n\tvar tower_preview: TowerPreview = gamescene.get_node(\"World/TowerPreview\")\n\n\tfor tower_id in tower_id_list:\n\t\tvar tower_name: String = TowerProperties.get_display_name(tower_id)\n\t\tprint(\"(%d/%d) Testing tower %d %s\" % [i + 1, tower_id_list.size(), tower_id, tower_name])\n\n#\t\tTest tower preview\n\t\ttower_preview.set_tower(tower_id)\n\t\tawait scene_tree.create_timer(0.01).timeout\n\n#\t\tTest building tower\n\t\tvar tower: Tower = Tower.make(tower_id, player)\n\t\ttower.set_position_wc3_2d(Vector2(123, 123))\n\t\tUtils.add_object_to_world(tower)\n\t\tawait scene_tree.create_timer(0.01).timeout\n\t\ttower.remove_from_game()\n\t\tawait scene_tree.create_timer(0.01).timeout\n\n\t\ti += 1\n"
  },
  {
    "path": "src/towers/README.md",
    "content": "tower_behaviors - contains scripts which define behaviors for individual towers. These scripts are attached to the main tower scene during runtime.\n\ntower_sprites - contains sprites for each individual tower. These sprites are attached to the main tower scene during runtime.\n"
  },
  {
    "path": "src/towers/autocast.gd",
    "content": "class_name Autocast\nextends Node\n\n# Autocast is attached to a unit and triggers an ability.\n# Can be attached using Tower.add_autocast(),\n# Buff.add_autocast() or Item.set_autocast().\n#\n# Note that autocast doesn't implement the gameplay effects\n# of the ability like dealing damage. That needs to be\n# implemented in the autocast handler. The only gameplay\n# effect that some autocasts do is applying buffs on units.\n#\n# Autocast type determines the way that the autocast\n# behaves. See below for descriptions of autocast types.\n#\n# AC_TYPE_ALWAYS_BUFF - applies a buff on targets in range\n# that don't already have the buff_type. Note that if a\n# handler is specified, then it will be called and buff\n# should be applied by the handler.\n#\n# AC_TYPE_ALWAYS_IMMEDIATE - calls the defined handler.\n# Ability effects should be implemented by the handler.\n#\n# AC_TYPE_OFFENSIVE_BUFF - same as AC_TYPE_ALWAYS_BUFF, but\n# is active only while tower is attacking.\n#\n# AC_TYPE_OFFENSIVE_UNIT - calls handler and passes current\n# attack target of caster via the event argument.\n#\n# AC_TYPE_OFFENSIVE_IMMEDIATE - same as\n# AC_TYPE_ALWAYS_IMMEDIATE but is active only while tower is\n# active.\n#\n# AC_TYPE_NOAC_IMMEDIATE - same as AC_TYPE_ALWAYS_IMMEDIATE\n# but is always in manual mode.\n#\n# AC_TYPE_NOAC_CREEP - same as AC_TYPE_OFFENSIVE_UNIT but is\n# always in manual mode.\n# \n# AC_TYPE_NOAC_TOWER - same as AC_TYPE_NOAC_CREEP but\n# accepts only tower targets.\n#\n# AC_TYPE_NOAC_PLAYER_TOWER - same as AC_TYPE_NOAC_TOWER but\n# accepts only player tower targets.\n# \n# See _types_that_can_use_auto_mode list for information\n# about which autocast types can use auto mode. Types not in\n# the list are always in manual mode.\n\n\nenum Type {\n\tAC_TYPE_ALWAYS_BUFF,\n\tAC_TYPE_ALWAYS_IMMEDIATE,\n\tAC_TYPE_OFFENSIVE_BUFF,\n\tAC_TYPE_OFFENSIVE_UNIT,\n\tAC_TYPE_OFFENSIVE_IMMEDIATE,\n\tAC_TYPE_OFFENSIVE_POINT,\n\tAC_TYPE_NOAC_IMMEDIATE,\n\tAC_TYPE_NOAC_CREEP,\n\tAC_TYPE_NOAC_TOWER,\n\tAC_TYPE_NOAC_PLAYER_TOWER,\n\tAC_TYPE_NOAC_POINT,\n}\n\n\nconst _types_that_can_use_auto_mode: Array[Autocast.Type] = [\n\tAutocast.Type.AC_TYPE_ALWAYS_BUFF,\n\tAutocast.Type.AC_TYPE_ALWAYS_IMMEDIATE,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_BUFF,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_UNIT,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_IMMEDIATE,\n]\nconst _immediate_type_list: Array[Autocast.Type] = [\n\tAutocast.Type.AC_TYPE_ALWAYS_IMMEDIATE,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_IMMEDIATE,\n\tAutocast.Type.AC_TYPE_NOAC_IMMEDIATE,\n]\nconst _buff_type_list: Array[Autocast.Type] = [\n\tAutocast.Type.AC_TYPE_ALWAYS_BUFF,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_BUFF,\n]\nconst _offensive_type_list: Array[Autocast.Type] = [\n\tAutocast.Type.AC_TYPE_OFFENSIVE_BUFF,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_UNIT,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_IMMEDIATE,\n\tAutocast.Type.AC_TYPE_OFFENSIVE_POINT,\n]\nconst _unit_type_list: Array[Autocast.Type] = [\n\tAutocast.Type.AC_TYPE_OFFENSIVE_UNIT,\n]\nconst _point_type_list: Array[Autocast.Type] = [\n\tAutocast.Type.AC_TYPE_OFFENSIVE_POINT,\n\tAutocast.Type.AC_TYPE_NOAC_POINT,\n]\n\n# NOTE: buff_target_type and buff_type are\n# only relevant to \"_BUFF\" autocast types. For other\n# autocast types leave these values blank.\n\nvar _autocast_id: int = -1\nvar _autocast_type: Autocast.Type = Type.AC_TYPE_OFFENSIVE_UNIT\nvar _buff_type: BuffType = null\nvar _buff_target_type: TargetType = null\nvar _handler: Callable = Callable()\nvar _target_pos: Vector2 = Vector2.ZERO\nvar _target_type: TargetType = null\nvar _caster: Unit = null\nvar _is_item_autocast: bool = false\nvar _item_owner: Item = null\n\n# Tracks how much time is left before ability can be used.\n@export var _cooldown_timer: ManualTimer\n# While auto mode is enabled, this timer periodically\n# triggers an attempt to cast ability if all requirements\n# are met. While auto mode is disabled, this timer is\n# paused.\n@export var _auto_timer: ManualTimer\n\nstatic var _uid_max: int = 1\nvar _uid: int = 0\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_cooldown_timer.wait_time = get_cooldown()\n\t_cooldown_timer.one_shot = true\n\n\t_uid = _uid_max\n\tAutocast._uid_max += 1\n\n\tGroupManager.add(\"autocasts\", self, get_uid())\n\n\tif !can_use_auto_mode():\n\t\t_auto_timer.set_paused(true)\n\n\t_check_buff_target_type()\n\n\t_target_type = Autocast.calculate_target_type(_autocast_type, _buff_target_type)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_id() -> int:\n\treturn _autocast_id\n\n\nfunc get_name_english() -> String:\n\tvar name_english: String = AutocastProperties.get_name_english(_autocast_id)\n\n\treturn name_english\n\n\nfunc get_autocast_name() -> String:\n\tvar autocast_name: String = AutocastProperties.get_autocast_name(_autocast_id)\n\n\treturn autocast_name\n\n\nfunc get_description_long() -> String:\n\tvar description_long: String = AutocastProperties.get_description_long(_autocast_id)\n\n\treturn description_long\n\n\nfunc get_icon_path() -> String:\n\tvar icon_path: String = AutocastProperties.get_icon_path(_autocast_id)\n\n\treturn icon_path\n\n\nfunc get_target_self() -> bool:\n\tvar target_self: bool = AutocastProperties.get_target_self(_autocast_id)\n\n\treturn target_self\n\n\nfunc get_cast_range() -> float:\n\tvar cast_range: float = AutocastProperties.get_cast_range(_autocast_id)\n\n\treturn cast_range\n\n\nfunc get_auto_range() -> float:\n\tvar auto_range: float = AutocastProperties.get_auto_range(_autocast_id)\n\n\treturn auto_range\n\n\nfunc get_uid() -> int:\n\treturn _uid\n\n\nfunc toggle_auto_mode():\n\tvar new_paused_value: bool = !_auto_timer.is_paused()\n\t_auto_timer.set_paused(new_paused_value)\n\n\nfunc auto_mode_is_enabled() -> bool:\n\tvar is_enabled: bool = !_auto_timer.is_paused()\n\n\treturn is_enabled\n\n\nfunc do_cast_at_pos(target_pos: Vector2):\n\t_target_pos = target_pos\n\tvar target: Unit = null\n\tdo_cast(target)\n\n\n# NOTE: target arg may be null if autocast is immediate\n# NOTE: this function doesn't check conditions like \"caster\n# has enough mana\", \"not on cooldown\". This has to be done\n# by the user of this function before calling the do_cast().\n# Use Autocast.can_cast() for checking.\nfunc do_cast(target: Unit):\n\tCombatLog.log_autocast(_caster, target, self)\n\n\t_cooldown_timer.start()\n\t\n\tif !_handler.is_null():\n\t\tvar autocast_event: Event = _make_autocast_event(target)\n\t\t_handler.call(autocast_event)\n\telif _buff_type != null:\n\t\t_buff_type.apply(_caster, target, _caster.get_level())\n\telse:\n\t\tpush_error(\"Incorrect autocast state, _handler = %s, _buff_type= %s\" % [_handler, _buff_type])\n\n\t\treturn\n\n#\tNOTE: the ordering of calls is important here. Must\n#\tsubtract mana AFTER calling the autocast handler\n#\tfunction. This is because autocast handlers need to\n#\tcheck mana value before it is spent.\n\tvar mana_cost: int = get_mana_cost()\n\t_caster.subtract_mana(mana_cost, false)\n\n\tvar spell_casted_event: Event = _make_autocast_event(target)\n\t_caster.spell_casted.emit(spell_casted_event)\n\n\tif target != null:\n\t\tvar spell_targeted_event: Event = _make_autocast_event(_caster)\n\t\ttarget.spell_targeted.emit(spell_targeted_event)\n\n\tvar caster_art: String = AutocastProperties.get_caster_art(_autocast_id)\n\tif !caster_art.is_empty():\n\t\tEffect.create_simple_at_unit(caster_art, _caster)\n\n\tvar target_art: String = AutocastProperties.get_target_art(_autocast_id)\n\tif !target_art.is_empty() && target != null:\n\t\tEffect.create_simple_at_unit(target_art, target)\n\n\nfunc check_target_for_unit_autocast(target: Unit) -> bool:\n\tif target == null:\n\t\treturn false\n\n\tvar target_is_in_range: bool = _get_target_is_in_range(target)\n\tvar target_type_is_valid = _target_type.match(target)\n\tvar target_is_immune: bool = target.is_immune()\n\tvar target_is_self: bool = target == _caster\n\tvar target_self: bool = get_target_self()\n\tvar targetting_self_when_forbidden: bool = !target_self && target_is_self\n\tvar target_is_ok: bool = target_is_in_range && target_type_is_valid && !target_is_immune && !targetting_self_when_forbidden\n\n\treturn target_is_ok\n\n\nfunc target_pos_is_in_range(target_pos: Vector2) -> bool:\n\tvar in_range: float = VectorUtils.in_range(_caster.get_position_wc3_2d(), target_pos, get_cast_range())\n\n\treturn in_range\n\n\nfunc can_cast() -> bool:\n\tif _caster == null:\n\t\treturn false\n\n\tvar on_cooldown: bool = _cooldown_timer.get_time_left() > 0\n\tvar mana_cost: int = get_mana_cost()\n\tvar enough_mana: bool = _caster.get_mana() >= mana_cost\n\tvar silenced: bool = _caster.is_silenced()\n\tvar stunned: bool = _caster.is_stunned()\n\tvar result: bool = !on_cooldown && enough_mana && !silenced && !stunned\n\n\treturn result\n\n\n# Some autocast types are always manual\nfunc can_use_auto_mode() -> bool:\n\tvar can_use: bool = _types_that_can_use_auto_mode.has(_autocast_type)\n\n\treturn can_use\n\n\n# Some autocast types are always manual\nstatic func can_use_auto_mode_for_id(autocast_id: int) -> bool:\n\tvar autocast_type: Autocast.Type = AutocastProperties.get_autocast_type(autocast_id)\n\tvar can_use: bool = _types_that_can_use_auto_mode.has(autocast_type)\n\n\treturn can_use\n\n\nfunc add_cast_error_message():\n\tvar cast_error: String = _get_cast_error()\n\n\tif !cast_error.is_empty():\n\t\tvar player: Player = _caster.get_player()\n\t\tUtils.add_ui_error(player, cast_error)\n\n\nfunc type_is_immediate() -> bool:\n\treturn _immediate_type_list.has(_autocast_type)\n\n\nfunc type_is_point() -> bool:\n\treturn _point_type_list.has(_autocast_type)\n\n\nfunc type_is_buff() -> bool:\n\treturn _buff_type_list.has(_autocast_type)\n\n\nfunc type_is_offensive() -> bool:\n\treturn _offensive_type_list.has(_autocast_type)\n\n\nfunc type_is_unit() -> bool:\n\treturn _unit_type_list.has(_autocast_type)\n\n\n# NOTE: this is used if this autocast is \"owned\" by an item\n# instead of a tower.\nfunc set_item_owner(item: Item):\n\t_item_owner = item\n\t_is_item_autocast = true\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _check_buff_target_type():\n\tvar ac_type_is_buff: bool = type_is_buff()\n\n\tif ac_type_is_buff && _buff_target_type == null:\n\t\tpush_error(\"Autocast %s has autocast type buff but doesn't have buff_target_type defined. You should define a non-null buff_target_type.\" % get_name_english())\n\telif !ac_type_is_buff && _buff_target_type != null:\n\t\tpush_error(\"Autocast %s doesn't have autocast type buff but has non-null buff_target_type. You should change buff_target_type to null.\" % get_name_english())\n\n\nfunc _make_autocast_event(target: Unit) -> Event:\n\tvar event: Event = Event.new(target)\n\tevent._autocast = self\n\n\treturn event\n\n\nfunc _get_target_is_in_range(target: Unit) -> bool:\n\tvar range_extended: float = Utils.apply_unit_range_extension(get_auto_range(), _target_type)\n\tvar target_is_in_range: bool = VectorUtils.in_range(target.get_position_wc3_2d(), _caster.get_position_wc3_2d(), range_extended)\n\n\treturn target_is_in_range\n\n\nstatic func calculate_target_type(autocast_type_arg: Autocast.Type, buff_target_type_arg: TargetType) -> TargetType:\n\tmatch autocast_type_arg:\n\t\tAutocast.Type.AC_TYPE_ALWAYS_BUFF:\n\t\t\tif buff_target_type_arg != null:\n\t\t\t\treturn buff_target_type_arg\n\t\t\telse:\n\t\t\t\treturn TargetType.new(0)\n\t\tAutocast.Type.AC_TYPE_ALWAYS_IMMEDIATE: return TargetType.new(0)\n\t\tAutocast.Type.AC_TYPE_OFFENSIVE_BUFF:\n\t\t\tif buff_target_type_arg != null:\n\t\t\t\treturn buff_target_type_arg\n\t\t\telse:\n\t\t\t\treturn TargetType.new(0)\n\t\tAutocast.Type.AC_TYPE_OFFENSIVE_UNIT: return TargetType.new(TargetType.CREEPS)\n\t\tAutocast.Type.AC_TYPE_OFFENSIVE_IMMEDIATE: return TargetType.new(0)\n\t\tAutocast.Type.AC_TYPE_NOAC_IMMEDIATE: return TargetType.new(0)\n\t\tAutocast.Type.AC_TYPE_NOAC_CREEP: return TargetType.new(TargetType.CREEPS)\n\t\tAutocast.Type.AC_TYPE_NOAC_TOWER: return TargetType.new(TargetType.TOWERS)\n\t\tAutocast.Type.AC_TYPE_NOAC_PLAYER_TOWER: return TargetType.new(TargetType.PLAYER_TOWERS)\n\t\tAutocast.Type.AC_TYPE_NOAC_POINT: return TargetType.new(0)\n\n\tpush_error(\"_calculate_target_type doesn't support type: \", autocast_type_arg)\n\n\treturn TargetType.new(0)\n\n\nfunc _get_target_for_auto_mode() -> Unit:\n\tif type_is_buff():\n\t\treturn _get_target_for_buff_autocast()\n\telif type_is_unit():\n\t\treturn _get_target_for_unit_autocast()\n\telif type_is_immediate():\n#\t\tImmediate autocasts have no target\n\t\treturn null\n\telse:\n\t\treturn null\n\n\nfunc _get_target_for_unit_autocast() -> Unit:\n# \tNOTE: use tower's current attack target instead of\n# \tsearching for nearby units ourselves.\n\tvar target: Unit = _caster.get_current_target()\n\n\tvar target_is_ok: bool = check_target_for_unit_autocast(target)\n\n\tif target_is_ok:\n\t\treturn target\n\telse:\n\t\treturn null\n\n\nfunc _get_target_for_buff_autocast() -> Unit:\n\tvar unit_list: Array = Utils.get_units_in_range(_caster, _target_type, _caster.get_position_wc3_2d(), get_auto_range())\n\n# \tNOTE: should not filter targets by buff groups if\n# \ttargets are creeps. Buff groups is a feature only for towers\n\tvar autocast_targets_towers: bool = _target_type != null && _target_type.get_unit_type() == TargetType.UnitType.TOWERS\n\tif autocast_targets_towers:\n\t\tunit_list = _filter_target_units_for_caster_buff_group(_caster, unit_list)\n\t\n\tUtils.shuffle(Globals.synced_rng, unit_list)\n\n\tvar target_self: bool = get_target_self()\n\tif !target_self:\n\t\tunit_list.erase(_caster)\n\n\tfor unit in unit_list:\n\t\tif !Utils.unit_is_valid(unit):\n\t\t\tcontinue\n\n\t\tif _buff_type == null:\n\t\t\treturn unit\n\n\t\tvar unit_is_immune: bool = unit.is_immune()\n\t\tif unit_is_immune:\n\t\t\tcontinue\n\n\t\tvar buff: Buff = unit.get_buff_of_type(_buff_type)\n\t\tvar unit_has_buff: bool = buff != null\n\n\t\tif !unit_has_buff:\n\t\t\treturn unit\n\n\treturn null\n\n\n# Examples:\n# \n# a) Caster has no buffgroups, target has no buffgroups =>\n#    accept\n# \n# b) Caster has buffgroup 1=outgoing, target has no\n#    buffgroups => reject\n# \n# c) Caster has buffgroup 1=outgoing, target has buffgroup\n#    1=incoming => accept\n# \n# d) Caster has buffgroup 1=outgoing 2=outgoing, target has\n#    buffgroup 1=incoming => accept\n# \n# e) Caster has no buffgroups, target has\n#    buffgroup 1=incoming => accept\nfunc _filter_target_units_for_caster_buff_group(caster: Unit, targets: Array) -> Array:\n\tvar caster_outgoing: Array[int] = caster.get_buff_groups([BuffGroupMode.enm.OUTGOING, BuffGroupMode.enm.BOTH])\n\n\tif caster_outgoing.is_empty():\n\t\treturn targets\n\n\tvar filtered_targets: Array = targets.filter(\n\t\tfunc(unit: Unit) -> bool:\n\t\t\tfor buff_group in caster_outgoing:\n\t\t\t\tvar target_mode: BuffGroupMode.enm = unit.get_buff_group_mode(buff_group)\n\t\t\t\tvar buff_group_match: bool = target_mode == BuffGroupMode.enm.INCOMING || target_mode == BuffGroupMode.enm.BOTH\n\n\t\t\t\tif buff_group_match:\n\t\t\t\t\treturn true\n\n\t\t\treturn false\n\t)\n\t\n\treturn filtered_targets\n\n\nfunc _get_cast_error() -> String:\n\tif _caster == null:\n\t\treturn \"\"\n\n\tvar on_cooldown: bool = _cooldown_timer.get_time_left() > 0\n\tvar mana_cost: int = get_mana_cost()\n\tvar enough_mana: bool = _caster.get_mana() >= mana_cost\n\tvar silenced: bool = _caster.is_silenced()\n\tvar stunned: bool = _caster.is_stunned()\n\n\tif on_cooldown:\n\t\treturn tr(\"AUTOCAST_ERROR_NOT_READY\")\n\telif !enough_mana:\n\t\treturn tr(\"AUTOCAST_ERROR_NOT_ENOUGH_MANA\")\n\telif silenced:\n\t\treturn tr(\"AUTOCAST_ERROR_SILENCED\")\n\telif stunned:\n\t\treturn tr(\"AUTOCAST_ERROR_STUNNED\")\n\telse:\n\t\treturn \"\"\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_auto_timer_timeout():\n\tif !can_cast():\n\t\treturn\n\t\n# \tNOTE: need to do combat check in here instead of in\n# \tcan_cast() so that if auto mode is disabled, autocast\n# \tcan still be casted manually by player. For example,\n# \tplayer needs to be able to start the cast to pick the\n# \ttarget before tower starts attacking.\n\tvar cant_cast_because_not_in_combat: bool = type_is_offensive() && !_caster.is_in_combat()\n\n\tif cant_cast_because_not_in_combat:\n\t\treturn\n\n\tvar cant_cast_because_zero_charges: bool = _item_owner != null && _item_owner.get_charges() == 0 && _item_owner.uses_charges()\n\n\tif cant_cast_because_zero_charges:\n\t\treturn\n\n\tvar target: Unit = _get_target_for_auto_mode()\n\n#\tNOTE: no error message here like in manual case becase\n#\tthis is the auto case and adding an error message here\n#\twould cause spam\n\tif target == null && !type_is_immediate():\n\t\treturn\n\n\tdo_cast(target)\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc set_caster(caster: Unit):\n\t_caster = caster\n\n\nfunc get_caster() -> Unit:\n\treturn _caster\n\n\nfunc get_autocast_index() -> int:\n\tvar autocast_list: Array[Autocast] = _caster.get_autocast_list()\n\tvar index: int = autocast_list.find(self)\n\n\treturn index\n\n\n# NOTE: autocast.getCooldown() in JASS\nfunc get_cooldown() -> float:\n\tvar cooldown: float = AutocastProperties.get_cooldown(_autocast_id)\n\n\treturn cooldown\n\n\nfunc get_remaining_cooldown() -> float:\n\tif !is_node_ready():\n\t\tpush_error(\"Autocast cannot perform the request because it hasn't been added to the scene tree. Make sure that autocast's parent and it's ancestors have been added to the scene tree. Parent: \", get_parent())\n\n\t\treturn 0.0\n\n\treturn _cooldown_timer.time_left\n\n# NOTE: autocast.getManacost() in JASS\nfunc get_mana_cost() -> int:\n\tvar mana_cost: int = AutocastProperties.get_mana_cost(_autocast_id)\n\n\treturn mana_cost\n\n\nfunc is_item_autocast() -> bool:\n\treturn _is_item_autocast\n\n\nfunc get_target_pos() -> Vector2:\n\treturn _target_pos\n\n\nfunc get_target_error_message(target: Unit) -> String:\n\tif target == null:\n\t\treturn tr(\"MESSAGE_NO_TARGET\")\n\n\tvar target_is_in_range: bool = _get_target_is_in_range(target)\n\tvar target_type_is_valid = _target_type.match(target)\n\tvar target_is_immune: bool = target.is_immune()\n\tvar target_is_self: bool = target != null && target == _caster\n\tvar target_self: bool = get_target_self()\n\tvar targetting_self_when_forbidden: bool = !target_self && target_is_self\n\n\tif !target_is_in_range:\n\t\treturn tr(\"MESSAGE_OUT_OF_RANGE\")\n\n\tif !target_type_is_valid:\n\t\treturn tr(\"MESSAGE_TARGET_NOT_VALID\")\n\n\tif target_is_immune:\n\t\treturn tr(\"MESSAGE_TARGET_IMMUNE\")\n\n\tif targetting_self_when_forbidden:\n\t\treturn tr(\"MESSAGE_CANT_CAST_ON_SELF\")\n\n\treturn tr(\"MESSAGE_TARGET_IS_VALID\")\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(autocast_id: int, creator_object: Object) -> Autocast:\n\tvar buff_type_string: String = AutocastProperties.get_buff_type(autocast_id)\n\tvar buff_type: BuffType\n\tif !buff_type_string.is_empty():\n\t\tbuff_type = creator_object.get(buff_type_string)\n\t\t\n\t\tif buff_type == null:\n\t\t\tpush_error(\"Failed to find buff type for autocast. Buff type = %s, autocast id = %s\" % [buff_type_string, autocast_id])\n\telse:\n\t\tbuff_type = null\n\n\tvar handler_function_string: String = AutocastProperties.get_handler_function(autocast_id)\n\tvar handler_function: Callable\n\tif !handler_function_string.is_empty():\n\t\thandler_function = Callable(creator_object, handler_function_string)\n\t\t\n\t\tif !handler_function.is_valid():\n\t\t\tpush_error(\"Failed to find handle function for autocast. Handler function = %s, autocast id = %d\" % [handler_function_string, autocast_id])\n#\t\t\tNOTE: Switch to empty callable to prevent\n#\t\t\truntime errors\n\t\t\thandler_function = Callable()\n\telse:\n\t\thandler_function = Callable()\n\t\n#\tNOTE: need to store autocast_type and buff_target_type\n#\tin variables instead of getting them from\n#\tAutocastProperties every time because these properties\n#\tare a bit costly too calculate all the time. Other\n#\tproperties are okay to get through AutocastProperties.\n\tvar autocast: Autocast = Preloads.autocast_scene.instantiate()\n\tautocast._autocast_id = autocast_id\n\tautocast._autocast_type = AutocastProperties.get_autocast_type(autocast_id)\n\tautocast._buff_target_type = AutocastProperties.get_buff_target_type(autocast_id)\n\tautocast._buff_type = buff_type\n\tautocast._handler = handler_function\n\n\treturn autocast\n\n\nstatic func autocast_type_to_string(t: Type) -> String:\n\tmatch t:\n\t\tType.AC_TYPE_ALWAYS_BUFF: return \"AC_TYPE_ALWAYS_BUFF\"\n\t\tType.AC_TYPE_ALWAYS_IMMEDIATE: return \"AC_TYPE_ALWAYS_IMMEDIATE\"\n\t\tType.AC_TYPE_OFFENSIVE_BUFF: return \"AC_TYPE_OFFENSIVE_BUFF\"\n\t\tType.AC_TYPE_OFFENSIVE_UNIT: return \"AC_TYPE_OFFENSIVE_UNIT\"\n\t\tType.AC_TYPE_OFFENSIVE_IMMEDIATE: return \"AC_TYPE_OFFENSIVE_IMMEDIATE\"\n\t\tType.AC_TYPE_OFFENSIVE_POINT: return \"AC_TYPE_OFFENSIVE_POINT\"\n\t\tType.AC_TYPE_NOAC_IMMEDIATE: return \"AC_TYPE_NOAC_IMMEDIATE\"\n\t\tType.AC_TYPE_NOAC_CREEP: return \"AC_TYPE_NOAC_CREEP\"\n\t\tType.AC_TYPE_NOAC_TOWER: return \"AC_TYPE_NOAC_TOWER\"\n\t\tType.AC_TYPE_NOAC_PLAYER_TOWER: return \"AC_TYPE_NOAC_PLAYER_TOWER\"\n\t\tType.AC_TYPE_NOAC_POINT: return \"AC_TYPE_NOAC_POINT\"\n\n\treturn \"UNKNOWN\"\n\n\nstatic func string_to_autocast_type(t_string: String) -> Type:\n\tmatch t_string:\n\t\t\"AC_TYPE_ALWAYS_BUFF\": return Type.AC_TYPE_ALWAYS_BUFF\n\t\t\"AC_TYPE_ALWAYS_IMMEDIATE\": return Type.AC_TYPE_ALWAYS_IMMEDIATE\n\t\t\"AC_TYPE_OFFENSIVE_BUFF\": return Type.AC_TYPE_OFFENSIVE_BUFF\n\t\t\"AC_TYPE_OFFENSIVE_UNIT\": return Type.AC_TYPE_OFFENSIVE_UNIT\n\t\t\"AC_TYPE_OFFENSIVE_IMMEDIATE\": return Type.AC_TYPE_OFFENSIVE_IMMEDIATE\n\t\t\"AC_TYPE_OFFENSIVE_POINT\": return Type.AC_TYPE_OFFENSIVE_POINT\n\t\t\"AC_TYPE_NOAC_IMMEDIATE\": return Type.AC_TYPE_NOAC_IMMEDIATE\n\t\t\"AC_TYPE_NOAC_CREEP\": return Type.AC_TYPE_NOAC_CREEP\n\t\t\"AC_TYPE_NOAC_TOWER\": return Type.AC_TYPE_NOAC_TOWER\n\t\t\"AC_TYPE_NOAC_PLAYER_TOWER\": return Type.AC_TYPE_NOAC_PLAYER_TOWER\n\t\t\"AC_TYPE_NOAC_POINT\": return Type.AC_TYPE_NOAC_POINT\n\n\treturn Type.AC_TYPE_NOAC_POINT\n"
  },
  {
    "path": "src/towers/autocast.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://81kmmaauauh7\"]\n\n[ext_resource type=\"Script\" path=\"res://src/towers/autocast.gd\" id=\"1\"]\n[ext_resource type=\"Script\" path=\"res://src/game_scene/manual_timer.gd\" id=\"2_hmm6b\"]\n\n[node name=\"Autocast\" type=\"Node2D\" node_paths=PackedStringArray(\"_cooldown_timer\", \"_auto_timer\")]\nscript = ExtResource(\"1\")\n_cooldown_timer = NodePath(\"CooldownTimer\")\n_auto_timer = NodePath(\"AutoTimer\")\n\n[node name=\"CooldownTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_hmm6b\")\none_shot = true\n\n[node name=\"AutoTimer\" type=\"Node\" parent=\".\"]\nscript = ExtResource(\"2_hmm6b\")\nwait_time = 0.2\nautostart = true\n\n[connection signal=\"timeout\" from=\"AutoTimer\" to=\".\" method=\"_on_auto_timer_timeout\"]\n"
  },
  {
    "path": "src/towers/event.gd",
    "content": "class_name Event\n\n\nenum Type {\n\tCLEANUP,\n\tCREATE,\n\tUPGRADE,\n\tREFRESH,\n\tDEATH,\n\tKILL,\n\tLEVEL_CHANGED,\n\tATTACK,\n\tATTACKED,\n\tDAMAGE,\n\tDAMAGED,\n\tEXPIRE,\n\tSPELL_CAST,\n\tSPELL_TARGET,\n\tPURGE,\n}\n\n\nvar _buff: Buff\n# NOTE: damage may be modified in event handlers to change\n# the final effect of the event\nvar damage: float\nvar _number_of_crits: int = 0\n# target is of type Unit, can't use typing because of cyclic dependency...\nvar _target: Unit\nvar _is_main_target: bool = false\nvar _is_spell_damage: bool = false\n# Timer belonging to a buff that triggered this event. Used\n# for cases where periodic event handler needs to modify\n# duration of periodic event.\nvar _timer: ManualTimer = null\nvar _autocast: Autocast = null\nvar _level_increased_during_event: bool = false\n\n\n#########################\n### Code starts here  ###\n#########################\n\nfunc _init(target: Unit):\n\t_target = target\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc get_buff() -> Buff:\n\treturn _buff\n\n# Event.getAutocastType() in JASS\nfunc get_autocast_type() -> Autocast:\n\treturn _autocast\n\n# Event.getTarget() in JASS\nfunc get_target() -> Unit:\n\treturn _target\n\n# Only relevant for \"damage\" event. True for damage\n# from normal tower attacks, for main target of splash tower\n# attacks and for first target of tower bounce attack.\n# \n# Event.isMainTarget() in JASS\nfunc is_main_target() -> bool:\n\treturn _is_main_target\n\n# Only relevant for damaged events. True if damaged event is\n# caused by spell damage.\n# Event.isSpellDamage() in JASS\nfunc is_spell_damage() -> bool:\n\treturn _is_spell_damage\n\n# Changes the properties of the current PERIODIC event. Does\n# nothing when called for other types of events. Note that\n# if \"one shot\" is set to true, then the periodic event will\n# trigger one more time and then stop forever.\n# Event.enableAdvanced() in JASS\nfunc enable_advanced(wait_time: float, one_shot: bool):\n\tif _timer == null:\n\t\treturn\n\n\t_timer.stop()\n\t_timer.wait_time = wait_time\n\t_timer.one_shot = one_shot\n\t_timer.start()\n\n\n# This returns the number of crits for current attack or\n# damage instance. This contains a valid value only inside\n# the following events: attack, attacked, damage, damaged.\n# \n# NOTE: tower.getNumberOfCrits() in JASS\n# This function belongs to Tower in JASS engine but I moved\n# to Event because it makes more sense.\nfunc get_number_of_crits() -> int:\n\treturn _number_of_crits\n\n\n# Valid only for the following events: attack, attacked,\n# damage, damaged.\n# NOTE: Event.isAttackDamageCritical() in JASS\nfunc is_attack_damage_critical() -> int:\n\tvar is_critical: bool = _number_of_crits > 0\n\n\treturn is_critical\n\n\n# Returns true if current LEVEL_CHANGED event was triggered when\n# tower level increased. False if tower level decreased.\n# NOTE: \"Event.isLevelUp()\" in JASS\nfunc level_increased() -> bool:\n\treturn _level_increased_during_event\n"
  },
  {
    "path": "src/towers/multiboard_values.gd",
    "content": "class_name MultiboardValues\n\n\nvar _size: int = 0\nvar _key_map: Dictionary = {}\nvar _value_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(size_arg: int):\n\t_size = size_arg\n\n\tfor index in range(0, _size):\n\t\t_key_map[index] = \"\"\n\t\t_value_map[index] = \"\"\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: multiboard.setKey() in JASS\nfunc set_key(index: int, key: String):\n\t_key_map[index] = key\n\n\n# NOTE: multiboard.setValue() in JASS\nfunc set_value(index: int, value: String):\n\t_value_map[index] = value\n\n\n# NOTE: multiboard.size() in JASS\nfunc size() -> int:\n\treturn _size\n\n\nfunc get_key(index: int) -> String:\n\tvar key: String = _key_map[index]\n\n\treturn key\n\n\nfunc get_value(index: int) -> String:\n\tvar value: String = _value_map[index]\n\n\treturn value\n"
  },
  {
    "path": "src/towers/range_data.gd",
    "content": "class_name RangeData\n\n\n# This class is used to store data about a tower \"range\".\n# Range can refer to range of tower attack, tower aura or\n# tower ability. when displaying ranges in tower details and\n# when setting up range indicators.\n\n\nvar name_english: String = \"placeholder\"\nvar radius: float = 100\nvar targets_creeps: bool = true\nvar affected_by_builder: bool = false\nvar is_attack_range: bool = false\n\n# NOTE: avoid using any greenish colors to avoid confusion\n# with selection circle.\nconst COLOR_LIST: Array = [Color.AQUA, Color.ORANGE, Color.YELLOW, Color.PURPLE, Color.PINK, Color.RED, Color.LIGHT_BLUE]\n\n\nfunc _init(name_english_arg: String, radius_arg: float, target_type: TargetType = null, is_attack: bool = false):\n\tname_english = name_english_arg\n\tradius = radius_arg\n\tis_attack_range = is_attack\n\tif target_type != null:\n\t\ttargets_creeps = target_type.get_unit_type() == TargetType.UnitType.CREEPS\n\n\nfunc get_radius_with_builder_bonus(player: Player):\n\tvar builder: Builder = player.get_builder()\n\tvar with_bonus: float = radius\n\tif affected_by_builder or is_attack_range:\n\t\tvar radius_bonus: float = builder.get_range_bonus()\n\t\twith_bonus += radius_bonus\n\t\n\tif is_attack_range:\n\t\twith_bonus += player.get_attack_range_bonus()\n\t\n\treturn with_bonus\n\n\nstatic func get_color_for_index(index: int) -> Color:\n\tvar wrapped_index: int = wrapi(index, 0, COLOR_LIST.size())\n\tvar color: Color = COLOR_LIST[wrapped_index]\n\n\treturn color\n"
  },
  {
    "path": "src/towers/range_indicator.gd",
    "content": "class_name RangeIndicator\nextends Node2D\n\n# Shows range of a tower by drawing a circle.\n\n\nconst POINT_COUNT: int = 100\n\n@export var radius: float\n@export var enable_floor_collisions: bool = true\n@export var color: Color\n\n# NOTE: y_offset is used by TowerPreview to draw range\n# indicator at an offset so that it's at same y coord as the\n# tower sprite.\nvar y_offset: float = 0.0\nvar _prev_pos: Vector2 = Vector2.INF\nvar ability_name_english: String = \"\"\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _draw():\n\t_draw_circle_arc(self.position, 0, 360)\n\n\n# NOTE: redraw when position changes because depending on\n# position, we need to draw different transparency sections.\n# For towers, we never redraw because they don't move.\n# For tower preview, we redraw as the mouse moves around.\nfunc _process(_delta: float):\n\tvar new_pos: Vector2 = global_position\n\tvar pos_changed: bool = new_pos != _prev_pos\n\t_prev_pos = new_pos\n\n\tif pos_changed:\n\t\tqueue_redraw()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_radius(radius_wc3: float):\n\tradius = Utils.to_pixels(radius_wc3)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _draw_circle_arc(center: Vector2, angle_from: float, angle_to: float):\n\tvar transparent_color: Color = Color(color).darkened(0.5)\n\ttransparent_color.a = 0.2\n\n\tvar angles_tuple_array: Array = [] \n\tvar on_ground_start_angle: float = -1.0\n\tvar on_ground = false\n\tvar prev_angle: float = -1.0\n\t\n\tvar transform_scale: Vector2 = Vector2(1.0, 0.5)\n\tdraw_set_transform(Vector2.ZERO, 0.0, transform_scale)\n\t\n\tif enable_floor_collisions:\n\t\tdraw_arc(center + Vector2(0, y_offset) * 2, radius, deg_to_rad(angle_from), deg_to_rad(angle_to), 100, transparent_color, 5.0, true)\n\telse:\n\t\tdraw_arc(center + Vector2(0, y_offset) * 2, radius, deg_to_rad(angle_from), deg_to_rad(angle_to), 100, color, 5.0, true)\n\n\t\treturn\n\t\n\t# Calculate floor collisions for range indicator points.\n\t# Add points which are on the ground floor to the array.\n\tfor i in range(POINT_COUNT):\n\t\tvar current_angle: float = deg_to_rad(angle_from + i * (angle_to - angle_from) / POINT_COUNT)\n\t\tvar point_top_down: Vector2 = center + Vector2(radius, 0).rotated(current_angle)\n\t\tvar point_canvas: Vector2 = VectorUtils.top_down_to_canvas(point_top_down) + Vector2(0, y_offset)\n\t\t\n\t\tvar global_point_pos: Vector2 = point_canvas + global_position\n\t\tvar map: Map = Globals.get_map()\n\t\tvar pos_is_on_ground: bool = map.pos_is_on_ground(global_point_pos)\n\t\t\n\t\tif pos_is_on_ground && !on_ground:\n\t\t\ton_ground_start_angle = prev_angle\n\t\t\ton_ground = true\n\t\telif !pos_is_on_ground && on_ground:\n\t\t\tvar on_ground_end_angle: float = current_angle\n\t\t\tangles_tuple_array.append(Vector2(on_ground_start_angle, on_ground_end_angle))\n\t\t\ton_ground = false\n\n\t\tprev_angle = current_angle\n\t\n\t# If last ground point didn't have a closing pair point,\n\t# set it as a starting point for the first tuple.\n\tif on_ground && !angles_tuple_array.is_empty():\n\t\tangles_tuple_array[0].x = on_ground_start_angle - TAU\n\t\n\t# Only draw arcs which are on the ground floor, because previously\n\t# we already draw the whole circle with transparent color.\n\tfor angles_tuple in angles_tuple_array:\n\t\tdraw_arc(center + Vector2(0, y_offset) * 2, radius, angles_tuple.y, angles_tuple.x, 100, color, 5.0, true)\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make() -> RangeIndicator:\n\tvar range_indicator: RangeIndicator = Preloads.range_indicator_scene.instantiate()\n\treturn range_indicator\n"
  },
  {
    "path": "src/towers/range_indicator.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://oqea8bsilibl\"]\n\n[ext_resource type=\"Script\" path=\"res://src/towers/range_indicator.gd\" id=\"1\"]\n\n[node name=\"RangeIndicator\" type=\"Node2D\"]\nscript = ExtResource(\"1\")\n"
  },
  {
    "path": "src/towers/tower.gd",
    "content": "class_name Tower\nextends Unit\n\n\nsignal items_changed()\n\n\nenum AttackStyle {\n\tNORMAL,\n\tSPLASH,\n\tBOUNCE,\n}\n\nconst ELEMENT_TO_EXPLOSION_ART: Dictionary = {\n\tElement.enm.ICE: \"res://src/effects/projectile_explosion_ice.tscn\",\n\tElement.enm.NATURE: \"res://src/effects/projectile_explosion_nature.tscn\",\n\tElement.enm.FIRE: \"res://src/effects/projectile_explosion_fire.tscn\",\n\tElement.enm.ASTRAL: \"res://src/effects/projectile_explosion_astral.tscn\",\n\tElement.enm.DARKNESS: \"res://src/effects/projectile_explosion_darkness.tscn\",\n\tElement.enm.IRON: \"res://src/effects/projectile_explosion_iron.tscn\",\n\tElement.enm.STORM: \"res://src/effects/projectile_explosion_storm.tscn\",\n\tElement.enm.NONE: \"res://src/effects/projectile_explosion_storm.tscn\",\n}\n\n\nconst TOWER_SELECTION_VISUAL_SIZE: int = 128\nstatic var TARGET_TYPE_GROUND_ONLY: TargetType = TargetType.new(TargetType.CREEPS + TargetType.SIZE_MASS + TargetType.SIZE_NORMAL + TargetType.SIZE_CHAMPION + TargetType.SIZE_BOSS)\nstatic var TARGET_TYPE_AIR_ONLY: TargetType = TargetType.new(TargetType.CREEPS + TargetType.SIZE_AIR)\n\n@export var _id: int = 0\nvar _splash_map: Dictionary = {}\nvar _bounce_count_max: int = 0\nvar _bounce_damage_multiplier: float = 0.0\nvar _attack_style: AttackStyle = AttackStyle.NORMAL\n# NOTE: _target_list must be an untyped Array because it may\n# contain invalid instances.\nvar _target_list: Array = []\nvar _target_count_from_tower: int = 1\nvar _target_count_from_item: int = 0\nvar _default_projectile_type: ProjectileType\nvar _current_attack_cooldown: float = 0.0\nvar _was_ordered_to_stop_attack: bool = false\nvar _was_ordered_to_change_target: bool = false\nvar _new_target_from_order: Unit\nvar _item_container: TowerItemContainer\n# NOTE: preceding tower reference is used only during\n# Tower._ready() and TowerBehavior.init(). It becomes null\n# forever after that and it is also always null for first\n# tier towers.\nvar _temp_preceding_tower: Tower = null\n# This attack type determines which targets will be picked\n# for attacking.\nvar _attack_target_type: TargetType = TargetType.new(TargetType.CREEPS)\nvar _range_indicator_list: Array[RangeIndicator] = []\nvar _tower_behavior: TowerBehavior = null\nvar _sprite: Sprite2D = null\nvar _hide_attack_projectiles: bool = false\nvar _current_crit_count: int = 0\nvar _current_crit_damage: float = 0\nvar _transform_is_allowed: bool = true\nvar _is_in_combat: bool = false\n\n\n@export var _mana_bar: ProgressBar\n@export var _tower_selection_area: Area2D\n@export var _visual: Node2D\n@export var _range_indicator_parent: Node2D\n@export var _sprite_parent: Node2D\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tsuper()\n\n# \tNOTE: see explanation of z_index setup in map.gd\n\tz_index = 20\n\n\t_set_visual_node(_visual)\n\tvar outline_thickness: float = 6.0\n\t_setup_unit_sprite(_sprite, _sprite_parent, outline_thickness)\n\n#\tNOTE: set z to this value to position tower on 2nd floor\n\tvar tower_z: float = Constants.TILE_SIZE_WC3\n\tset_z(tower_z)\n#\tNOTE: need to adjust y position of selection visual\n# \tbecause it's placed at ground position in Unit.gd but\n# \tneeds to be at visual position for towers (which is 2nd\n# \tfloor).\n\t_selection_indicator.position.y -= Constants.TILE_SIZE.y\n\n\tvar base_mana: int = TowerProperties.get_mana(_id)\n\tset_base_mana(base_mana)\n\tset_mana(0)\n\n\tvar base_mana_regen: int = TowerProperties.get_mana_regen(_id)\n\tset_base_mana_regen(base_mana_regen)\n\n\tvar inventory_capacity: int = get_inventory_capacity()\n\t_item_container = TowerItemContainer.new(inventory_capacity, self)\n\t_item_container.set_player(get_player())\n\tadd_child(_item_container)\n\t_item_container.items_changed.connect(_on_item_container_items_changed)\n\n\tGroupManager.add(\"towers\", self, get_uid())\n\n\tmana_changed.connect(_on_mana_changed)\n\t_on_mana_changed()\n\t_mana_bar.visible = get_base_mana() > 0\n\n\tvar missile_speed: int = TowerProperties.get_missile_speed(get_id())\n\t_default_projectile_type = ProjectileType.create_interpolate(\"\", missile_speed, self)\n\t_default_projectile_type.set_event_on_interpolation_finished(_on_projectile_target_hit)\n\tvar explosion_art: String = ELEMENT_TO_EXPLOSION_ART[get_element()]\n\t_default_projectile_type.set_explosion_art(explosion_art)\n\n\tvar missile_uses_lightning_visual: bool = TowerProperties.get_missile_use_lightning_visual(get_id())\n\tif missile_uses_lightning_visual:\n\t\t_default_projectile_type.switch_to_lightning_visual()\n\n# \tCarry over some properties and all items from preceding\n# \ttower\n\tif _temp_preceding_tower != null:\n\t\tget_player().transfer_autooils(_temp_preceding_tower, self)\n\t\t\n\t\tvar preceding_item_list: Array = _temp_preceding_tower.get_items()\n\t\tvar preceding_oil_list: Array = _temp_preceding_tower.get_oils()\n\n\t\tfor oil_item in preceding_oil_list:\n\t\t\t_temp_preceding_tower.get_item_container().remove_item(oil_item)\n\t\t\t_item_container.add_item(oil_item)\n\n#\t\tRemove items from preceding tower\n#\t\tNOTE: need to use drop() and pickup() for consistent\n#\t\tlogic, instead of directly manipulating item\n#\t\tcontainers.\n\t\tfor item in preceding_item_list:\n\t\t\titem.drop()\n\n#\t\tNOTE: must set level and experience after removing\n#\t\titems from preceding tower and before adding items\n#\t\tto new tower. This is to correctly handle items\n#\t\twhich grant experience while carried.\n\t\tset_level(_temp_preceding_tower._level)\n\t\t_experience_centi = _temp_preceding_tower._experience_centi\n\n#\t\tAdd items to new tower\n#\t\tNOTE: for upgrade case, inventory will always be\n#\t\tsame size or bigger but for transform case inventory\n#\t\tmay be smaller. Handle transform case by returning\n#\t\tany extra items to stash.\n\t\tfor item in preceding_item_list:\n\t\t\tif have_item_space():\n\t\t\t\titem.pickup(self)\n\t\t\telse:\n\t\t\t\titem.fly_to_stash(0.0)\n\n\t\t_kill_count = _temp_preceding_tower._kill_count\n\t\t_best_hit = _temp_preceding_tower._best_hit\n\t\t_damage_dealt_total = _temp_preceding_tower._damage_dealt_total\n\t\t_damage_dealt_to_wave_map = _temp_preceding_tower._damage_dealt_to_wave_map\n\t\t_attack_damage_dealt = _temp_preceding_tower._attack_damage_dealt\n\t\t_spell_damage_dealt = _temp_preceding_tower._spell_damage_dealt\n\t\t_attack_damage_dealt_to_wave_map = _temp_preceding_tower._attack_damage_dealt_to_wave_map\n\t\t_spell_damage_dealt_to_wave_map = _temp_preceding_tower._spell_damage_dealt_to_wave_map\n\t\t\n#\t\tTransition all buff groups from preceding tower\n\t\t_buff_groups = _temp_preceding_tower._buff_groups.duplicate()\n\telse:\n#\t\tNOTE: only apply tower exp and lvl bonus if tower is\n#\t\t\"fresh\". When tower is transformed or upgraded, it\n#\t\tinherits level of preceding tower\n#\t\tand these bonuses can't be applied.\n\t\tvar exp_from_bonuses: float = _calculate_exp_from_bonuses()\n\t\tvar lvl_from_bonuses: int = Experience.get_level_at_exp(exp_from_bonuses, get_player())\n\t\tset_level(lvl_from_bonuses)\n\t\t_experience_centi = roundi(exp_from_bonuses * 100.0)\n\n\tvar wisdom_modifier: Modifier = get_player().get_wisdom_modifier()\n\tadd_modifier(wisdom_modifier)\n\n#\tNOTE: some stats have an innate level-based modifier\n\tvar innate_modifier: Modifier = Modifier.new()\n\tinnate_modifier.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0, Constants.INNATE_MOD_ATK_CRIT_CHANCE_LEVEL_ADD)\n\tinnate_modifier.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0, Constants.INNATE_MOD_ATK_CRIT_DAMAGE_LEVEL_ADD)\n\tinnate_modifier.add_modification(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, 0, Constants.INNATE_MOD_SPELL_CRIT_CHANCE_LEVEL_ADD)\n\tinnate_modifier.add_modification(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, 0, Constants.INNATE_MOD_SPELL_CRIT_DAMAGE_LEVEL_ADD)\n\tinnate_modifier.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0, Constants.INNATE_MOD_DAMAGE_BASE_PERC_LEVEL_ADD)\n\tinnate_modifier.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0, Constants.INNATE_MOD_ATTACKSPEED_LEVEL_ADD)\n\tadd_modifier(innate_modifier)\n\n\tvar tower_id: int = get_id()\n\n\tvar multishot_count: int = TowerProperties.get_multishot(tower_id)\n\tset_target_count(multishot_count)\n\n\tvar bounce_attack_values: Array = TowerProperties.get_bounce_attack(tower_id)\n\tvar splash_attack_values: Dictionary = TowerProperties.get_splash_attack(tower_id)\n\tif !bounce_attack_values.is_empty():\n\t\t_attack_style = AttackStyle.BOUNCE\n\t\t_bounce_count_max = bounce_attack_values[0]\n\t\t_bounce_damage_multiplier = bounce_attack_values[1]\n\telif !splash_attack_values.is_empty():\n\t\t_attack_style = AttackStyle.SPLASH\n\t\t_splash_map = splash_attack_values\n\n\tvar attack_target_type: TargetType = TowerProperties.get_attack_target_type(tower_id)\n\t_attack_target_type = attack_target_type\n\n\tvar specials_modifier = TowerProperties.get_specials_modifier(tower_id)\n\tadd_modifier(specials_modifier)\n\n\t_tower_behavior.init(self, _temp_preceding_tower)\n\n#\tNOTE: add aura range indicators to \"visual\" for correct\n#\tpositioning on y axis.\n\tvar range_data_list: Array[RangeData] = TowerProperties.get_range_data_list(get_id())\n\t_range_indicator_list = Utils.setup_range_indicators(range_data_list, _range_indicator_parent, get_player())\n\n#\tHide all range indicators by default, they get shown\n#\twhen mousing over ability\n\tfor range_indicator in _range_indicator_list:\n\t\trange_indicator.visible = false\n\n\t_setup_selection_signals(_tower_selection_area)\n\n\tvar sprite_dimensions: Vector2 = Utils.get_sprite_dimensions(_sprite)\n\t_set_unit_dimensions(sprite_dimensions)\n\n#\tNOTE: we want size of selection visual to be the same\n#\tfor all towers. That's why we're not using sprite\n#\tdimensions here like for creeps.\n\t_set_selection_size(TOWER_SELECTION_VISUAL_SIZE)\n\n#\tReset preceding tower var to avoid having dangling\n#\treference\n#\tNOTE: need to reset this reference at this point and not\n#\tany earlier because it's used in previous operations.\n\t_temp_preceding_tower = null\n\t\n\n# NOTE: need to do attack timing without Timer because Timer\n# doesn't handle short durations well (<0.5s)\nfunc update(delta: float):\n\tsuper.update(delta)\n\n\tif is_stunned():\n\t\treturn\n\n#\tNOTE: reduce current tracked cooldown to overall\n#\tcooldown if overall cooldown is smaller. This handles\n#\tcases where tower's attack speed was significantly\n#\treduced and then returns to normal.\n# \n#\tFor example, let's say tower's attack speed gets reduced\n#\tby some debuff so much that the attack cooldown becomes\n#\t100 seconds. The debuff expires after 10 seconds and\n#\ttower would be doing nothing for 90 seconds. Instead of\n#\tthat, we recalculate the cooldown so that tower can\n#\tstart attacking normally again.\n\tvar attack_speed: float = get_current_attack_speed()\n\tif _current_attack_cooldown > attack_speed:\n\t\t_current_attack_cooldown = attack_speed\n\n\tif _current_attack_cooldown > 0.0:\n\t\t_current_attack_cooldown -= delta\n\n\tif _current_attack_cooldown <= 0.0:\n#\t\tNOTE: need to update target list even if tower is\n#\t\tnot attacking, to have targets for offensive\n#\t\tabilities and items.\n\t\t_update_target_list()\n\t\t\n\t\tvar attack_enabled: bool = get_attack_enabled()\n\n\t\tvar should_reset_attack_cooldown: bool\n\t\tif attack_enabled:\n\t\t\tshould_reset_attack_cooldown = _try_to_attack()\n\t\telse:\n\t\t\tshould_reset_attack_cooldown = true\n\n# \t\tNOTE: important to add, not set! So that if game is\n# \t\tlagging, all of the attacks fire instead of skipping.\n\t\tif should_reset_attack_cooldown:\n\t\t\t_current_attack_cooldown += attack_speed\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_transform_is_allowed(value: bool):\n\t_transform_is_allowed = value\n\n\nfunc get_transform_is_allowed() -> bool:\n\treturn _transform_is_allowed\n\n\n# NOTE: resetAttackCrits() in JASS\nfunc reset_attack_crits():\n\t_current_crit_count = 0\n\t_current_crit_damage = 0.0\n\n\nfunc set_range_indicator_visible(ability_name_english: String, value: bool):\n\tfor range_indicator in _range_indicator_list:\n\t\tvar name_match: bool = range_indicator.ability_name_english == ability_name_english\n\t\t\n\t\tif name_match:\n\t\t\trange_indicator.visible = value\n\n\nfunc on_tower_details() -> MultiboardValues:\n\treturn _tower_behavior.on_tower_details()\n\n\nfunc remove_from_game():\n\t_tower_behavior.on_destruct()\n\n\tsuper()\n\n\nfunc force_attack_target(forced_target: Creep):\n\tvar type_ok: bool = _attack_target_type.match(forced_target)\n\tif !type_ok:\n\t\treturn\n\n#\tNOTE: if tower can attack 1 target, then we simply stop\n#\tattacking current target. If tower can attack multiple\n#\ttargets, then we substitute one of the targets with the\n#\tforced target. Note that if the forced target is out of\n#\trange, we add it anyway and the tower will later\n#\tautomatically remove out of range forced target find a\n#\tnew valid target before next attack.\n\tif !_target_list.is_empty():\n\t\t_remove_target(_target_list[0])\n\n\t_add_target(forced_target)\n\n\n# NOTE: tower.orderStop() in JASS\nfunc order_stop():\n\t_was_ordered_to_stop_attack = true\n\n\n# Forces tower to attack a particular target. Works only if\n# called during ATTACK event callback.\n# NOTE: tower.issueTargetOrder() in JASS\nfunc issue_target_order(target: Unit):\n\tif !Utils.unit_is_valid(target):\n\t\treturn\n\n\t_was_ordered_to_change_target = true\n\t_new_target_from_order = target\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _calculate_exp_from_bonuses() -> float:\n\tvar player = get_player()\n\tvar builder: Builder = player.get_builder()\n\t\n\tvar tower_lvl_bonus: int = builder.get_tower_lvl_bonus()\n\tvar tower_exp_bonus: float = player.get_tower_exp_bonus()\n\t\n\tvar current_lvl: int = Experience.get_level_at_exp(tower_exp_bonus, player)\n\tvar experience_for_current_level: int = Experience.get_exp_for_level(current_lvl)\n\tvar increased_lvl: int = min(current_lvl + tower_lvl_bonus, player.get_max_tower_level())\n\tvar experience_for_increased_level: int = Experience.get_exp_for_level(increased_lvl)\n\t\n\tvar added_exp: float = float(experience_for_increased_level - experience_for_current_level)\n\t\n\treturn tower_exp_bonus + added_exp\n\n\nfunc _get_attack_ability_description() -> String:\n\tvar tower_id: int = get_id()\n\n\tvar base_attack_range: int = floor(get_base_range())\n\tvar bonus_attack_range: int = floor(get_range() - base_attack_range)\n\tvar attack_type: AttackType.enm = TowerProperties.get_attack_type(tower_id)\n\tvar damage_dealt_string: String = AttackType.get_rich_text_for_damage_dealt(attack_type)\n\tvar attack_type_string: String = AttackType.convert_to_colored_string(attack_type)\n\t\n\tvar attack_range_str: String = \"%s\" % base_attack_range\n\tif bonus_attack_range != 0:\n\t\tattack_range_str += \" + %s\" % bonus_attack_range\n\t\n\tvar text: String = tr(\"TOWER_ATTACK_ABILITY_TEXT\").format({ATTACK_TYPE = attack_type_string, RANGE = attack_range_str, DAMAGE_TO_TEXT = damage_dealt_string})\n\n\treturn text\n\n\nfunc _do_damage_from_projectile(projectile: Projectile, target: Unit, damage: float, is_main_target: bool):\n\tif !Utils.unit_is_valid(target):\n\t\treturn\n\n\tvar crit_count: int = projectile.get_tower_crit_count()\n\tvar crit_ratio: float = projectile.get_tower_crit_ratio()\n\tvar emit_damage_event: bool = true\n\n\tdo_attack_damage(target, damage, crit_ratio, crit_count, is_main_target, emit_damage_event)\n\n\n# NOTE: this f-n does some unnecessary work in some cases\n# but it's simpler this way.\n# NOTE: arg needs to be untyped because it may be an invalid\n# instance.\nfunc _target_is_valid(target) -> bool:\n#\tNOTE: return early here, so that if unit instance is\n#\tinvalid, we don't call f-ns on it - that would cause\n#\terrors\n\tvar unit_is_valid: bool = Utils.unit_is_valid(target)\n\tif !unit_is_valid:\n\t\treturn false\n\n# \tNOTE: need to extend attack range by \"tower radius\".\n# \tThis is how it works in the original game.\n\tvar attack_range: float = get_range() + Constants.RANGE_CHECK_BONUS_FOR_TOWERS\n\tattack_range = Utils.apply_unit_range_extension(attack_range, _attack_target_type)\n\t\n\tvar in_range = VectorUtils.in_range(get_position_wc3_2d(), target.get_position_wc3_2d(), attack_range)\n\n\tvar target_is_immune: bool = target.is_immune()\n\tvar attack_type_is_arcane: bool = get_attack_type() == AttackType.enm.ARCANE\n\tvar target_is_immune_to_attack_type: bool = target_is_immune && attack_type_is_arcane\n\n\tvar target_is_valid: bool = in_range && !target_is_immune_to_attack_type\n\n\treturn target_is_valid\n\n\n# NOTE: change color of projectile according to tower's\n# element. Note that this overrides projectile's natural color so\n# will need to rework this if we decide to make separate\n# projectile sprites for each element.\nfunc _make_projectile(from_pos_base: Vector3, target: Unit) -> Projectile:\n\tvar z_arc: float = TowerProperties.get_missile_arc(get_id())\n\tvar from_pos: Vector3 = from_pos_base + Projectile.UNIT_Z_OFFSET\n\tvar projectile: Projectile = Projectile.create_linear_interpolation_from_point_to_unit(_default_projectile_type, self, 0, 0, from_pos, target, z_arc, true)\n\n\tif _hide_attack_projectiles:\n\t\tprojectile.hide()\n\n\tvar element_color: Color\n\tvar element: Element.enm = get_element()\n\n\tmatch element:\n\t\tElement.enm.ICE: element_color = Color.LIGHT_BLUE\n\t\tElement.enm.NATURE: element_color = Color.FOREST_GREEN\n\t\tElement.enm.FIRE: element_color = Color.TOMATO\n\t\tElement.enm.ASTRAL: element_color = Color.GOLD\n\t\tElement.enm.DARKNESS: element_color = Color.PURPLE\n\t\tElement.enm.IRON: element_color = Color.SLATE_GRAY\n\t\tElement.enm.STORM: element_color = Color.TEAL\n\t\tElement.enm.NONE: element_color = Color.PINK\n\n\tprojectile.modulate = element_color\n\n\treturn projectile\n\n\nfunc _try_to_attack() -> bool:\n# \tNOTE: have to do this weird stuff instead of just\n# \titerating over target list because attacks can modify\n# \tthe target list by killing creeps (and not just the\n# \tcurrent target)\n\tvar attack_count: int = 0\n\tvar already_attacked_list: Array = []\n\n\twhile attack_count < get_target_count():\n\t\tvar target: Creep = null\n\n\t\tfor the_target in _target_list:\n#\t\t\tNOTE: need to check for unit validy here because\n#\t\t\ttargets during multishot attacks may become\n#\t\t\tinvalid. For example, if a previously attacked\n#\t\t\tcreep has a debuff which makes it explode and it\n#\t\t\tkills another target nearby.\n\t\t\tif !Utils.unit_is_valid(the_target):\n\t\t\t\tcontinue\n\n\t\t\tvar already_attacked: bool = already_attacked_list.has(the_target)\n\n\t\t\tif !already_attacked:\n\t\t\t\ttarget = the_target\n\n\t\t\t\tbreak\n\n\t\tif !Utils.unit_is_valid(target):\n\t\t\tbreak\n\n\t\tvar original_target: Unit = target\n\n\t\tvar target_is_first: bool = attack_count == 0\n\t\ttarget = _attack_target(target, target_is_first)\n\t\talready_attacked_list.append(target)\n\n#\t\tNOTE: manually swap targets if target was changed\n#\t\tvia issue_target_order() during _attack_target().\n\t\tvar was_ordered_to_change_target: bool = original_target != target\n\n\t\tif was_ordered_to_change_target:\n\t\t\tvar new_target_is_valid: bool = Utils.unit_is_valid(target)\n\n\t\t\tif new_target_is_valid:\n\t\t\t\t_remove_target(original_target)\n\t\t\t\t_add_target(target)\n\n\t\tattack_count += 1\n\n#\t\tNOTE: handlers for attack event (inside\n#\t\t_attack_target) may order the tower to stop\n#\t\tattacking or switch to a different target. Process\n#\t\tthe orders here. This part is to stop attacking if\n#\t\ttower has multishot.\n\t\tif _was_ordered_to_stop_attack:\n\t\t\t_was_ordered_to_stop_attack = false\n\n\t\t\tbreak\n\n\tvar attack_success: bool = attack_count > 0\n\n\treturn attack_success\n\n\n# NOTE: returns the target which was actually attacked. May\n# be different from input target if tower was ordered to\n# switch to new target.\nfunc _attack_target(target: Unit, target_is_first: bool) -> Unit:\n#\tNOTE: need to generate crit number here early instead of\n#\tright before dealing damage, so that for attacks like\n#\tsplash damage and bounce attacks all of the damage dealt\n#\thas the same crit values. Also so that attack and damage\n#\tevent handlers have access to crit count.\n# \n# \tNOTE: these variables need to be member vars instead of\n# \tlocal vars because some ATTACK callbacks in tower\n# \tscripts need to modify them.\n\t_current_crit_count = _generate_crit_count(0.0, 0.0)\n\t_current_crit_damage = _calc_attack_multicrit_from_crit_count(_current_crit_count, 0.0)\n\n#\tNOTE: emit attack event only for the \"first\" target so\n#\tthat if the tower has multishot ability, the attack\n#\tevent is emitted only once per series of attacks. This\n#\tis the way it works in original game.\n\tif target_is_first:\n\t\tvar attack_event: Event = Event.new(target)\n\t\tattack_event._number_of_crits = _current_crit_count\n\t\tattack.emit(attack_event)\n\n#\tNOTE: process crit bonuses after attack event so that if\n#\tany attack event handlers added crit bonuses, we apply\n#\tthese bonuses to current attack.\n\t_current_crit_count += _bonus_crit_count_for_next_attack\n\t_bonus_crit_count_for_next_attack = 0\n\n\t_current_crit_damage += _bonus_crit_ratio_for_next_attack\n\t_bonus_crit_ratio_for_next_attack = 0.0\n\n#\tNOTE: handlers for attack event may order the tower to\n#\tstop attacking or switch to a different target. Process\n#\tthe orders here.\n\tif _was_ordered_to_stop_attack:\n\t\treturn target\n\n\tif _was_ordered_to_change_target:\n\t\t_was_ordered_to_change_target = false\n\n\t\tvar new_target_is_valid: bool = Utils.unit_is_valid(_new_target_from_order)\n\t\tif new_target_is_valid:\n\t\t\ttarget = _new_target_from_order\n\n\tvar attacked_event: Event = Event.new(self)\n\tattacked_event._number_of_crits = _current_crit_count\n\ttarget.attacked.emit(attacked_event)\n\n\tvar tower_pos: Vector3 = get_position_wc3()\n\tvar projectile: Projectile = _make_projectile(tower_pos, target)\n\tprojectile.set_tower_crit_count(_current_crit_count)\n\tprojectile.set_tower_crit_ratio(_current_crit_damage)\n\n#\tNOTE: need to save some variables to be used later when\n#\tprojectile reaches target\n\tif _attack_style == AttackStyle.BOUNCE:\n\t\tvar randomize_damage: bool = true\n\t\tvar damage: float = get_current_attack_damage_with_bonus(randomize_damage)\n\t\tvar current_bounce_index: int = 0\n\n\t\tprojectile.user_real = damage\n\t\tprojectile.user_int = current_bounce_index\n\telif _attack_style == AttackStyle.NORMAL:\n\t\tif target_is_first:\n\t\t\tprojectile.user_int2 = 1\n\t\telse:\n\t\t\tprojectile.user_int2 = 0\n\n\tvar element: Element.enm = get_element()\n\tvar sfx_path: String = SfxPaths.TOWER_ATTACK_MAP[element]\n\tvar random_pitch: float = Globals.local_rng.randf_range(1.0, 1.1)\n\tSFX.sfx_at_unit(sfx_path, self, 0.0, random_pitch)\n\n\treturn target\n\n\nfunc _update_target_list():\t\n# \tNOTE: need to extend attack range by \"tower radius\".\n# \tThis is how it works in the original game.\n\tvar attack_range: float = get_range() + Constants.RANGE_CHECK_BONUS_FOR_TOWERS\n\n#\tNOTE: get_units_in_range() is one of the most expensive\n#\tcalls in the gameplay logic. Call it here once right\n#\tbefore attacking and no more.\n\tvar creeps_in_range: Array = Utils.get_units_in_range(self, _attack_target_type, get_position_wc3_2d(), attack_range)\n\n# \tNOTE: need to consider tower to be in combat if there\n# \tare *any* creeps in attack range, even if the tower is\n# \tnot able to attack for whatever reason. This is so that\n# \ttowers use their offensive abilities and items as\n# \texpected.\n\t_is_in_combat = !creeps_in_range.is_empty()\n\n#\tRemove targets that have become invalid. Targets can\n#\tbecome invalid for multiple reasons: moving out of\n#\trange, dying and other.\n\tvar removed_target_list: Array = []\n\n\tfor target in _target_list:\n\t\tvar target_is_valid: bool = _target_is_valid(target)\n\n\t\tif !target_is_valid:\n\t\t\tremoved_target_list.append(target)\n\n\tfor target in removed_target_list:\n\t\t_remove_target(target)\n\n# \tRemove targets if target list size is too large. For\n# \texample, if a tower ability temporarily increased target\n# \tcount to 3 and then it went back down to 1.\n\twhile _target_list.size() > get_target_count():\n\t\tvar target = _target_list.back()\n\t\t_remove_target(target)\n\n# \tAdd new targets that have entered into range\n\tUtils.sort_creep_list_for_targeting(creeps_in_range, get_position_wc3_2d())\n\n\tfor target in _target_list:\n\t\tcreeps_in_range.erase(target)\n\n\twhile creeps_in_range.size() > 0 && _target_list.size() < get_target_count():\n\t\tvar new_target: Creep = creeps_in_range.pop_front()\n\t\tvar target_is_valid: bool = _target_is_valid(new_target)\n\n\t\tif target_is_valid:\n\t\t\t_add_target(new_target)\n\n\nfunc _add_target(target: Creep):\n\tif _target_list.has(target):\n\t\treturn\n\n\t_target_list.append(target)\n\ttarget.tree_exited.connect(_on_target_tree_exited.bind(target))\n\n\n# NOTE: arg needs to be untyped because it may be an invalid\n# instance.\nfunc _remove_target(target):\n\tif !_target_list.has(target):\n\t\treturn\n\n\tif is_instance_valid(target):\n\t\ttarget.tree_exited.disconnect(_on_target_tree_exited)\n\n\t_target_list.erase(target)\n\n\nfunc _get_next_bounce_target(bounce_pos: Vector3, visited_list: Array[Unit]) -> Creep:\n\tvar bounce_pos_2d: Vector2 = Vector2(bounce_pos.x, bounce_pos.y)\n\tvar creep_list: Array = Utils.get_units_in_range(self, _attack_target_type, bounce_pos_2d, Constants.BOUNCE_ATTACK_RANGE)\n\n\tfor visited_creep in visited_list:\n\t\tif !Utils.unit_is_valid(visited_creep):\n\t\t\tcontinue\n\n\t\tcreep_list.erase(visited_creep)\n\n\tUtils.sort_unit_list_by_distance(creep_list, bounce_pos_2d)\n\n\tif !creep_list.is_empty():\n\t\tvar next_target = creep_list[0]\n\n\t\treturn next_target\n\telse:\n\t\treturn null\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_selected_changed():\n\t_range_indicator_parent.visible = is_selected()\n\n\nfunc _on_target_tree_exited(target: Creep):\n\t_remove_target(target)\n\n\nfunc _on_item_container_items_changed():\n\titems_changed.emit()\n\n\nfunc _on_mana_changed():\n\tvar mana_ratio: float = get_mana_ratio()\n\t_mana_bar.ratio = mana_ratio\n\n\nfunc _on_projectile_target_hit(projectile: Projectile, target: Unit):\n\tmatch _attack_style:\n\t\tAttackStyle.NORMAL:\n\t\t\t_on_projectile_target_hit_normal(projectile, target)\n\t\tAttackStyle.SPLASH:\n\t\t\t_on_projectile_target_hit_splash(projectile, target)\n\t\tAttackStyle.BOUNCE:\n\t\t\t_on_projectile_target_hit_bounce(projectile, target)\n\n\n# NOTE: only the first target is considered to be the \"main\n# target\" in case of multishot. This is how it works in\n# original game.\nfunc _on_projectile_target_hit_normal(projectile: Projectile, target: Unit):\n\tvar randomize_damage: bool = true\n\tvar damage: float = get_current_attack_damage_with_bonus(randomize_damage)\n\tvar target_is_first: bool = projectile.user_int2 == 1\n\tvar is_main_target: bool = target_is_first\n\t\n\t_do_damage_from_projectile(projectile, target, damage, is_main_target)\n\n\nfunc _on_projectile_target_hit_splash(projectile: Projectile, main_target: Unit):\n\tif _splash_map.is_empty():\n\t\treturn\n\n\tvar randomize_damage: bool = true\n\tvar damage: float = get_current_attack_damage_with_bonus(randomize_damage)\n\tvar is_main_target: bool = true\n\n\t_do_damage_from_projectile(projectile, main_target, damage, is_main_target)\n\n\tvar splash_pos: Vector2\n\tif main_target != null:\n\t\tsplash_pos = main_target.get_position_wc3_2d()\n\telse:\n\t\tsplash_pos = projectile.get_position_wc3_2d()\n\n#\tProcess splash ranges from closest to furthers,\n#\tso that strongest damage is applied\n\tvar splash_range_list: Array = _splash_map.keys()\n\tsplash_range_list.sort()\n\n\tvar splash_range_max: float = splash_range_list.back()\n\n\tvar creep_list: Array = Utils.get_units_in_range(self, _attack_target_type, splash_pos, splash_range_max)\n\n\tif main_target != null:\n\t\tcreep_list.erase(main_target)\n\n\tfor neighbor in creep_list:\n#\t\tNOTE: need to check validity because splash attack\n#\t\tmay trigger an exploding creep ability which will\n#\t\tkill other splash attack targets before they are\n#\t\tprocessed.\n\t\tif !Utils.unit_is_valid(neighbor):\n\t\t\tcontinue\n\n\t\tvar neighbor_pos: Vector2 = neighbor.get_position_wc3_2d()\n\t\tvar distance: float = splash_pos.distance_to(neighbor_pos)\n\n\t\tfor splash_range in splash_range_list:\n\t\t\tvar creep_is_in_range: bool = distance < splash_range\n\n\t\t\tif creep_is_in_range:\n\t\t\t\tvar splash_damage_ratio: float = _splash_map[splash_range]\n\t\t\t\tvar splash_damage: float = damage * splash_damage_ratio\n\t\t\t\tvar splash_is_main_target: bool = false\n\t\t\t\t_do_damage_from_projectile(projectile, neighbor, splash_damage, splash_is_main_target)\n\n\t\t\t\tbreak\n\n\nfunc _on_projectile_target_hit_bounce(projectile: Projectile, current_target: Unit):\n\tvar current_damage: float = projectile.user_real\n\tvar current_bounce_index: int = projectile.user_int\n\tvar bounce_visited_list: Array[Unit] = projectile.get_tower_bounce_visited_list()\n\tif current_target != null:\n\t\tbounce_visited_list.append(current_target)\n\n\tvar is_first_bounce: bool = current_bounce_index == 0\n\tvar is_main_target: bool = is_first_bounce\n\n\tvar bounce_pos: Vector3\n\tif current_target != null:\n\t\tbounce_pos = current_target.get_position_wc3()\n\telse:\n\t\tbounce_pos = projectile.get_position_wc3()\n\n\t_do_damage_from_projectile(projectile, current_target, current_damage, is_main_target)\n\n# \tLaunch projectile for next bounce, if bounce isn't over\n\tvar bounce_end: bool = current_bounce_index == _bounce_count_max - 1\n\n\tif bounce_end:\n\t\treturn\n\n\tvar next_damage: float = current_damage * (1.0 - _bounce_damage_multiplier)\n\n\tvar next_target: Creep = _get_next_bounce_target(bounce_pos, bounce_visited_list)\n\n\tif !Utils.unit_is_valid(next_target):\n\t\treturn\n\n\tvar next_projectile: Projectile = _make_projectile(bounce_pos, next_target)\n\tnext_projectile.user_real = next_damage\n\tnext_projectile.user_int = current_bounce_index + 1\n\tnext_projectile._tower_bounce_visited_list = bounce_visited_list\n#\tNOTE: save crit count in projectile so that it can be\n#\tused when projectile reaches the target to calculate\n#\tdamage\n\tnext_projectile.set_tower_crit_count(projectile.get_tower_crit_count())\n\tnext_projectile.set_tower_crit_ratio(projectile.get_tower_crit_ratio())\n\n\n#########################\n### Setters / Getters ###\n#########################\n\n# Makes all future attack projectiles invisible. Useful in\n# rare cases.\nfunc hide_attack_projectiles():\n\t_hide_attack_projectiles = true\n\n\n# This f-n changes how many targets the tower can attack at\n# the same time. Note that the default value of this\n# property is loaded from tower properties CSV when tower is\n# created. After that, if this f-n is called from tower\n# script the original value is overwritten.\nfunc set_target_count(count: int):\n\t_target_count_from_tower = count\n\n\nfunc set_target_count_from_item(count: int):\n\t_target_count_from_item = count\n\n\nfunc get_target_count_from_item() -> int:\n\treturn _target_count_from_item\n\n\n# NOTE: tower.getTargetCount() in JASS\nfunc get_target_count() -> int:\n\treturn _target_count_from_tower + _target_count_from_item\n\n\n# Tower is attacking while it has valid targets in range.\n# NOTE: for towers which don't attack, the target list is\n# always empty, so treat such towers as always attacking.\n# This is to ensure that items with offensive autocasts\n# still get triggered when equipped on such towers.\nfunc is_in_combat() -> bool:\n\treturn _is_in_combat\n\n\n# NOTE: tower.countFreeSlots() in JASS\nfunc count_free_slots() -> int:\n\tvar item_count: int = _item_container.get_item_count()\n\tvar capacity: int = _item_container.get_capacity()\n\tvar free_slots = capacity - item_count\n\n\treturn free_slots\n\n\n# NOTE: tower.haveItemSpace() in JASS\nfunc have_item_space() -> bool:\n\treturn _item_container.have_item_space()\n\n\nfunc get_oils() -> Array[Item]:\n\treturn _item_container.get_oil_list()\n\n\nfunc get_items() -> Array[Item]:\n\treturn _item_container.get_item_list()\n\n\nfunc get_item_count() -> int:\n\treturn _item_container.get_item_count()\n\n\n# NOTE: slot_number starts at 1 instead of 0\n# NOTE: tower.getHeldItem() in JASS\nfunc get_held_item(slot_number: int) -> Item:\n\tvar slot_index: int = slot_number - 1\n\treturn _item_container.get_item_at_index(slot_index)\n\n\nfunc get_item_tower_details() -> Array[MultiboardValues]:\n\tvar out: Array[MultiboardValues] = []\n\n\tvar item_list: Array[Item] = _item_container.get_item_list()\n\t\n\tfor item in item_list:\n\t\tvar board: MultiboardValues = item.on_tower_details()\n\n\t\tif board != null:\n\t\t\tout.append(board)\n\n\treturn out\n\n\nfunc get_log_name() -> String:\n\treturn get_display_name()\n\n\nfunc get_item_container() -> ItemContainer:\n\treturn _item_container\n\n\nfunc get_ability_button_data_list() -> Array[AbilityButton.Data]:\n\tvar list: Array[AbilityButton.Data] = []\n\n\tvar tower_id: int = get_id()\n\n\tvar attack_enabled: bool = TowerProperties.get_attack_enabled(get_id())\n\tif attack_enabled:\n\t\tvar attack_ability: AbilityButton.Data = AbilityButton.Data.new()\n\t\tvar attack_description: String = _get_attack_ability_description()\n\t\tattack_ability.name_english = Constants.TOWER_ATTACK_ABILITY_NAME_ENGLISH\n\t\tattack_ability.ability_name = tr(\"TOWER_ATTACK_ABILITY_TITLE\")\n\t\tattack_ability.icon = \"res://resources/icons/rockets/rocket_01.tres\"\n\t\tattack_ability.description_long = attack_description\n\t\tlist.append(attack_ability)\n\n\tvar specials_description: String = RichTexts.get_tower_specials_text(tower_id)\n\tif !specials_description.is_empty():\n\t\tvar specials: AbilityButton.Data = AbilityButton.Data.new()\n\t\tspecials.ability_name = tr(\"TOWER_SPECIALS_TITLE\")\n\t\tspecials.icon = \"res://resources/icons/rockets/rocket_04.tres\"\n\t\tspecials.description_long = specials_description\n\t\tlist.append(specials)\n\n\tif _attack_style == AttackStyle.SPLASH:\n\t\tvar splash_attack: AbilityButton.Data = AbilityButton.Data.new()\n\t\tsplash_attack.ability_name = tr(\"TOWER_SPLASH_ATTACK_TITLE\")\n\t\tsplash_attack.icon = \"res://resources/icons/rockets/rocket_05.tres\"\n\t\tvar splash_attack_text: String = RichTexts.get_tower_splash_attack_text(tower_id)\n\t\tsplash_attack.description_long = splash_attack_text\n\t\tlist.append(splash_attack)\n\n\tif _attack_style == AttackStyle.BOUNCE:\n\t\tvar bounce_attack: AbilityButton.Data = AbilityButton.Data.new()\n\t\tbounce_attack.ability_name = tr(\"TOWER_BOUNCE_ATTACK_TITLE\")\n\t\tbounce_attack.icon = \"res://resources/icons/daggers/dagger_09.tres\"\n\t\tvar bounce_attack_text: String = RichTexts.get_tower_bounce_attack_text(tower_id)\n\t\tbounce_attack.description_long = bounce_attack_text\n\t\tlist.append(bounce_attack)\n\n#\tNOTE: need to use _target_count_from_tower without\n#\tadding _target_count_from_item so that item's bonus is\n#\tnot displayed in tower info.\n\tif _target_count_from_tower > 1:\n\t\tvar multishot: AbilityButton.Data = AbilityButton.Data.new()\n\t\tmultishot.ability_name = tr(\"TOWER_MULTISHOT_TITLE\")\n\t\tmultishot.icon = \"res://resources/icons/spears/many_spears_01.tres\"\n\t\tvar multishot_tooltip: String = RichTexts.get_tower_multishot_text(tower_id)\n\t\tmultishot.description_long = multishot_tooltip\n\t\tlist.append(multishot)\n\n\treturn list\n\n\nfunc get_current_target() -> Unit:\n\tif !_target_list.is_empty():\n\t\tvar target: Unit = _target_list.front()\n\n#\t\tNOTE: need to check validity here because target may\n#\t\tbe in list but become invalid because it just died\n\t\tif Utils.unit_is_valid(target):\n\t\t\treturn target\n\t\telse:\n\t\t\treturn null\n\telse:\n\t\treturn null\n\n\n# NOTE: this must be called once after the tower is created\n# but before it's added to game scene\nfunc set_id(id: int):\n\t_id = id\n\n\nfunc get_id() -> int:\n\treturn _id\n\n\nfunc get_tier() -> int:\n\treturn TowerProperties.get_tier(_id)\n\n# NOTE: tower.getFamily() in JASS\nfunc get_family() -> int:\n\treturn TowerProperties.get_family(_id)\n\n\n# NOTE: tower.getElement() in JASS\nfunc get_element() -> Element.enm:\n\treturn TowerProperties.get_element(_id)\n\n\n# This is the base time between tower attacks, before\n# applying modifications. Do not confuse this value with\n# MOD_ATTACKSPEED.\n# attack speed = time in seconds\n# MOD_ATTACKSPEED = multiplier which reduces/increases the time\n# NOTE: tower.getBaseAttackspeed() in JASS\nfunc get_base_attack_speed() -> float:\n\treturn TowerProperties.get_base_attack_speed(_id)\n\n# This is the actual time between tower attacks, after\n# applying modifications.\n# Example: If the base attack speed is 2.0 seconds and the\n# tower has 1.25 attack speed, then the real attack cooldown\n# will be 2.0/1.25 == 1.6 seconds.\n# NOTE: tower.getCurrentAttackSpeed() in JASS\nfunc get_current_attack_speed() -> float:\n\tvar attack_speed: float = get_base_attack_speed()\n\tvar attack_speed_mod: float = get_attack_speed_modifier()\n\tvar current_attack_speed: float = attack_speed / attack_speed_mod\n\n\treturn current_attack_speed\n\n\nfunc get_remaining_cooldown() -> float:\n\treturn max(0, _current_attack_cooldown)\n\nfunc get_damage_min() -> int:\n\treturn TowerProperties.get_damage_min(_id)\n\nfunc get_damage_max() -> int:\n\treturn TowerProperties.get_damage_max(_id)\n\n# Returns the base damage, without bonuses to base damage\n# NOTE: tower.getBaseDamage() in JASS\nfunc get_base_damage() -> int:\n\treturn TowerProperties.get_base_damage(_id)\n\n\n# NOTE: this value is sum of MOD_DAMAGE_ADD and bonus\n# derived from MOD_DPS_ADD. Doesn't include\n# MOD_DAMAGE_ADD_PERC.\nfunc get_damage_add_overall() -> float:\n\tvar damage_add: float = get_damage_add()\n\tvar dps_bonus: float = get_dps_bonus()\n\tvar base_attack_speed: float = get_base_attack_speed()\n\tvar dps_mod: float = dps_bonus * base_attack_speed\n\tvar result: float = damage_add + dps_mod\n\n\treturn result\n\n\n# Returns base damage, including bonuses to base damage\n# NOTE: tower.getCurrentAttackDamageBase() in JASS\nfunc get_current_attack_damage_base() -> float:\n\tvar base_damage: float = get_base_damage()\n\tvar base_bonus: float = get_base_damage_bonus()\n\tvar base_bonus_percent: float = get_base_damage_bonus_percent()\n\tvar base_damage_with_bonus: float = (base_damage + base_bonus) * base_bonus_percent\n\n\treturn base_damage_with_bonus\n\n\n# NOTE: by default this value is based on the average of\n# tower's min and max damage. When tower is calculating\n# attack damage, the randomize_damage arg is set to true so\n# that this f-n returns random value between min and max.\n# NOTE: tower.getCurrentAttackDamageWithBonus() in JASS\nfunc get_current_attack_damage_with_bonus(randomize_damage: bool = false) -> float:\n\tvar base_damage: float\n\tvar damage_min: float = get_damage_min()\n\tvar damage_max: float = get_damage_max()\n\tif randomize_damage:\n\t\tbase_damage = Globals.synced_rng.randf_range(damage_min, damage_max)\n\telse:\n\t\tbase_damage = floori((damage_min + damage_max) / 2)\n\n\tvar base_bonus: float = get_base_damage_bonus()\n\tvar base_bonus_percent: float = get_base_damage_bonus_percent()\n\tvar damage_add_total: float = get_damage_add_overall()\n\tvar damage_add_percent: float = get_damage_add_percent()\n\n\tvar overall_base_damage: float = (base_damage + base_bonus) * base_bonus_percent\n\tvar overall_damage: float = (overall_base_damage + damage_add_total) * damage_add_percent\n\n\toverall_damage = max(0, overall_damage)\n\n\treturn overall_damage\n\n\n# How much damage the tower deals with its attack per second on average (not counting in any crits). \nfunc get_overall_dps() -> float:\n\tvar damage: float = get_current_attack_damage_with_bonus()\n\tvar attack_speed: float = get_current_attack_speed()\n\tvar dps: float = damage / attack_speed\n\n\treturn dps\n\n\n# How much damage the tower deals with its attack per second on average when \n# counting attack crits and multicrits.\nfunc get_dps_with_crit() -> float:\n\t# Extra crit damage per successful crit:\n\t# if crit_damage = 1.5x, then extra = 0.5\n\tvar extra_per_crit: float = get_prop_atk_crit_damage() - 1.0\n\t\n\t# Loop parameters\n\tvar remaining_multicrits: int = get_prop_multicrit_count()      # M\n\tvar current_crit_chance: float = get_prop_atk_crit_chance()     # initial p_1\n\n\t# Probability that the chain survives to stage k (P[crits ≥ k])\n\tvar chain_prob_at_least_k: float = 1.0\n\n\t# Expected crit multiplier:\n\t# E[multiplier] = 1 + extra * Σ_{k=1..M} P(crits ≥ k)\n\tvar expected_crit_multiplier: float = 1.0\n\n\twhile remaining_multicrits > 0:\n\t\t# Compute effective crit probability for this stage, clamped to cap\n\t\t# and update chain -> probability of reaching at least this stage\n\t\tchain_prob_at_least_k *= clampf(current_crit_chance, 0.0, Constants.ATK_CRIT_CHANCE_CAP)\n\n\t\t# Add contribution of this stage\n\t\texpected_crit_multiplier += extra_per_crit * chain_prob_at_least_k\n\n\t\t# Prepare for next stage: diminish chance\n\t\tcurrent_crit_chance *= Constants.ATK_MULTICRIT_DIMISHING\n\t\tremaining_multicrits -= 1\n\n\tvar dps: float = get_overall_dps()\n\tvar dps_with_crit: float = dps * expected_crit_multiplier\n\t\n\treturn dps_with_crit\n\n\n# How much damage the tower dealt in total\n# NOTE: getOverallDamage() in JASS, renamed to avoid confusion\nfunc get_total_damage() -> float:\n\treturn _damage_dealt_total\n\t\nfunc get_total_damage_by_type(damage_source: DamageSource = DamageSource.Attack) -> float:\n\tif damage_source == DamageSource.Attack:\n\t\treturn _attack_damage_dealt\n\tif damage_source == DamageSource.Spell:\n\t\treturn _spell_damage_dealt\n\treturn 0.0\n\n# How much damage the tower dealt in total, during last 5 waves\nfunc get_total_damage_recent(use_damage_source: bool = false, damage_source: DamageSource = DamageSource.Attack) -> float:\n\tvar total_damage_recent: float = 0\n\t\n\tvar team: Team = _player.get_team()\n\tvar current_wave_level: int = team.get_level()\n\t\n\tvar damage_dealt_to_wave_map: Dictionary = _damage_dealt_to_wave_map\n\tif use_damage_source and damage_source == DamageSource.Attack:\n\t\tdamage_dealt_to_wave_map = _attack_damage_dealt_to_wave_map\n\tif use_damage_source and damage_source == DamageSource.Spell:\n\t\tdamage_dealt_to_wave_map = _spell_damage_dealt_to_wave_map\n\t\t\n\tfor i in range(current_wave_level, current_wave_level - 5, -1):\n\t\tvar damage_to_wave: float = damage_dealt_to_wave_map.get(i, 0)\n\t\ttotal_damage_recent += damage_to_wave\n\t\n\treturn total_damage_recent\n\n# How much kills the tower has in total\nfunc get_kills() -> int:\n\treturn _kill_count\n\n# What was the max hit damage the tower dealt\nfunc get_best_hit() -> float:\n\treturn _best_hit\n\nfunc get_base_range() -> float:\n\treturn TowerProperties.get_range(_id)\n\n# NOTE: tower.getRange() in JASS\nfunc get_range() -> float:\n\tvar original_range: float = get_base_range()\n\tvar player: Player = get_player()\n\tvar builder: Builder = player.get_builder()\n\tvar builder_range_bonus: float = builder.get_range_bonus()\n\tvar attack_range_bonus: float = player.get_attack_range_bonus()\n\tvar total_range: float = original_range + builder_range_bonus + attack_range_bonus\n\n\treturn total_range\n\n\n# NOTE: tower.getRarity() in JASS\nfunc get_rarity() -> Rarity.enm:\n\treturn TowerProperties.get_rarity(_id)\n\t\nfunc get_display_name() -> String:\n\treturn TowerProperties.get_display_name(_id)\n\n# NOTE: tower.getAttackType() in JASS\nfunc get_attack_type() -> AttackType.enm:\n\treturn TowerProperties.get_attack_type(_id)\n\n# NOTE: tower.getGoldCost() in JASS\nfunc get_gold_cost() -> int:\n\treturn TowerProperties.get_cost(_id)\n\nfunc get_inventory_capacity() -> int:\n\tvar original_capacity: int = TowerProperties.get_inventory_capacity(_id)\n\tvar builder: Builder = get_player().get_builder()\n\tvar builder_item_slots_bonus: int = builder.get_item_slots_bonus()\n\tvar total_capacity: int = original_capacity + builder_item_slots_bonus\n\ttotal_capacity = clampi(total_capacity, 1, Constants.INVENTORY_CAPACITY_MAX)\n\n\treturn total_capacity\n\nfunc get_attack_enabled() -> bool:\n\treturn TowerProperties.get_attack_enabled(_id)\n\n\n#########################\n###       Static      ###\n#########################\n\n# Return new unique instance of the Tower by its ID. Get\n# script for tower and attach to scene. Script name matches\n# with scene name so this can be done automatically instead\n# of having to do it by hand in scene editor.\nstatic func make(id: int, player: Player, preceding_tower: Tower = null) -> Tower:\n\tvar tower: Tower = Preloads.tower_scene.instantiate()\n\tvar script_path: String = TowerProperties.get_script_path(id)\n\tvar tower_behavior_script: Script = load(script_path)\n\tvar tower_behavior: TowerBehavior = tower_behavior_script.new()\n\ttower._tower_behavior = tower_behavior\n\ttower.add_child(tower_behavior)\n\tvar tower_sprite: Sprite2D = TowerSprites.get_sprite(id)\n\tvar visual_node: Node2D = tower.get_node(\"Visual\")\n\tvar sprite_parent_node: Node2D = tower.get_node(\"Visual/SpriteParent\")\n\t\n\tif visual_node == null:\n\t\tpush_error(\"visual node is null\")\n\t\t\n\t\treturn null\n\n\tsprite_parent_node.add_child(tower_sprite)\n\ttower._sprite = tower_sprite\n\t\n\ttower._temp_preceding_tower = preceding_tower\n\n\ttower.set_id(id)\n\ttower.set_player(player)\n\n\treturn tower\n"
  },
  {
    "path": "src/towers/tower.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://1vlynice43b0\"]\n\n[ext_resource type=\"Script\" path=\"res://src/towers/tower.gd\" id=\"2\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://cefr72vfj04ja\" path=\"res://resources/theme/unit_menu/mana_bar_background.tres\" id=\"2_35wpd\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://rku7yxxl0iit\" path=\"res://resources/theme/unit_menu/mana_bar_fill.tres\" id=\"3_vryaj\"]\n\n[node name=\"Tower\" type=\"Node2D\" node_paths=PackedStringArray(\"_mana_bar\", \"_tower_selection_area\", \"_visual\", \"_range_indicator_parent\", \"_sprite_parent\")]\nscript = ExtResource(\"2\")\n_mana_bar = NodePath(\"Visual/ManaBar\")\n_tower_selection_area = NodePath(\"Visual/TowerSelectionArea\")\n_visual = NodePath(\"Visual\")\n_range_indicator_parent = NodePath(\"Visual/RangeIndicatorParent\")\n_sprite_parent = NodePath(\"Visual/SpriteParent\")\n\n[node name=\"Visual\" type=\"Node2D\" parent=\".\"]\nz_index = 1\n\n[node name=\"SpriteParent\" type=\"Node2D\" parent=\"Visual\"]\n\n[node name=\"TowerSelectionArea\" type=\"Area2D\" parent=\"Visual\"]\nmonitoring = false\nmonitorable = false\n\n[node name=\"CollisionPolygon2D\" type=\"CollisionPolygon2D\" parent=\"Visual/TowerSelectionArea\"]\npolygon = PackedVector2Array(-102, 6, 0, 56, 102, 6, 102, -96, 0, -147, -102, -96)\n\n[node name=\"ManaBar\" type=\"ProgressBar\" parent=\"Visual\"]\neditor_description = \"NOTE: z index is 1 because Unit.gd sets z index of outline to 1\"\nz_index = 1\noffset_left = -75.0\noffset_right = 75.0\noffset_bottom = 20.0\nmouse_filter = 2\ntheme_override_styles/background = ExtResource(\"2_35wpd\")\ntheme_override_styles/fill = ExtResource(\"3_vryaj\")\nvalue = 30.0\nshow_percentage = false\nmetadata/_edit_use_anchors_ = true\n\n[node name=\"RangeIndicatorParent\" type=\"Node2D\" parent=\"Visual\"]\nvisible = false\n\n[connection signal=\"selected_changed\" from=\".\" to=\".\" method=\"_on_selected_changed\"]\n"
  },
  {
    "path": "src/towers/tower_behavior.gd",
    "content": "class_name TowerBehavior extends Node\n\n\n# TowerBehavior is used to implement behavior for a\n# particular tower. Each tower family has it's own\n# TowerBehavior script which is attached to Tower base class\n# to create a complete tower.\n\n\nvar tower: Tower\nvar _stats: Dictionary = {}\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc init(tower_arg: Tower, preceding_tower: Tower):\n\ttower = tower_arg\n\n# \tLoad stats for current tier. Stats are defined in\n# \tsubclass.\n\tvar tier: int = tower.get_tier()\n\tvar stats_for_all_tiers: Dictionary = get_tier_stats()\n\tif stats_for_all_tiers.has(tier):\n\t\t_stats = stats_for_all_tiers[tier]\n\telse:\n\t\t_stats = {}\n\n#\tNOTE: need to call load_triggers() after loading stats\n#\tbecause stats must be available in load_triggers().\n\tvar triggers_bt: BuffType = BuffType.new(\"triggers_bt\", 0, 0, true, self)\n\ttriggers_bt.set_hidden()\n\ttriggers_bt.disable_stacking_behavior()\n\ttriggers_bt.set_buff_tooltip(\"DEBUG Triggers buff for tower\")\n\tload_triggers(triggers_bt)\n\ttriggers_bt.apply_to_unit_permanent(tower, tower, 0)\n\n\ttower_init()\n\n#\tNOTE: must setup auras and autocasts after calling\n#\ttower_init() because some auras and autocasts use buff\n#\ttypes which are initialized inside tower_init().\n\tvar tower_id: int = tower.get_id()\n\tvar aura_id_list: Array = TowerProperties.get_aura_id_list(tower_id)\n\tfor aura_id in aura_id_list:\n\t\ttower.add_aura(aura_id, self)\n\n\tvar autocast_id_list: Array = TowerProperties.get_autocast_id_list(tower_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast: Autocast = Autocast.make(autocast_id, self)\n\t\ttower.add_autocast(autocast)\n\n\ton_create(preceding_tower)\n\n\n# Override in subclass to define custom stats for each tower\n# tier. Access as _stats.\nfunc get_tier_stats() -> Dictionary:\n\treturn {}\n\n\n# Override in subclass to attach trigger handlers to\n# triggers buff passed in the argument.\nfunc load_triggers(_triggers_bt: BuffType):\n\tpass\n\n\n# Override in subclass to initialize tower.\n# NOTE: do NOT use _init() function - that's a native Godot\n# function and it's called too early which will make some\n# variables unavailable.\n# NOTE: tower.init() in JASS\nfunc tower_init():\n\tpass\n\t\n\n# NOTE: tower.onCreate() in JASS\nfunc on_create(_preceding_tower: Tower):\n\tpass\n\n\n# NOTE: tower.onDestruct() in JASS\nfunc on_destruct():\n\tpass\n\n\n# NOTE: tower.onTowerDetails() in JASS\nfunc on_tower_details() -> MultiboardValues:\n\tvar empty_multiboard: MultiboardValues = MultiboardValues.new(0)\n\n\treturn empty_multiboard\n\n\nfunc get_tower() -> Tower:\n\treturn tower\n"
  },
  {
    "path": "src/towers/tower_behavior_template.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: this script can be used as a template for tower\n# behavior scripts.\n\n\n# var example_bt: BuffType\n# var example_pt: ProjectileType\n# var multiboard: MultiboardValues\n\n\n# func get_tier_stats() -> Dictionary:\n# \treturn {\n# \t\t1: {foo = 123},\n# \t\t2: {foo = 123},\n# \t\t3: {foo = 123},\n# \t}\n\n\n# func load_triggers(triggers: BuffType):\n# \ttriggers.add_event_on_damage(on_damage)\n\n\n# func tower_init():\n# \texample_bt = BuffType.new(\"example_bt\", 5, 0, true, self)\n# \tvar example_bt_mod: Modifier = Modifier.new()\n# \texample_bt_mod.add_modification(ModificationType.enm.MOD_ARMOR, 0.0, 0.0)\n# \texample_bt.set_buff_modifier(example_bt_mod)\n# \texample_bt.set_buff_icon(\"res://resources/icons/generic_icons/egg.tres\")\n# \texample_bt.set_buff_icon_color(Color.WHITE)\n# \texample_bt.set_buff_tooltip(tr(\"TRANSLATION_ID_GOES_HERE\"))\n\n#\texample_pt = ProjectileType.create(\"path_to_projectile_sprite\", 0, 1000, self)\n#\texample_pt.enable_homing(example_pt_on_hit, 0)\n\n#\tmultiboard = MultiboardValues.new(2)\n#\tvar foo_label: String = tr(\"XYZW\")\n#\tmultiboard.set_key(0, foo_label)\n\n\n# func on_damage(event: Event):\n#\tpass\n\n\n# func on_autocast(event: Event):\n#\tpass\n\n\n# func on_tower_details() -> MultiboardValues:\n# \tmultiboard.set_value(0, \"Foo value\")\n\n# \treturn multiboard\n\n\n# func example_pt_on_hit(p: Projectile, target: Unit):\n# \tif target == null:\n# \t\treturn\n\n# \ttower.do_spell_damage(target, 123, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/afflicted_obelisk.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: it may look wrong that the parasite buff has\n# \"friendly\" property set to true but it doesn't matter\n# because this buff is only for visual purposes. Leave it as\n# is and do not change this.\n\n\nvar parasite_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {vuln_value = 0.025, vuln_value_add = 0.0005},\n\t\t2: {vuln_value = 0.030, vuln_value_add = 0.0006},\n\t\t3: {vuln_value = 0.035, vuln_value_add = 0.0007},\n\t\t4: {vuln_value = 0.040, vuln_value_add = 0.0008},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tparasite_bt = BuffType.new(\"parasite_bt\", 0, 0, true, self)\n\tparasite_bt.set_buff_icon(\"res://resources/icons/generic_icons/amber_mosquito.tres\")\n\tparasite_bt.set_buff_tooltip(tr(\"DCFN\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n#\tNOTE: need to divide by tower's buff duration because\n#\tduration will later be multiplied by tower's buff\n#\tduration, when buff is applied. Final result will be\n#\tthat duration is 3 seconds.\n\tparasite_bt.apply_custom_timed(tower, target, 0, 3.0 / tower.get_prop_buff_duration())\n\ttarget.modify_property(ModificationType.enm.MOD_DMG_FROM_NATURE, _stats.vuln_value + level * _stats.vuln_value_add)\n\n\tawait Utils.create_manual_timer(3.0, self).timeout\n\n\tif Utils.unit_is_valid(target):\n\t\ttower.do_custom_attack_damage(target, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit(0, 0, 0), AttackType.enm.DECAY)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/crypt_fiend_eggsack.tscn\", target)\n\t\ttarget.modify_property(ModificationType.enm.MOD_DMG_FROM_NATURE, -_stats.vuln_value - level * _stats.vuln_value_add)\n"
  },
  {
    "path": "src/towers/tower_behaviors/ancient_energy_converter.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original script is missing the implementation for\n# damage dealt by orbs. It might be implemented as this\n# call: \"p.addAbility('@@0@@')\". Not sure. Wrote an\n# implementation for this ability effect from scratch.\n\n\nvar stun_bt: BuffType\nvar chain_lightning_st: SpellType\nvar orb_pt: ProjectileType\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tchain_lightning_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 5.0, self)\n\tchain_lightning_st.set_damage_event(chain_lightning_st_on_damage)\n\tchain_lightning_st.data.chain_lightning.damage = 1500\n\tchain_lightning_st.data.chain_lightning.damage_reduction = 0.25\n\tchain_lightning_st.data.chain_lightning.chain_count = 4\n\n\torb_pt = ProjectileType.create(\"path_to_projectile_sprite\", 12, 250, self)\n\torb_pt.enable_periodic(orb_pt_periodic, 1.0)\n\n\nfunc on_autocast(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar projectile_count: int = 3 + level / 5\n\n\tvar start_rotation: float = 1.2 * (Globals.synced_rng.randi_range(0, 1) * 2 - 1)\n\torb_pt.set_start_rotation(start_rotation)\n\n\tfor i in range(0, projectile_count):\n\t\tvar p: Projectile = Projectile.create(orb_pt, tower, 1.0 + 0.05 * level, tower.calc_spell_crit_no_bonus(), tower.get_position_wc3(), i * 360 / projectile_count)\n\t\tp.set_projectile_scale(2.0)\n\n\nfunc orb_pt_periodic(p: Projectile):\n\tvar lightning_chance: float = 0.25\n\n\tvar it_for_lightning: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(p.get_x(), p.get_y()), 650.0)\n\n\tvar lightning_target: Unit = it_for_lightning.next_random()\n\n\tif lightning_target != null:\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, p.get_position_wc3(), lightning_target)\n\t\tlightning.modulate = Color.YELLOW\n\t\tlightning.set_lifetime(0.1)\n\n\t\tvar orb_damage: float = 1500 + 75 * tower.get_level()\n\t\ttower.do_spell_damage(lightning_target, orb_damage, tower.calc_spell_crit_no_bonus())\n\n\tif !tower.calc_chance(lightning_chance):\n\t\treturn\n\n\tvar it_for_chain: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(p.get_x(), p.get_y()), 650.0)\n\n\tvar chain_target: Unit = it_for_chain.next()\n\n\tif chain_target != null:\n\t\tchain_lightning_st.target_cast_from_point(tower, chain_target, Vector2(p.get_x(), p.get_y()), p.get_dmg_ratio(), p.get_crit_ratio())\n\n\nfunc chain_lightning_st_on_damage(event: Event, _dummy_unit: DummyUnit):\n\tvar target: Unit = event.get_target()\n\tstun_bt.apply_only_timed(tower, target, 0.8)\n"
  },
  {
    "path": "src/towers/tower_behaviors/annoyed_tree.gd",
    "content": "extends TowerBehavior\n\n\nvar rock_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 150, damage_add = 5, rock_range = 300},\n\t\t2: {damage = 600, damage_add = 20, rock_range = 350},\n\t\t3: {damage = 1200, damage_add = 40, rock_range = 400},\n\t\t4: {damage = 1950, damage_add = 65, rock_range = 450},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc rock_hit(p: Projectile, _target: Unit):\n\tp.do_spell_damage_pb_aoe(_stats.rock_range, _stats.damage + _stats.damage_add * tower.get_level(), 0)\n\tEffect.add_special_effect(\"res://src/effects/impale_target_dust.tscn\", Vector2(p.get_x(), p.get_y()))\n\n\nfunc tower_init():\n\trock_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 750, self)\n\trock_pt.set_event_on_interpolation_finished(rock_hit)\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(0.3 + 0.06 * tower.get_level()):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Rock Thorw\")\n\n\tProjectile.create_linear_interpolation_from_unit_to_unit(rock_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, event.get_target(), 0.25, true)\n"
  },
  {
    "path": "src/towers/tower_behaviors/arcane_storm.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: this script uses chain lightning cast weirdly. It\n# uses it only to create a single chain between two units,\n# doesn't deal damage with them - basically it's a visual\n# only. The reason why is that this tower's ability is\n# supposed to have a chance for each chain jump. Using the\n# chain lighting cast normally would make this not possible\n# because chain lightning cast always jumps up to the\n# defined number of jumps.\n\n# NOTE: changed missile speed in csv for this tower.\n# 5000->9001. This tower uses \"lightning\" projectile visual\n# so slow speed looks weird because it makes the damage\n# delayed compared to the lightning visual.\n\n\nvar attraction_bt: BuffType\nvar manastorm_bt: BuffType\nvar surge_st: SpellType\nvar manastorm_st: SpellType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tattraction_bt = BuffType.new(\"attraction_bt\", -1, 0, false, self)\n\tattraction_bt.set_buff_icon(\"res://resources/icons/generic_icons/star_swirl.tres\")\n\tattraction_bt.set_buff_tooltip(tr(\"M22D\"))\n\tattraction_bt.add_event_on_death(attraction_bt_on_death)\n\n\tmanastorm_bt = BuffType.new(\"manastorm_bt\", 2.0, 0, true, self)\n\tmanastorm_bt.set_buff_icon(\"res://resources/icons/generic_icons/rolling_energy.tres\")\n\tmanastorm_bt.set_buff_tooltip(tr(\"ME8L\"))\n\tvar manastorm_bt_mod: Modifier = Modifier.new()\n\tmanastorm_bt_mod.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 3, 0)\n\tmanastorm_bt.set_buff_modifier(manastorm_bt_mod)\n\n\tsurge_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 1.0, self)\n\tsurge_st.data.chain_lightning.damage = 0\n\tsurge_st.data.chain_lightning.damage_reduction = 0\n\tsurge_st.data.chain_lightning.chain_count = 1\n\tsurge_st.set_source_height(90.0)\n\n\tmanastorm_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 1.0, self)\n\tmanastorm_st.data.chain_lightning.damage = 0\n\tmanastorm_st.data.chain_lightning.damage_reduction = 0\n\tmanastorm_st.data.chain_lightning.chain_count = 1\n\tsurge_st.set_source_height(90.0)\n\n\nfunc on_damage(event: Event):\n\tvar main_target: Unit = event.get_target()\n\tvar chance_per_stack = 0.01 + 0.0002 * tower.get_level()\n\tvar mana: float = tower.get_mana()\n\tvar extra_per: float = 75 - 1 * tower.get_level()\n\tvar extra_attacks: int = 2 + floori(mana / extra_per)\n\tvar original_damage: float = event.damage\n\tvar damage: float = original_damage * (1 + 0.01 * mana)\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), tower.get_range())\n\tvar stacks: int = 0\n\tvar total_stacks: int = 0\n\tvar target: Unit\n\tvar iterate_destroyed: bool = false\n\n\tevent.damage = damage\n\ttower.subtract_mana(mana, true)\n\n\tif mana >= 1:\n\t\tmanastorm_bt.apply(tower, tower, 1)\n\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/holy_bolt.tscn\", tower)\n\t\tEffect.set_color(effect, Color.AQUAMARINE)\n\t\tEffect.set_lifetime(effect, 0.3)\n\n\twhile true:\n\t\tif extra_attacks == 0:\n\t\t\tbreak\n\n\t\tif !iterate_destroyed:\n\t\t\ttarget = it.next_random()\n\n\t\t\tif target == null:\n\t\t\t\titerate_destroyed = true\n\t\t\t\ttarget = main_target\n\n\t\tif iterate_destroyed || target != main_target:\n\t\t\tstacks = ashbringer_attraction_apply(target, 1)\n\n\t\t\tif target != main_target:\n\t\t\t\tmanastorm_st.target_cast_from_caster(tower, target, 0.0, 0.0)\n\t\t\t\ttotal_stacks += stacks\n\n\t\t\t\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\n\t\t\textra_attacks -= 1\n\n\tmanastorm_st.target_cast_from_caster(tower, main_target, 0.0, 0.0)\n\tstacks = ashbringer_attraction_apply(main_target, 1)\n\ttotal_stacks += stacks\n\n\tif tower.calc_chance(stacks * chance_per_stack):\n\t\tashbringer_surge_start(main_target, mana)\n\n\ttower.add_mana(total_stacks)\n\n\nfunc ashbringer_attraction_apply(target: Unit, applied_stacks: int) -> int:\n\tif applied_stacks < 1:\n\t\tapplied_stacks = 1\n\n\tvar buff: Buff = target.get_buff_of_type(attraction_bt)\n\n\tvar active_stacks: int\n\tif buff != null:\n\t\tactive_stacks = buff.user_int\n\telse:\n\t\tactive_stacks = 0\n\n\tvar new_stacks: int = active_stacks + applied_stacks\n\n\tbuff = attraction_bt.apply(tower, target, 1)\n\tbuff.user_int = new_stacks\n\tbuff.set_displayed_stacks(new_stacks)\n\n\treturn new_stacks\n\n\n# NOTE: \"ashbringer_attraction_ondeath()\" in original script\nfunc attraction_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar it_range: float = 500 + 10 * tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, it_range)\n\tvar count: int = it.count()\n\tvar stacks: int = buff.user_int\n\tvar stacks_spare: int = 0\n\tvar stacks_each: int = 0\n\tvar applied: int = 0\n\tvar damage_per_stack: float = tower.get_current_attack_damage_with_bonus() * (0.2 + 0.004 * tower.get_level())\n\n\tCombatLog.log_ability(tower, target, \"Arcane Attraction Death Effect\")\n\n\tif stacks < count:\n\t\tstacks_spare = stacks\n\telse:\n\t\tif count != 0:\n\t\t\tstacks_spare = stacks % count\n\t\t\tstacks_each = (stacks - stacks_spare) / count\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif stacks_spare > 0:\n\t\t\tapplied = stacks_each + 1\n\t\t\tstacks_spare -= -1\n\t\telse:\n\t\t\tapplied = stacks_each\n\n\t\tashbringer_attraction_apply(next, applied)\n\t\tvar damage: float = applied * damage_per_stack\n\t\ttower.do_attack_damage(next, damage, tower.calc_attack_multicrit_no_bonus())\n\t\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/arcane_tower_attack.tscn\", next, Unit.BodyPart.ORIGIN)\n\t\tEffect.set_color(effect, Color.AQUAMARINE)\n\n\nfunc ashbringer_surge_start(target: Unit, mana: float):\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 750)\n\tvar damage: float = tower.get_current_attack_damage_with_bonus() * (2.0 + 0.04 * tower.get_level()) * (1 + 0.01 * mana)\n\tvar chance_per_stack: float = 0.01 + 0.0002 * tower.get_level()\n\tvar prev: Unit = target\n\n\tCombatLog.log_ability(tower, target, \"Surge\")\n\n\tsurge_st.target_cast_from_caster(tower, target, 0.0, 0.0)\n\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next == target:\n\t\t\tcontinue\n\n\t\tvar attraction_buff: Buff = next.get_buff_of_type(attraction_bt)\n\n\t\tif attraction_buff == null:\n\t\t\tcontinue\n\n\t\tvar active_stacks: int = attraction_buff.user_int\n\t\tvar jump_chance: float = active_stacks * chance_per_stack\n\n\t\tif !tower.calc_chance(jump_chance):\n\t\t\tcontinue\n\n\t\tsurge_st.target_cast_from_caster(prev, next, 0.0, 0.0)\n\t\ttower.do_attack_damage(next, damage, tower.calc_attack_multicrit_no_bonus())\n\t\tprev = next\n"
  },
  {
    "path": "src/towers/tower_behaviors/area_roaster.gd",
    "content": "extends TowerBehavior\n\n\nvar ignite_bt: BuffType\n\n\nconst IGNITE_DURATION: float = 5.0\nconst IGNITE_DURATION_ADD: float = 0.05\nconst IGNITE_DAMAGE_PERIOD: float = 0.5\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_dmg_from_fire = 0.07, ignite_damage = 35, ignite_damage_add = 1.4},\n\t\t2: {mod_dmg_from_fire = 0.14, ignite_damage = 70, ignite_damage_add = 2.8},\n\t\t3: {mod_dmg_from_fire = 0.21, ignite_damage = 140, ignite_damage_add = 5.6},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: sir_area_damage() in original script\nfunc ignite_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = event.get_target()\n\tvar ignite_damage: float = buff.user_real\n\n\ttower.do_spell_damage(target, ignite_damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc tower_init():\n\tignite_bt = BuffType.new(\"ignite_bt\", IGNITE_DURATION, IGNITE_DURATION_ADD, false, self)\n\tignite_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tignite_bt.set_buff_tooltip(tr(\"WGVN\"))\n\tignite_bt.add_periodic_event(ignite_bt_periodic, IGNITE_DAMAGE_PERIOD)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_FIRE, _stats.mod_dmg_from_fire, 0.0)\n\tignite_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tvar active_buff: Buff = target.get_buff_of_type(ignite_bt)\n\tvar active_stacks: int = 0\n\tvar active_damage: float = 0\n\tif active_buff != null:\n\t\tactive_stacks = active_buff.user_int\n\t\tactive_damage = active_buff.user_real\n\n\tvar new_stacks: int = active_stacks + 1\n\tvar added_damage: float = _stats.ignite_damage + _stats.ignite_damage_add * level\n\tvar new_damage: float = active_damage + added_damage\n\n#\tNOTE: weaker tier tower increases damage without\n#\trefreshing duration\n\tactive_buff = ignite_bt.apply(tower, target, 1)\n\tactive_buff.user_int = new_stacks\n\tactive_buff.set_displayed_stacks(new_stacks)\n\tactive_buff.user_real = new_damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/ash_geyser.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Changed behavior when\n# multiple copies of this tower try to apply Ignite buff on\n# same unit.\n# \n# Original game: lower tier tower could temporarily reduce\n# damage of Ignite.\n#\n# YouTD2: Lower tier tower can't reduce damage of Ignite.\n\n\nvar ignite_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_regen = 0.05, mod_regen_add = 0.001},\n\t\t2: {mod_regen = 0.10, mod_regen_add = 0.002},\n\t\t3: {mod_regen = 0.15, mod_regen_add = 0.003},\n\t\t4: {mod_regen = 0.20, mod_regen_add = 0.004},\n\t\t5: {mod_regen = 0.25, mod_regen_add = 0.005},\n\t}\n\n\nconst IGNITE_CHANCE: float = 0.30\nconst IGNITE_DURATION: float = 8.0\nconst IGNITE_DAMAGE: float = 0.15\nconst IGNITE_DAMAGE_ADD: float = 0.006\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\n# NOTE: drol_fireDot_Damage() in original script\nfunc ignite_bt_periodic(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tb.get_caster().do_spell_damage(b.get_buffed_unit(), b.user_real, b.get_caster().calc_spell_crit_no_bonus())\n\n\nfunc tower_init():\n\tignite_bt = BuffType.new(\"ignite_bt\", IGNITE_DURATION, 0, false, self)\n\tignite_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tignite_bt.set_buff_tooltip(tr(\"M9RF\"))\n\tignite_bt.add_periodic_event(ignite_bt_periodic, 1)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_HP_REGEN_PERC, -_stats.mod_regen, -_stats.mod_regen)\n\tignite_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(IGNITE_CHANCE):\n\t\treturn\n\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Ignite\")\n\n\tvar buff: Buff = ignite_bt.apply(tower, target, level)\n\n\tvar current_ignite_damage: float = buff.user_real\n\tvar new_ignite_damage: float = tower.get_current_attack_damage_with_bonus() * (0.15 + tower.get_level() * 0.006)\n\tif new_ignite_damage > current_ignite_damage:\n\t\tbuff.user_real = new_ignite_damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/astral_lantern.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Commented out sections\n# relevant to invisibility because invisible waves are not\n# implemented.\n\n\n# func get_tier_stats() -> Dictionary:\n# \treturn {\n# \t\t1: {damage_base = 0.15, damage_add = 0.006},\n# \t\t2: {damage_base = 0.20, damage_add = 0.008},\n# \t\t3: {damage_base = 0.25, damage_add = 0.010},\n# \t\t4: {damage_base = 0.30, damage_add = 0.012},\n# \t}\n\n\n# func load_triggers(triggers_buff_type: BuffType):\n# \ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\n# func on_damage(event: Event):\n# \tif event.get_target().is_invisible():\n# \t\tevent.damage = event.damage * (_stats.damage_base + tower.get_level() * _stats.damage_add)\n"
  },
  {
    "path": "src/towers/tower_behaviors/astral_rift.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar slow_bt: BuffType\n\n\nconst AURA_RANGE: int = 750\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", 2, 0, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"DQPN\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.3, -0.01)\n\tslow_bt.set_buff_modifier(mod)\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/ophiucus.tres\")\n\taura_bt.set_buff_tooltip(tr(\"KSQW\"))\n\taura_bt.add_periodic_event(aura_bt_periodic, 1.0)\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar target: Creep = event.get_target()\n\tvar target_is_boss: bool = target.get_size() >= CreepSize.enm.BOSS\n\tvar enough_mana: bool = tower.get_mana() >= 30\n\n\tif !enough_mana:\n\t\treturn\n\n\tvar rift_chance: float = 0.10 + 0.004 * level\n\tif target_is_boss:\n\t\trift_chance *= 0.5\n\n\tif !tower.calc_chance(rift_chance):\n\t\treturn\n\n\ttower.subtract_mana(30, false)\n\n\tEffect.create_animated(\"res://src/effects/replenish_mana.tscn\", tower.get_position_wc3(), 0)\n\tEffect.create_simple(\"res://src/effects/spell_aiil.tscn\", Vector2(target.get_x(), target.get_y()))\n\n\tvar move_aoe: bool = tower.calc_chance(0.15)\n\n\tif move_aoe:\n\t\tCombatLog.log_ability(tower, target, \"Spacial Rift AoE\")\n\n\t\tvar spacial_rift_aoe_it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 175 + level)\n\n\t\twhile true:\n\t\t\tvar next: Unit = spacial_rift_aoe_it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tmove_creep_back(next)\n\telse:\n\t\tCombatLog.log_ability(tower, target, \"Spacial Rift\")\n\n\t\tmove_creep_back(target)\n\n\tEffect.create_simple(\"res://src/effects/silence_area.tscn\", Vector2(target.get_x(), target.get_y()))\n\n\tvar slow_aoe_it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 250 + level)\n\n\twhile true:\n\t\tvar next: Unit = slow_aoe_it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tslow_bt.apply(tower, next, level)\n\n\n# NOTE: SPDamage() in original script\nfunc aura_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar damage: float = creep.get_current_movespeed() * (2.0 + 0.16 * tower.get_level())\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc move_creep_back(creep: Unit):\n\tvar facing: float = creep.get_unit_facing()\n\tvar facing_reversed: float = facing - 180\n\tvar teleport_offset: Vector2 = Vector2(175 + tower.get_level(), 0).rotated(deg_to_rad(facing_reversed))\n\tvar current_creep_pos: Vector2 = creep.get_position_wc3_2d()\n\tvar new_creep_pos: Vector2 = current_creep_pos + teleport_offset\n\tcreep.set_position_wc3_2d(new_creep_pos)\n"
  },
  {
    "path": "src/towers/tower_behaviors/baby_tuskin.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Baby Tuskar\"=>\"Baby Tuskin\"\n\n\nvar snowball_pt: ProjectileType\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {stun_temple_duration = 0.6, stun_knockdown_duration = 0.4, hit_chance_add = 0.01},\n\t\t2: {stun_temple_duration = 0.8, stun_knockdown_duration = 0.6, hit_chance_add = 0.0125},\n\t\t3: {stun_temple_duration = 1.0, stun_knockdown_duration = 0.8, hit_chance_add = 0.014},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc snowball_pt_on_hit(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar t: Unit = p.get_caster()\n\n\tif p.user_int == 0:\n\t\tCombatLog.log_ability(t, target, \"Snow Ball miss\")\n\n\t\tvar miss_text: String = tr(\"FLOATING_TEXT_MISS\")\n\t\tt.get_player().display_floating_text_x_2(miss_text, target, Color8(150, 50, 0, 155), 0.07, 1, 2, 0.018, 0)\n\telse:\n\t\tt.do_spell_damage(target, p.user_real, t.calc_spell_crit_no_bonus())\n\t\tstun_bt.apply_only_timed(t, target, p.user_real2)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", target)\n\t\tSFX.sfx_at_unit(SfxPaths.POW, target)\n\n\t\tif p.user_int2 == 1:\n\t\t\tCombatLog.log_ability(t, target, \"Snow Ball Temple Crusher\")\n\t\t\t\n\t\t\tvar temple_crusher_text: String = tr(\"IQQP\")\n\t\t\tt.get_player().display_floating_text_x_2(temple_crusher_text, target, Color8(150, 50, 255, 200), 0.07, 2, 3, 0.026, 0)\n\t\telse:\n\t\t\tCombatLog.log_ability(t, target, \"Snow Ball Knockdown\")\n\t\t\t\n\t\t\tvar knockdown_text: String = tr(\"IM7N\")\n\t\t\tt.get_player().display_floating_text_x_2(knockdown_text, target, Color8(0, 0, 255, 155), 0.07, 1.5, 3, 0.022, 0)\n\n\nfunc tower_init():\n\tsnowball_pt = ProjectileType.create(\"path_to_projectile_sprite\", 0.0, 2000, self)\n\tsnowball_pt.enable_homing(snowball_pt_on_hit, 0)\n\n\tstun_bt = BuffType.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_attack(event: Event):\n\tvar u: Unit = event.get_target()\n\tvar facing_delta: float\n\tvar unit_to_tower_vector: float = rad_to_deg(atan2(tower.get_y() - u.get_y(), tower.get_x() - u.get_x()))\n\tvar p: Projectile\n\n\tif unit_to_tower_vector < 0:\n\t\tunit_to_tower_vector += 360\n\n\tfacing_delta = unit_to_tower_vector - u.get_unit_facing()\n\n\tif facing_delta < 0:\n\t\tfacing_delta += 360\n\n\tif facing_delta > 180:\n\t\tfacing_delta = 360 - facing_delta\n\n\tif facing_delta >= 80:\n\t\tp = Projectile.create_from_unit_to_unit(snowball_pt, tower, 100, 0, tower, event.get_target(), true, false, true)\n\t\tp.set_projectile_scale(0.8)\n\n\t\tif facing_delta <= 100:\n#\t\t\tTemple shot\n\t\t\tCombatLog.log_ability(tower, u, \"Create Snow Ball Temple Crusher\")\n\n\t\t\tp.user_int2 = 1\n\t\t\tp.user_real = tower.get_current_attack_damage_with_bonus() * 1.2\n\t\t\tp.user_real2 = _stats.stun_temple_duration\n\t\telse:\n#\t\t\tBack of the head\n\t\t\tCombatLog.log_ability(tower, u, \"Create Snow Ball back of the head\")\n\t\t\tp.user_int2 = 2\n\t\t\tp.user_real = tower.get_current_attack_damage_with_bonus() * 0.5\n\t\t\tp.user_real2 = _stats.stun_knockdown_duration\n\n#\t\tDecide hit/miss\n\t\tif tower.calc_chance(0.20 + tower.get_level() * _stats.hit_chance_add):\n#\t\t\tHit\n\t\t\tCombatLog.log_ability(tower, u, \"Create Snow Ball hit\")\n\t\t\tp.user_int = 1\n\t\telse:\n#\t\t\tMiss\n\t\t\tCombatLog.log_ability(tower, u, \"Create Snow Ball miss\")\n\t\t\tp.user_int = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/ball_lightning_accelerator.gd",
    "content": "extends TowerBehavior\n\n\nvar energetic_weapon_pt: ProjectileType\nvar absorb_target_bt: BuffType\nvar absorb_caster_bt: BuffType\nvar slow_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 500, projectile_damage_add = 25},\n\t\t2: {projectile_damage = 1000, projectile_damage_add = 50},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tabsorb_target_bt = BuffType.new(\"absorb_target_bt\", 8, 0, false, self)\n\tabsorb_target_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\tabsorb_target_bt.set_buff_tooltip(tr(\"CE7I\"))\n\tvar absorb_target_bt_mod: Modifier = Modifier.new()\n\tabsorb_target_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.1, 0.001)\n\tabsorb_target_bt.set_buff_modifier(absorb_target_bt_mod)\n\n\tabsorb_caster_bt = BuffType.new(\"absorb_caster_bt\", 8, 0, true, self)\n\tabsorb_caster_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\tabsorb_caster_bt.set_buff_tooltip(tr(\"CI6U\"))\n\tvar absorb_caster_bt_mod: Modifier = Modifier.new()\n\tabsorb_caster_bt_mod.add_modification(ModificationType.enm.MOD_MANA_REGEN, 0.0, 0.04)\n\tabsorb_caster_bt.set_buff_modifier(absorb_caster_bt_mod)\n\n\tenergetic_weapon_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 1000, 650, self)\n\tenergetic_weapon_pt.enable_collision(energetic_weapon_pt_on_hit, 250, TargetType.new(TargetType.CREEPS), false)\n\n\tslow_bt = BuffType.new(\"slow_bt\", 1.5, 0.04, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"BADR\"))\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.001)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar angle: float = atan2(target.get_y() - tower.get_y(), target.get_x() - tower.get_x())\n\tvar mana: float = tower.get_mana()\n\n\tvar p: Projectile = Projectile.create(energetic_weapon_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), Vector3(tower.get_x() + cos(angle) * 110, tower.get_y() + sin(angle) * 110, tower.get_z()), rad_to_deg(angle))\n\tvar damage_from_mana: float = mana * (3.0 + 0.05 * tower.get_level())\n\tvar projectile_damage: float = _stats.projectile_damage + _stats.projectile_damage_add * tower.get_level() + damage_from_mana\n\tp.user_real = projectile_damage\n\tp.set_projectile_scale(2.0)\n\n\ttower.set_mana(mana * 0.8)\n\n\nfunc on_autocast(_event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 1000)\n\tvar tower_count: int = 0\n\n\twhile true:\n\t\tvar target: Unit = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tif target != tower:\n\t\t\ttower_count += 1\n\t\t\tabsorb_target_bt.apply(tower, target, lvl)\n\n\tif tower_count > 0:\n\t\tvar buff_level: int = (50 + lvl) * tower_count\n\t\tabsorb_caster_bt.apply(tower, tower, buff_level)\n\n\nfunc energetic_weapon_pt_on_hit(projectile: Projectile, target: Unit):\n\tvar caster: Unit = projectile.get_caster()\n\tvar lightning_start_pos: Vector3 = Vector3(\n\t\tprojectile.get_x() + 50.0 * cos(deg_to_rad(projectile.get_direction())),\n\t\tprojectile.get_y() + 50.0 * sin(deg_to_rad(projectile.get_direction())),\n\t\t60.0\n\t\t)\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, lightning_start_pos, target)\n\tinterpolated_sprite.set_lifetime(0.2)\n\n\tvar projectile_damage: float = projectile.user_real\n\tprojectile.do_spell_damage(target, projectile_damage)\n\n\tvar slow: float = projectile_damage / 4000\n\tif slow > 20:\n\t\tslow = 20\n\tvar slow_buff_level: int = int(slow * 10)\n\tvar slow_buff_duration: float = 1.5 + 0.04 * caster.get_level()\n\tslow_bt.apply_custom_timed(caster, target, slow_buff_level, slow_buff_duration)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/purge_buff_target.tscn\", target)\n"
  },
  {
    "path": "src/towers/tower_behaviors/basic_knowledge.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {exp = 0.40},\n\t\t2: {exp = 0.55},\n\t\t3: {exp = 0.70},\n\t\t4: {exp = 0.85},\n\t\t5: {exp = 1.00},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(_event: Event):\n\ttower.add_exp(_stats.exp)\n"
  },
  {
    "path": "src/towers/tower_behaviors/black_dragon_roost.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Original script appears to be\n# completely broken? It uses addEventOnDamage() which means\n# that the handler will be called when creep *deals damage*\n# and that's clearly not what's supposed to happen. Fixed it\n# by switching to addEventOnDamaged()/add_event_on_damaged()\n# so that the handler which increases damage taken by creep\n# is called when creep takes damage.\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed Fear the Dark behavior:\n# \"each creep in range decreases the effect by 25%, creeps\n# with this buff don't count\".\n# - Ability description states that \"creeps with this buff\n#   don't count\".\n# - Tower behavior in original game is the opposite - creeps\n#   with the buff count and creeps without buff don't count.\n# \n# Assume that ability description is the correct behavior,\n# so made the behavior work like in description.\n\n# NOTE: the trigger chance for Fear the Dark ability appears\n# to have been changed often. Used 20% which is the value on\n# youtd.best and appears to be the most recent.\n\n\nvar fear_dark_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tfear_dark_bt = BuffType.new(\"fear_dark_bt\", 5, 0.1, false, self)\n\tfear_dark_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\tfear_dark_bt.set_buff_tooltip(tr(\"EZS3\"))\n\tfear_dark_bt.add_event_on_create(fear_dark_bt_on_create)\n\tfear_dark_bt.add_event_on_cleanup(fear_dark_bt_on_cleanup)\n\tfear_dark_bt.add_event_on_damaged(fear_dark_bt_on_damaged)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.5, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_HP_REGEN_PERC, -0.5, -0.01)\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, 0.5, -0.008)\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH, 0.25, 0.01)\n\tfear_dark_bt.set_buff_modifier(mod)\n\n\nfunc on_damage(event: Event):\n\tvar chance: float = 0.20 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Fear the Dark\")\n\n\tfear_dark_bt.apply(tower, event.get_target(), tower.get_level())\n\n\n# NOTE: startA() in original script\nfunc fear_dark_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar unit: Unit = buff.get_buffed_unit()\n\tunit.set_sprite_color(Color8(125, 125, 125, 255))\n\n\n# NOTE: clean() in original script\nfunc fear_dark_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar unit: Unit = buff.get_buffed_unit()\n\tunit.set_sprite_color(Color8(255, 255, 255, 255))\n\n\n# NOTE: dmg() in original script\nfunc fear_dark_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(caster, TargetType.new(TargetType.CREEPS), target, 500)\n\n\tvar damage_increase: float = 0.30 + 0.012 * caster.get_level()\n\tif target.get_size() >= CreepSize.enm.BOSS:\n\t\tdamage_increase *= 0.5\n\n\twhile true:\n\t\tvar creep: Unit = it.next()\n\t\tif creep == null:\n\t\t\tbreak\n\n\t\tvar creep_has_buff: bool = creep.get_buff_of_type(fear_dark_bt) != null\n\n\t\tif creep_has_buff:\n\t\t\tcontinue\n\n\t\tdamage_increase *= 0.75\n\n\tevent.damage *= (1.0 + damage_increase)\n"
  },
  {
    "path": "src/towers/tower_behaviors/black_rock_totem.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Blackrock's Totem\"=>\"Black Rock Totem\"\n\n\nvar fighter_totem_bt: BuffType\nvar demonic_fire_bt: BuffType\nvar shamanic_totem_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tfighter_totem_bt = BuffType.new(\"fighter_totem_bt\", 5, 0.2, true, self)\n\tvar figher_totem_bt_mod: Modifier = Modifier.new()\n\tfigher_totem_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.10, 0.004)\n\tfigher_totem_bt_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.05, 0.002)\n\tfigher_totem_bt_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.50, 0.020)\n\tfighter_totem_bt.set_buff_modifier(figher_totem_bt_mod)\n\tfighter_totem_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tfighter_totem_bt.set_buff_tooltip(tr(\"VAVG\"))\n\n\tshamanic_totem_bt = BuffType.new(\"shamanic_totem_bt\", 5, 0.2, true, self)\n\tvar shamanic_totem_bt_mod: Modifier = Modifier.new()\n\tshamanic_totem_bt_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.10, 0.004)\n\tshamanic_totem_bt.set_buff_modifier(shamanic_totem_bt_mod)\n\tshamanic_totem_bt.set_buff_icon(\"res://resources/icons/generic_icons/aquarius.tres\")\n\tshamanic_totem_bt.set_buff_tooltip(tr(\"QK8O\"))\n\n\tdemonic_fire_bt = BuffType.new(\"demonic_fire_bt\", 5, 0.2, false, self)\n\tdemonic_fire_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tdemonic_fire_bt.set_buff_tooltip(tr(\"L44U\"))\n\tdemonic_fire_bt.add_event_on_damaged(demonic_fire_bt_on_damaged)\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar chance: float = 0.15 + 0.002 * level\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Fighter Totem\")\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\n\twhile true:\n\t\tvar other_tower: Tower = it.next()\n\n\t\tif other_tower == null:\n\t\t\tbreak\n\n\t\tfighter_totem_bt.apply(tower, other_tower, level)\n\n\nfunc on_autocast(event: Event):\n\tvar level: int = tower.get_level()\n\tvar target: Creep = event.get_target()\n\tvar target_is_boss: bool = target.get_size() >= CreepSize.enm.BOSS\n\tvar shamanic_totem_chance: float = 0.30 + 0.004 * level\n\tvar restore_mana_ratio: float = 0.075 + 0.003 * level\n\n\tvar mod_dmg_from_fire_value: float\n\tif target_is_boss:\n\t\tmod_dmg_from_fire_value = 0.01 + 0.0004 * level\n\telse:\n\t\tmod_dmg_from_fire_value = 0.03 + 0.0008 * level\n\n\tvar buff: Buff = demonic_fire_bt.apply(tower, target, level)\n\tbuff.user_real = mod_dmg_from_fire_value\n\n\tif !tower.calc_chance(shamanic_totem_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Shamanic Totem\")\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\n\twhile true:\n\t\tvar other_tower: Tower = it.next()\n\n\t\tif other_tower == null:\n\t\t\tbreak\n\n\t\tshamanic_totem_bt.apply(tower, other_tower, level)\n\n\t\tif other_tower != tower:\n\t\t\tother_tower.add_mana_perc(restore_mana_ratio)\n\n\nfunc demonic_fire_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar mod_value: float = buff.user_real\n\n\tif creep.calc_chance(0.2):\n\t\tcreep.modify_property(ModificationType.enm.MOD_DMG_FROM_FIRE, mod_value)\n"
  },
  {
    "path": "src/towers/tower_behaviors/bomb_turret.gd",
    "content": "extends TowerBehavior\n\n\nvar silence_bt: BuffType\nvar concussive_tower_bt: BuffType\nvar concussive_creep_bt: BuffType\nvar acid_tower_bt: BuffType\nvar acid_creep_bt: BuffType\nvar smoke_tower_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {bomb_radius = 250, concussive_mod_movespeed = 0.15, concussive_mod_movespeed_add = 0.004, acid_mod_armor = 0.10, acid_mod_armor_add = 0.004, smoke_duration = 1.0, smoke_duration_add = 0.04},\n\t\t2: {bomb_radius = 300, concussive_mod_movespeed = 0.25, concussive_mod_movespeed_add = 0.006, acid_mod_armor = 0.15, acid_mod_armor_add = 0.006, smoke_duration = 1.5, smoke_duration_add = 0.06},\n\t}\n\nconst CONCUSSIVE_DURATION: float = 4.0\nconst ACID_DURATION: float = 4.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tsilence_bt = CbSilence.new(\"silence_bt\", 0, 0, false, self)\n\n\tconcussive_creep_bt = BuffType.new(\"concussive_creep_bt\", CONCUSSIVE_DURATION, 0, false, self)\n\tvar dave_concussive_creep_mod: Modifier = Modifier.new()\n\tdave_concussive_creep_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.concussive_mod_movespeed, -_stats.concussive_mod_movespeed_add)\n\tconcussive_creep_bt.set_buff_modifier(dave_concussive_creep_mod)\n\tconcussive_creep_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tconcussive_creep_bt.set_buff_tooltip(tr(\"PP9O\"))\n\n\tacid_creep_bt = BuffType.new(\"acid_creep_bt\", ACID_DURATION, 0, false, self)\n\tvar dave_acid_creep_mod: Modifier = Modifier.new()\n\tdave_acid_creep_mod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, -_stats.acid_mod_armor, -_stats.acid_mod_armor_add)\n\tacid_creep_bt.set_buff_modifier(dave_acid_creep_mod)\n\tacid_creep_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tacid_creep_bt.set_buff_tooltip(tr(\"SLZT\"))\n\n\tconcussive_tower_bt = BuffType.new(\"concussive_tower_bt\", -1, 0, true, self)\n\tconcussive_tower_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tconcussive_tower_bt.set_buff_tooltip(tr(\"UX05\"))\n\n\tacid_tower_bt = BuffType.new(\"acid_tower_bt\", -1, 0, true, self)\n\tacid_tower_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tacid_tower_bt.set_buff_tooltip(tr(\"HJG8\"))\n\n\tsmoke_tower_bt = BuffType.new(\"smoke_tower_bt\", -1, 0, true, self)\n\tsmoke_tower_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_meteor.tres\")\n\tsmoke_tower_bt.set_buff_tooltip(tr(\"JFQ6\"))\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar main_target: Unit = event.get_target()\n\tvar is_concussive: bool = tower.get_buff_of_type(concussive_tower_bt) != null\n\tvar is_acid: bool = tower.get_buff_of_type(acid_tower_bt) != null\n\tvar is_smoke: bool = tower.get_buff_of_type(smoke_tower_bt) != null\n\tvar creeps_in_range: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), main_target, _stats.bomb_radius)\n\n\tif is_concussive:\n\t\twhile true:\n\t\t\tvar creep: Unit = creeps_in_range.next()\n\t\t\tif creep == null:\n\t\t\t\tbreak\n\t\t\tconcussive_creep_bt.apply(tower, creep, level)\n\t\n\t\tEffect.create_scaled(\"res://src/effects/thunder_clap.tscn\", Vector3(main_target.get_x(), main_target.get_y(), 0), 0, 1.0)\n\telif is_acid:\n\t\twhile true:\n\t\t\tvar creep: Unit = creeps_in_range.next()\n\t\t\tif creep == null:\n\t\t\t\tbreak\n\t\t\tacid_creep_bt.apply(tower, creep, level)\n\n\t\tvar effect: int = Effect.create_scaled(\"res://src/effects/thunder_clap.tscn\", Vector3(main_target.get_x(), main_target.get_y(), 0), 0, 0.8)\n\t\tEffect.set_color(effect, Color.GREEN)\n\telif is_smoke:\n\t\twhile true:\n\t\t\tvar creep: Unit = creeps_in_range.next()\n\t\t\tif creep == null:\n\t\t\t\tbreak\n\n\t\t\tvar buff_duration: float = _stats.smoke_duration + _stats.smoke_duration_add * level\n\t\t\tsilence_bt.apply_only_timed(tower, creep, buff_duration)\n\n\t\tvar effect: int = Effect.create_scaled(\"res://src/effects/cloud_of_fog_small.tscn\", Vector3(main_target.get_x(), main_target.get_y(), 0), 0, 0.8)\n\t\tEffect.set_lifetime(effect, 0.5)\n\n\nfunc on_autocast_concussive(_event: Event):\n\tswitch_bomb_type(concussive_tower_bt)\n\n\nfunc on_autocast_acid(_event: Event):\n\tswitch_bomb_type(acid_tower_bt)\n\n\nfunc on_autocast_smoke(_event: Event):\n\tswitch_bomb_type(smoke_tower_bt)\n\n\nfunc switch_bomb_type(new_bomb_bt: BuffType):\n# \tRemove current bomb\n\tvar bomb_bt_list: Array[BuffType] = [\n\t\tconcussive_tower_bt,\n\t\tacid_tower_bt,\n\t\tsmoke_tower_bt,\n\t]\n\tbomb_bt_list.erase(new_bomb_bt)\n\tfor bomb_bt in bomb_bt_list:\n\t\tvar active_buff: Buff = tower.get_buff_of_type(bomb_bt)\n\t\tif active_buff != null:\n\t\t\tactive_buff.remove_buff()\n\n# \tSwitch to new bomb\n\tif tower.get_buff_of_type(new_bomb_bt) == null:\n\t\tnew_bomb_bt.apply(tower, tower, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/bone_shrine.gd",
    "content": "extends TowerBehavior\n\n\nvar curse_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {dmg_increase = 0.02, dmg_increase_add = 0.0004},\n\t\t2: {dmg_increase = 0.04, dmg_increase_add = 0.0008},\n\t\t3: {dmg_increase = 0.06, dmg_increase_add = 0.0012},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tcurse_bt = BuffType.new(\"curse_bt\", 0, 0, false, self)\n\tcurse_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tcurse_bt.set_buff_tooltip(tr(\"O4H7\"))\n\n\n# NOTE: buff is used only to keep track of stacks and as\n# visual indicator. MOD_DMG_FROM_DARKNESS modifier is\n# applied directly. It's possible to rework this script so\n# that modifier is attached to buff but it's tricky.\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar buff: Buff = target.get_buff_of_type(curse_bt)\n\n\tvar active_stacks: int\n\tif buff != null:\n\t\tactive_stacks = buff.get_level()\n\telse:\n\t\tactive_stacks = 0\n\n\tif active_stacks < 10:\n\t\tvar new_stacks: int = active_stacks + 1\n\t\t\n\t\ttarget.modify_property(ModificationType.enm.MOD_DMG_FROM_DARKNESS, _stats.dmg_increase + tower.get_level() * _stats.dmg_increase_add)\n\n\t\tbuff = curse_bt.apply_to_unit_permanent(tower, target, new_stacks)\n\t\tbuff.set_displayed_stacks(new_stacks)\n"
  },
  {
    "path": "src/towers/tower_behaviors/bonk_the_living_mountain.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: SCALE_MIN must match the value in tower sprite\n# scene\nconst SCALE_MIN: float = 0.5\nconst SCALE_MAX: float = 1.0\n\nvar stun_bt: BuffType\nvar morale_bt: BuffType\nvar grow_bt: BuffType\nvar rock_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar grow_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 25)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\t\n\tmorale_bt = BuffType.new(\"morale_bt\", 10, 0, true, self)\n\tmorale_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\tmorale_bt.set_buff_tooltip(tr(\"Z5K1\"))\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.10, 0.004)\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.10, 0.004)\n\tmorale_bt.set_buff_modifier(mod)\n\n\tgrow_bt = BuffType.new(\"grow_bt\", -1, 0, true, self)\n\tgrow_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tgrow_bt.set_buff_tooltip(tr(\"VCSG\"))\n\n\trock_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 700, self)\n\trock_pt.enable_homing(rock_pt_on_hit, 0)\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar grow_count_label: String = tr(\"D7GE\")\n\tmultiboard.set_key(0, grow_count_label)\n\n\nfunc on_create(_preceding: Tower):\n\tvar grow_buff: Buff = grow_bt.apply_to_unit_permanent(tower, tower, 0)\n\tgrow_buff.set_displayed_stacks(grow_count)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar chance: float = 0.25\n\tvar enough_grow_count_for_landslide: bool = grow_count >= 20\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tif !enough_grow_count_for_landslide:\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Landslide\")\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 300)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tProjectile.create_from_unit_to_unit(rock_pt, tower, 1.0, 0.0, tower, next, true, false, false)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar crush_damage: float = 5000 + 250 * level + 50 * grow_count\n\n\tvar enough_grow_count_for_crush: bool = grow_count >= 10\n\tif !enough_grow_count_for_crush:\n\t\treturn\n\n\tif !creep.is_stunned():\n\t\treturn\n\n\ttower.do_spell_damage(creep, crush_damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_animated(\"res://src/effects/impale_target_dust.tscn\", Vector3(creep.get_x(), creep.get_y(), 0.0), 0)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.TOWERS), tower, 500)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tmorale_bt.apply(tower, next, level)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, str(grow_count))\n\n\treturn multiboard\n\nfunc periodic(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar reached_max_growth: bool = grow_count >= 160\n\n\tif reached_max_growth:\n\t\treturn\n\n\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/roots.tscn\", tower)\n\tEffect.set_lifetime(effect, 1.0)\n\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.03 + 0.001 * level)\n\ttower.add_exp(4)\n\n\tgrow_count += 1\n\n\tvar grow_buff: Buff = tower.get_buff_of_type(grow_bt)\n\tgrow_buff.set_displayed_stacks(grow_count)\n\n\tvar tower_scale: float = Utils.get_scale_from_grows(SCALE_MIN, SCALE_MAX, grow_count, 160)\n\ttower.set_unit_scale(tower_scale)\n\n\nfunc rock_pt_on_hit(_projectile: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar damage: float = 700 + 50 * tower.get_level() + 15 * grow_count\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tstun_bt.apply_only_timed(tower, creep, 0.5)\n"
  },
  {
    "path": "src/towers/tower_behaviors/broken_cage.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 0.35, damage_add = 0.010},\n\t\t2: {damage = 0.45, damage_add = 0.013},\n\t\t3: {damage = 0.55, damage_add = 0.016},\n\t\t4: {damage = 0.65, damage_add = 0.019},\n\t\t5: {damage = 0.75, damage_add = 0.022},\n\t\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Creep = event.get_target()\n\tvar creep_category: CreepCategory.enm = creep.get_category()\n\tvar category_match: bool = [CreepCategory.enm.UNDEAD, CreepCategory.enm.MAGIC, CreepCategory.enm.NATURE].has(creep_category)\n\n\tif category_match:\n\t\ttower.do_spell_damage(creep, event.damage * (_stats.damage + (_stats.damage_add * tower.get_level())), tower.calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/mana_burn_target.tscn\", creep)\n"
  },
  {
    "path": "src/towers/tower_behaviors/broken_circle_of_wind.gd",
    "content": "extends TowerBehavior\n\n\nvar wind_bt: BuffType\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {catch_chance = 0.20, catch_chance_add = 0.003, cyclone_duration = 0.5, cyclone_damage = 20, cyclone_damage_add = 2},\n\t\t2: {catch_chance = 0.22, catch_chance_add = 0.004, cyclone_duration = 0.6, cyclone_damage = 68, cyclone_damage_add = 7},\n\t\t3: {catch_chance = 0.24, catch_chance_add = 0.005, cyclone_duration = 0.7, cyclone_damage = 196, cyclone_damage_add = 20},\n\t\t4: {catch_chance = 0.26, catch_chance_add = 0.006, cyclone_duration = 0.8, cyclone_damage = 600, cyclone_damage_add = 60},\n\t\t5: {catch_chance = 0.28, catch_chance_add = 0.007, cyclone_duration = 1.0, cyclone_damage = 1120, cyclone_damage_add = 112},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\twind_bt = CbStun.new(\"wind_bt\", 1.0, 0, false, self)\n\twind_bt.set_buff_icon(\"res://resources/icons/generic_icons/rolling_energy.tres\")\n\twind_bt.add_event_on_create(wind_bt_on_create)\n\twind_bt.add_periodic_event(wind_bt_periodic, 0.1)\n\twind_bt.add_event_on_cleanup(wind_bt_on_cleanup)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar damage: float = _stats.cyclone_damage + _stats.cyclone_damage_add * tower.get_level()\n\tvar b: Buff\n\n\tif (target.get_size() == CreepSize.enm.MASS || target.get_size() == CreepSize.enm.NORMAL || target.get_size() == CreepSize.enm.CHAMPION):\n\t\tif (tower.calc_chance(_stats.catch_chance + (_stats.catch_chance_add * tower.get_level()))):\n\t\t\tCombatLog.log_ability(tower, target, \"Wind of Death\")\n\n\t\t\tb = target.get_buff_of_type(wind_bt)\n\t\t\t\n\t\t\tif b != null:\n\t\t\t\tdamage = max(b.user_real3, damage)\n\n\t\t\tb = wind_bt.apply_custom_timed(tower, target, tower.get_level(), _stats.cyclone_duration)\n\n\t\t\tif b != null:\n\t\t\t\tb.user_real3 = damage\n\n\n# NOTE: cyclone_creep_up() in original script\nfunc wind_bt_on_create(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tvar c: Unit = b.get_buffed_unit()\n#\t(start) cyclone animation\n\tb.user_int = Effect.create_simple_at_unit_attached(\"res://src/effects/cyclone_target.tscn\", c)\n\tEffect.set_auto_destroy_enabled(b.user_int, false)\n\tEffect.set_z_index(b.user_int, -1)\n#   move creep up\n\tc.adjust_height(300, 1000)\n\n\n# NOTE: cyclone_creep_turn() in original script\nfunc wind_bt_periodic(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tvar real_unit: Unit = b.get_buffed_unit()\n\treal_unit.set_unit_facing(real_unit.get_unit_facing() + 150.0)\n\treal_unit = null\n\n\n# NOTE: cyclone_creep_down() in original script\nfunc wind_bt_on_cleanup(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tvar t: Unit = b.get_caster()\n\tvar c: Unit = b.get_buffed_unit()\n\tvar ratio: float = 1\n\n\tCombatLog.log_ability(t, c, \"Wind of Death End\")\n\n#\tset units back (down)\n\tc.adjust_height(-300, 2500)\n#\tremove the cyclone\n\tEffect.destroy_effect(b.user_int)\n# \teffects\n\tSFX.sfx_at_unit(SfxPaths.CLOUD_POOF, c)\n\tvar creep_pos: Vector2 = c.get_position_wc3_2d()\n\tvar thunder_clap_effect: int = Effect.create_simple(\"res://src/effects/thunder_clap.tscn\", creep_pos)\n\tEffect.set_z_index(thunder_clap_effect, Effect.Z_INDEX_BELOW_CREEPS)\n\tEffect.create_simple(\"res://src/effects/monsoon_bolt.tscn\", creep_pos)\n#   do damage\n\tif c.get_size() == CreepSize.enm.CHAMPION:\n\t\tratio = 1.25\n\n\tt.do_attack_damage_aoe_unit(c, ratio * 300.0, b.user_real3, t.calc_attack_multicrit(0, 0, 0), 0.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/broken_fire_pit.gd",
    "content": "extends TowerBehavior\n\n\nvar coals_bt : BuffType\n\n\nconst MOD_CRIT_CHANCE_ADD: float = 0.003\nconst DURATION_ADD: float = 0.05\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_crit_chance = 0.15, duration = 7.5},\n\t\t2: {mod_crit_chance = 0.20, duration = 8.5},\n\t\t3: {mod_crit_chance = 0.25, duration = 9.5},\n\t\t4: {mod_crit_chance = 0.30, duration = 10.5},\n\t\t5: {mod_crit_chance = 0.35, duration = 11.5},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, _stats.mod_crit_chance, MOD_CRIT_CHANCE_ADD)\n\tcoals_bt = BuffType.new(\"coals_bt \", _stats.duration, DURATION_ADD, true, self)\n\tcoals_bt.set_buff_modifier(m)\n\tcoals_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_meteor.tres\")\n\tcoals_bt.set_buff_tooltip(tr(\"BB66\"))\n\n\nfunc on_kill(_event: Event):\n\tvar level: int = tower.get_level()\n\tcoals_bt.apply(tower, tower, level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/broken_lightning_rod.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 70, damage_add = 3.5},\n\t\t2: {damage = 250, damage_add = 12.5},\n\t\t3: {damage = 700, damage_add = 35},\n\t\t4: {damage = 1400, damage_add = 70},\n\t\t5: {damage = 2500, damage_add = 125},\n}\n\n\nfunc on_autocast(event: Event):\n\tvar creep: Unit = event.get_target()\n\ttower.do_spell_damage(creep, _stats.damage + (tower.get_level() * _stats.damage_add), tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", creep, Unit.BodyPart.ORIGIN)\n"
  },
  {
    "path": "src/towers/tower_behaviors/bronze_dragon_roost.gd",
    "content": "extends TowerBehavior\n\n\nvar bronze_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tbronze_bt = BuffType.new(\"bronze_bt\", 5, 0.1, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.5, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_HP_REGEN_PERC, -0.5, -0.01)\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, 0.5, -0.008)\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH, 0.25, 0.01)\n\tbronze_bt.set_buff_modifier(mod)\n\tbronze_bt.set_buff_icon(\"res://resources/icons/generic_icons/gold_bar.tres\")\n\tbronze_bt.add_event_on_create(bronze_bt_on_create)\n\tbronze_bt.add_event_on_cleanup(bronze_bt_on_cleanup)\n\tbronze_bt.set_buff_tooltip(tr(\"MCA0\"))\n\n\nfunc on_damage(event: Event):\n\tvar chance: float = 0.1 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Bronzefication\")\n\n\tbronze_bt.apply(tower, event.get_target(), tower.get_level())\n\n\nfunc bronze_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar unit: Unit = buff.get_buffed_unit()\n\tunit.set_sprite_color(Color8(255, 255, 125, 255))\n\n\nfunc bronze_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar unit: Unit = buff.get_buffed_unit()\n\tunit.set_sprite_color(Color8(255, 255, 255, 255))\n"
  },
  {
    "path": "src/towers/tower_behaviors/buried_soul.gd",
    "content": "extends TowerBehavior\n\n\nvar cripple_bt: BuffType\nvar banish_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {banish_lvl = 40, banish_lvl_add = 0.32, banish_duration = 2.5, cripple_duration = 2.5, damage = 80, damage_add = 4},\n\t\t2: {banish_lvl = 60, banish_lvl_add = 0.48, banish_duration = 3.0, cripple_duration = 3.0, damage = 310, damage_add = 15.5},\n\t\t3: {banish_lvl = 80, banish_lvl_add = 0.64, banish_duration = 3.5, cripple_duration = 3.5, damage = 1240, damage_add = 62},\n\t\t4: {banish_lvl = 100, banish_lvl_add = 0.80, banish_duration = 4.0, cripple_duration = 4.0, damage = 2450, damage_add = 122.5},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tvar banish: Modifier = Modifier.new()\n\tvar cripple: Modifier = Modifier.new()\n\n\tcripple_bt = BuffType.new(\"cripple_bt\", 0.0, 0, false, self)\n\tbanish_bt = BuffType.new(\"banish_bt\", 0.0, 0, false, self)\n\tcripple_bt.set_buff_icon(\"res://resources/icons/generic_icons/triple_scratches.tres\")\n\tcripple_bt.set_special_effect(\"res://src/effects/cripple_target.tscn\", 50, 1.0)\n\tbanish_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\tbanish.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.0, 0.0001)\n\tcripple.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.6, 0.01)\n\tcripple_bt.set_buff_modifier(cripple)\n\tbanish_bt.set_buff_modifier(banish)\n\n\tcripple_bt.set_buff_tooltip(tr(\"ANC7\"))\n\tbanish_bt.set_buff_tooltip(tr(\"BRYE\"))\n\n\nfunc on_attack(event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar creep: Creep = event.get_target()\n\n\tif tower.calc_chance(0.1):\n\t\tCombatLog.log_ability(tower, creep, \"Soul Scattering\")\n\n\t\tbanish_bt.apply_custom_timed(tower, creep, int((_stats.banish_lvl + _stats.banish_lvl_add * lvl) * 100), _stats.banish_duration)\n\t\tcripple_bt.apply_custom_timed(tower, tower, lvl, _stats.cripple_duration)\n\n\tif tower.calc_chance(0.25 + 0.005 * lvl):\n\t\tCombatLog.log_ability(tower, creep, \"Shadowstrike\")\n\t\t\n\t\ttower.do_spell_damage(creep, _stats.damage + tower.get_level() * _stats.damage_add, tower.calc_spell_crit_no_bonus())\n\t\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/frost_armor_damage.tscn\", creep)\n\t\tEffect.set_color(effect, Color.PURPLE)\n"
  },
  {
    "path": "src/towers/tower_behaviors/burning_watchtower.gd",
    "content": "extends TowerBehavior\n\n\nvar burning_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {bonus_damage = 1.0, bonus_damage_add = 0.10, explode_damage = 49},\n\t\t2: {bonus_damage = 2.5, bonus_damage_add = 0.25, explode_damage = 277},\n\t\t3: {bonus_damage = 4.0, bonus_damage_add = 0.40, explode_damage = 750},\n\t\t4: {bonus_damage = 5.5, bonus_damage_add = 0.55, explode_damage = 1875},\n\t}\n\n\n# b.userReal: The user Real is the current bonus damage of the buff. Init with 0\n# NOTE: initOnCreate() in original script\nfunc burning_bt_on_create(event: Event):\n\tvar b: Buff = event.get_buff()\n\tb.user_real = 0.0\n\tb.user_int = 0\n\n\n# Increase damage gain and do direct damage to the target by setting the event damage\n# NOTE: damageOnFireAttack() in original script\nfunc burning_bt_on_damaged(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tvar damage_gain: float\n\tvar damage_factor: float\n\tvar caster: Tower = b.get_caster()\n\tvar attacker: Tower = event.get_target()\n\tvar is_burning_tower: bool\n\n\tif attacker.get_element() == Element.enm.FIRE:\n\t\tis_burning_tower = attacker.get_family() == caster.get_family()\n\n\t\tif is_burning_tower:\n\t\t\tdamage_factor = 1.0\n\t\telse:\n\t\t\tdamage_factor = 0.3\n\n\t\tdamage_gain = damage_factor * b.get_level() * 0.01\n\t\tb.user_real = b.user_real + damage_gain\n\t\tevent.damage = event.damage + b.user_real\n\n\t\tif is_burning_tower:\n\t\t\tvar damage_bonus_text: String = Utils.format_float(b.user_real, 0)\n\t\t\tattacker.get_player().display_small_floating_text(damage_bonus_text, b.get_buffed_unit(), Color8(255, 90, 0), 40.0)\n\n\t\tb.refresh_duration()\n\n\n# Does damage to all units around the buffed unit, if the buffed unit dies\n# b.userInt: AOE damage of the current buff.\n# NOTE: explodeOnDeath() in original script\nfunc burning_bt_on_death(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar killer: Unit = event.get_target()\n\tvar buffed_unit: Unit = b.get_buffed_unit()\n\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", buffed_unit)\n\tkiller.do_spell_damage_aoe_unit(buffed_unit, 200, b.user_int, killer.calc_spell_crit_no_bonus(), 0.0)\n\n\nfunc tower_init():\n#   This buff is configurated as follows:\n#   level: damage gain per attack\n#   userReal: Already done bonus damage on the buffed unit\n#   userInt: AOE-Damage if the buffed unit dies\n\tburning_bt = BuffType.new(\"burning_bt\", 0.0, 0.0, false, self)\n\tburning_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tburning_bt.add_event_on_create(burning_bt_on_create)\n\tburning_bt.add_event_on_damaged(burning_bt_on_damaged)\n\tburning_bt.add_event_on_death(burning_bt_on_death)\n\n\tburning_bt.set_buff_tooltip(tr(\"MBB6\"))\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar tower_level: int = tower.get_level()\n\tvar target: Unit = event.get_target()\n\tvar level: float = _stats.bonus_damage + tower_level * _stats.bonus_damage_add\n\tvar duration: float = 5 + tower_level * 0.12\n\tvar b: Buff = burning_bt.apply_custom_timed(tower, target, int(level * 100), duration)\n\n#\tUpgrade AOE-damage, if it makes sense\n\tif b.user_int < _stats.explode_damage:\n\t\tb.user_int = _stats.explode_damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/burrow.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {armor_ignored = 0.1, armor_ignored_add = 0.004},\n\t\t2: {armor_ignored = 0.2, armor_ignored_add = 0.008},\n\t\t3: {armor_ignored = 0.3, armor_ignored_add = 0.012},\n\t\t4: {armor_ignored = 0.4, armor_ignored_add = 0.016},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar cur_ratio: float = _stats.armor_ignored + _stats.armor_ignored_add * tower.get_level()\n\tvar s_dmg: float = event.damage\n\tvar damage_base: float = event.damage\n\tvar target: Creep = event.get_target() as Creep\n\tvar temp: float = AttackType.get_damage_against(AttackType.enm.PHYSICAL, target.get_armor_type())\n\n#\tignoring armor type \"resistance\" not weakness :P\n\tif temp > 0.0 && temp < 1.0:\n\t\tdamage_base = damage_base / temp\n\n\ttemp = (1 - target.get_current_armor_damage_reduction())\n\tif temp > 0.0:\n\t\tdamage_base = damage_base / temp\n\n\tif s_dmg < damage_base:\n\t\tevent.damage = damage_base * cur_ratio + s_dmg * (1.0 - cur_ratio)\n\n\t# The engine calculates critical strike extra damage ***AFTER*** the onDamage event, so there is no need to care about it in this trigger.\n"
  },
  {
    "path": "src/towers/tower_behaviors/caged_fire.gd",
    "content": "extends TowerBehavior\n\n\nvar melt_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_armor = 1, mod_armor_add = 0.04, periodic_mod_armor = 0.5, periodic_mod_armor_add = 0.02, melt_damage = 20, melt_damage_add = 0.8, periodic_melt_damage_increase = 20},\n\t\t2: {mod_armor = 2, mod_armor_add = 0.08, periodic_mod_armor = 1.0, periodic_mod_armor_add = 0.04, melt_damage = 40, melt_damage_add = 1.6, periodic_melt_damage_increase = 40},\n\t}\n\nconst AURA_RANGE: int = 900\n\n\nfunc tower_init():\n\tmelt_bt = BuffType.create_aura_effect_type(\"melt_bt\", false, self)\n\tmelt_bt.add_event_on_create(melt_bt_on_create)\n\tmelt_bt.add_periodic_event(melt_bt_on_periodic, 1.0)\n\tmelt_bt.add_event_on_cleanup(melt_bt_on_cleanup)\n\tmelt_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tmelt_bt.set_buff_tooltip(tr(\"JD4J\"))\n\n\nfunc melt_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar lvl: int = caster.get_level()\n\tvar current_mod_armor: float = _stats.mod_armor + _stats.mod_armor_add * lvl\n\tvar current_melt_damage: float = _stats.melt_damage + _stats.melt_damage_add * lvl\n\tbuff.user_real = current_mod_armor\n\tbuff.user_real2 = current_melt_damage\n\ttarget.modify_property(ModificationType.enm.MOD_ARMOR, -current_mod_armor)\n\n\nfunc melt_bt_on_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar lvl: int = caster.get_level()\n\tvar mod_armor_increase: float = _stats.periodic_mod_armor + _stats.periodic_mod_armor_add * lvl\n\tvar melt_damage_increase: float = _stats.melt_damage + _stats.melt_damage_add * lvl\n\tvar old_mod_armor: float = buff.user_real\n\tvar current_mod_armor: float = buff.user_real + mod_armor_increase\n\tvar current_melt_damage: float = buff.user_real2 + melt_damage_increase\n\tbuff.user_real = current_mod_armor\n\tbuff.user_real2 = current_melt_damage\n\n\tcaster.do_spell_damage(target, current_melt_damage, caster.calc_spell_crit_no_bonus())\n\ttarget.modify_property(ModificationType.enm.MOD_ARMOR, old_mod_armor)\n\ttarget.modify_property(ModificationType.enm.MOD_ARMOR, -current_mod_armor)\n\n\nfunc melt_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar current_mod_armor: float = buff.user_real\n\ttarget.modify_property(ModificationType.enm.MOD_ARMOR, current_mod_armor)\n"
  },
  {
    "path": "src/towers/tower_behaviors/cenarion.gd",
    "content": "extends TowerBehavior\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Cenarius\"=>\"Cenarion\"\n\n# NOTE: deduced the wave count of leaf storm cast like this:\n# 1. tooltip says it deals 2100dmg over time.\n# 2. dmg ratio for the cast is 700dmg base.\n# 3. 2100 / 700 = 3 waves\n\n\nvar roots_pt: ProjectileType\nvar entangle_bt: BuffType\nvar thorned_bt: BuffType\nvar tranquility_bt: BuffType\nvar leaf_storm_bt: BuffType\nvar leaf_storm_st: SpellType\n\n\nconst AURA_RANGE: int = 450\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 950, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\ttranquility_bt = BuffType.create_aura_effect_type(\"tranquility_bt\", true, self)\n\tvar tranquility_mod: Modifier = Modifier.new()\n\ttranquility_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -0.2, 0.004)\n\ttranquility_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.4, 0.004)\n\ttranquility_bt.set_buff_modifier(tranquility_mod)\n\ttranquility_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\ttranquility_bt.set_buff_tooltip(tr(\"I4NZ\"))\n\n\tentangle_bt = CbStun.new(\"entangle_bt\", 1.5, 0.02, false, self)\n\tentangle_bt.set_buff_icon(\"res://resources/icons/generic_icons/root_tip.tres\")\n\tentangle_bt.add_periodic_event(entangle_bt_periodic, 1.0)\n\tentangle_bt.set_buff_tooltip(tr(\"ZXE9\"))\n\n\troots_pt = ProjectileType.create_ranged(\"\", 1000, 600, self)\n\troots_pt.enable_collision(roots_pt_on_hit, 175, TargetType.new(TargetType.CREEPS), false)\n\troots_pt.enable_periodic(roots_pt_periodic, 0.2)\n\n\tleaf_storm_st = SpellType.new(SpellType.Name.BLIZZARD, 4.00, self)\n\tleaf_storm_st.set_damage_event(leaf_storm_st_on_damage)\n\tleaf_storm_st.data.blizzard.damage = 1.0\n\tleaf_storm_st.data.blizzard.radius = 200\n\tleaf_storm_st.data.blizzard.wave_count = 3\n\n\tvar leaf_storm_mod: Modifier = Modifier.new()\n\tleaf_storm_bt = BuffType.new(\"leaf_storm_bt\", 1.0, 0.04, false, self)\n\tleaf_storm_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.3, -0.006)\n\tleaf_storm_bt.set_buff_modifier(leaf_storm_mod)\n\tleaf_storm_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\tleaf_storm_bt.set_buff_tooltip(tr(\"BCDD\"))\n\n\tthorned_bt = BuffType.new(\"thorned_bt\", 3.0, 0.06, false, self)\n\tvar thorned_mod: Modifier = Modifier.new()\n\tthorned_mod.add_modification(ModificationType.enm.MOD_DMG_FROM_NATURE, 0.3, 0.006)\n\tthorned_bt.set_buff_modifier(thorned_mod)\n\tthorned_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\tthorned_bt.set_buff_tooltip(tr(\"AB6M\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar leaf_storm_chance: float = 0.15 + 0.006 * tower.get_level()\n\tvar damage_ratio: float = 700 + 30 * tower.get_level()\n\n\tif !tower.calc_chance(leaf_storm_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Leaf Storm\")\n\n\tleaf_storm_st.target_cast_from_caster(tower, target, damage_ratio, tower.calc_spell_crit_no_bonus())\n\n\nfunc on_unit_in_range(event: Event):\n\tvar target: Unit = event.get_target()\n\tthorned_bt.apply(tower, target, tower.get_level())\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar angle: float = rad_to_deg((target.get_position_wc3_2d() - tower.get_position_wc3_2d()).angle())\n\n\tProjectile.create_from_unit(roots_pt, tower, tower, angle, 1.0, tower.calc_spell_crit_no_bonus())\n\tProjectile.create_from_unit(roots_pt, tower, tower, angle + 15.0, 1.0, tower.calc_spell_crit_no_bonus())\n\tProjectile.create_from_unit(roots_pt, tower, tower, angle - 15.0, 1.0, tower.calc_spell_crit_no_bonus())\n\n\nfunc roots_pt_on_hit(p: Projectile, target: Unit):\n\tvar caster: Unit = p.get_caster()\n\tentangle_bt.apply(caster, target, caster.get_level())\n\n\n# NOTE: WWPeriodic() in original script\nfunc roots_pt_periodic(p: Projectile):\n\tvar effect: int = Effect.create_scaled(\"res://src/effects/roots.tscn\", Vector3(p.get_x(), p.get_y(), 0), 0, 0.5)\n\tEffect.set_lifetime(effect, 2.0)\n\n\nfunc entangle_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar damage: float = 1100 + 44 * caster.get_level()\n\n\tcaster.do_spell_damage(target, damage, caster.calc_spell_crit_no_bonus())\n\n\nfunc leaf_storm_st_on_damage(event: Event, _dummy_unit: DummyUnit):\n\tvar target: Unit = event.get_target()\n\tleaf_storm_bt.apply(tower, target, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/chaining_storm.gd",
    "content": "extends TowerBehavior\n\n\nvar strong_wind_bt: BuffType\nvar multiboard: MultiboardValues\nvar storm_power: int = 0\n\n\nconst AURA_RANGE: int = 900\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tstrong_wind_bt = BuffType.create_aura_effect_type(\"strong_wind_bt\", false, self)\n\tstrong_wind_bt.set_buff_icon(\"res://resources/icons/generic_icons/energy_breath.tres\")\n\tstrong_wind_bt.add_event_on_create(strong_wind_bt_on_create)\n\tstrong_wind_bt.add_periodic_event(strong_wind_bt_periodic, 1.0)\n\tstrong_wind_bt.add_event_on_cleanup(strong_wind_bt_on_cleanup)\n\tstrong_wind_bt.set_buff_tooltip(tr(\"M1X0\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar storm_power_label: String = tr(\"KPSU\")\n\tmultiboard.set_key(0, storm_power_label)\n\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar lvl: int = tower.get_level()\n\tvar x: float = target.get_x()\n\tvar y: float = target.get_y()\n\tvar bonus_spell_crit: float = 0.0\n\tvar air_bonus: float = 1.0\n\n\tvar chaining_storm_chance: float = 0.25 + 0.0125 * lvl + 0.0002 * storm_power\n\n\tif !tower.calc_chance(chaining_storm_chance):\n\t\treturn\n\n\tif tower.get_mana() < 100:\n\t\treturn\n\n\ttower.subtract_mana(100, false)\n\n#\tremove Mana\n#\tFirst Iteration\n#\tfor damage -> count creeps (save in: numCreeps)\n\n\tCombatLog.log_ability(tower, target, \"Chaining Storm\")\n\n\tvar it_for_count: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 350)\n\tvar creep_count: int = it_for_count.count()\n\n#\tdo effects\n\tEffect.create_simple(\"res://src/effects/thunder_clap.tscn\", Vector2(x, y))\n\tEffect.create_simple(\"res://src/effects/cyclone_target.tscn\", Vector2(x, y))\n\tvar effect3: int = Effect.create_simple(\"res://src/effects/voodoo_aura.tscn\", Vector2(x, y))\n\tEffect.set_z_index(effect3, Effect.Z_INDEX_BELOW_CREEPS)\n\tEffect.set_lifetime(effect3, 1.0)\n\n# \tAdjust ratios against air\n\tif target.get_size() == CreepSize.enm.AIR:\n\t\tbonus_spell_crit = 0.25\n\t\tair_bonus = 2.0\n\n\tvar damage: float = creep_count * air_bonus * (200 + 65 * lvl)\n\ttower.do_spell_damage_aoe_unit(target, 350, damage, tower.calc_spell_crit_no_bonus() + bonus_spell_crit, 0)\n\n#\tweaken creeps (weakening is divided by the number of creeps hit)\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 350)\n\tvar mod: float = (0.02 * 0.0012 * lvl) * creep_count\n\t\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tnext.modify_property(ModificationType.enm.MOD_DMG_FROM_STORM, mod)\n\t\tnext.modify_property(ModificationType.enm.MOD_DMG_FROM_ICE, mod)\n\t\tnext.modify_property(ModificationType.enm.MOD_DMG_FROM_ASTRAL, mod)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, str(storm_power))\n\n\treturn multiboard\n\n\n# NOTE: \"strongWindOnCreate()\" in original script\nfunc strong_wind_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_int = 0 # will be used to store buff level\n\tbuff.user_int2 = 0 # counts number of stacks\n\tbuff.user_real = 0.0 # records movespeed stolen (in case aura has levelled)\n\tbuff.user_real2 = 0.03 # stores slow factor, so that we don't need to recalculate it every second\n\n\n# NOTE: \"strongWindPeriodic()\" in original script\nfunc strong_wind_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar buff_level: int = buff.get_level()\n\n#\tCheck if aura level hasn't changed\n\tif buff_level != buff.user_int:\n\t\tbuff.user_int = buff_level\n\n#\t\tGive creep back its old movespeed and calculate new slow factor\n\t\tbuff.user_real2 = 0.03 + 0.0008 * buff_level\n\n\t\tif creep.get_size() == CreepSize.enm.AIR:\n\t\t\tbuff.user_real2 *= 2\n\n#\t\tAdjust movespeed accordingly\n\t\tcreep.modify_property(ModificationType.enm.MOD_MOVESPEED, buff.user_real - buff.user_real2 * buff.user_int2)\n\t\tbuff.user_real = buff.user_real2 * buff.user_int2\n\n#\tApply slow\n\tif buff.user_int2 < 15:\t# Max 15 stacks\n\t\tbuff.user_int2 += 1\n\t\tcreep.modify_property(ModificationType.enm.MOD_MOVESPEED, -buff.user_real2)\n\t\tbuff.user_real = buff.user_real + buff.user_real2\n\n\tbuff.set_displayed_stacks(buff.user_int2)\n\n#\tDeal damage\n\tvar damage_multiplier: float = 1.0 + 0.05 * buff_level + 0.0005 * storm_power\n\tvar damage: float = buff.user_real * 10 * caster.get_current_attack_damage_with_bonus() * damage_multiplier\n\tcaster.do_attack_damage(creep, damage, caster.calc_attack_multicrit_no_bonus())\n\n\n# NOTE: \"strongWindOnCleanup()\" in original script\nfunc strong_wind_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tif creep.get_health() > 0:\n#\t\tGive creep its movespeed back\n\t\tcreep.modify_property(ModificationType.enm.MOD_MOVESPEED, buff.user_real)\n\telse:\n#\t\tcreep died under the effect? Increse storm power!\n\t\tstorm_power += 1\n#\t\t+ mana\n\t\tcaster.add_mana(35)\n"
  },
  {
    "path": "src/towers/tower_behaviors/chaos_warlock.gd",
    "content": "extends TowerBehavior\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Eredar Warlock\"=>\"Chaos Warlock\"\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] changed autocast.buff_type\n# (null->siphon_bt). This fixes an issue where autocast\n# would rebuff the unit which is already buffed. Now, the\n# autocast will buff only units which don't already have the\n# buff.\n\n\nvar stun_bt: BuffType\nvar siphon_bt: BuffType\nvar aura_bt: BuffType\nvar wave_shadowbolt_pt: ProjectileType\nvar attack_shadowbolt_pt: ProjectileType\n\nvar last_autocast_triggered_bolt_wave: bool = false\n\nconst AURA_RANGE: int = 750\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {autocast_cooldown = 2.5, bolt_count = 10, bolt_damage = 1050, bolt_damage_add = 21},\n\t\t2: {autocast_cooldown = 1.5, bolt_count = 12, bolt_damage = 1700, bolt_damage_add = 34},\n\t}\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tsiphon_bt = BuffType.new(\"siphon_bt\", 5, 0, true, self)\n\tsiphon_bt.set_buff_icon(\"res://resources/icons/generic_icons/omega.tres\")\n\tsiphon_bt.add_event_on_attack(siphon_bt_on_attack)\n\tsiphon_bt.set_buff_tooltip(tr(\"DY1R\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\taura_bt.add_periodic_event(aura_bt_periodic, 1.0)\n\taura_bt.set_buff_tooltip(tr(\"LX2N\"))\n\n#\tNOTE: this tower uses two separate projectile types.\n#\t1. The first one is launched from the tower in all\n#\t   directions - not targeted at creeps.\n#  \t2. When the first projectiles expire, they transform\n#  \t   into homing projectiles, which are now targeted at\n#  \t   creeps.\n\twave_shadowbolt_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 300, 600, self)\n\twave_shadowbolt_pt.set_event_on_expiration(wave_shadowbolt_pt_on_expire)\n\n\tattack_shadowbolt_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 1000, self)\n\tattack_shadowbolt_pt.enable_homing(attack_shadowbolt_pt_on_hit, 0)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Tower = event.get_target()\n\tsiphon_bt.apply(tower, target, 1)\n\troll_for_shadow_wave()\n\n\nfunc roll_for_shadow_wave():\n\tvar wave_chance: float\n\tif last_autocast_triggered_bolt_wave:\n\t\twave_chance = 0.20\n\telse:\n\t\twave_chance = 0.40\n\n\tif !tower.calc_chance(wave_chance):\n\t\tlast_autocast_triggered_bolt_wave = false\n\n\t\treturn\n\telse:\n\t\tlast_autocast_triggered_bolt_wave = true\n\n\tCombatLog.log_ability(tower, null, \"Shadowbolt Wave\")\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\n\tif it.count() == 0:\n\t\treturn\n\n\tvar angle: float = 0.0\n\tvar tower_pos: Vector2 = tower.get_position_wc3_2d()\n\n#\tCreate projectiles which radiate around the tower\n\tfor i in range(0, _stats.bolt_count):\n\t\tangle += 360 / _stats.bolt_count\n\t\tvar offset: Vector2 = Vector2(300, 0).rotated(deg_to_rad(angle))\n\t\tvar target_pos_2d: Vector2 = tower_pos + offset\n\t\tvar target_pos: Vector3 = Vector3(target_pos_2d.x, target_pos_2d.y, tower.get_z())\n\t\tProjectile.create_from_unit_to_point(wave_shadowbolt_pt, tower, 1.0, 1.0, tower, target_pos, false, false)\t\n\n\nfunc siphon_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar warlock: Tower = buff.get_caster()\n\tvar attacker: Tower = buff.get_buffed_unit()\n\tvar target: Unit = event.get_target()\n\tvar dmg: float = 3 * attacker.get_current_attack_damage_with_bonus() / attacker.get_current_attack_speed()\n\tvar stun_duration: float = 2.5 - 0.02 * warlock.get_level()\n\n\tstun_bt.apply_only_timed(warlock, attacker, stun_duration)\n\n# \tNOTE: need to separately call order_stop() to stop\n# \tcurrent attack of buffed tower. Note that applying\n# \tstun_bt will not stop an attack which is already in\n# \tprogress.\n\tattacker.order_stop()\n\n#\tNOTE: calc_spell_crit_no_bonus() is used in original\n#\tscript even though this is do_attack_damage(). Maybe on\n#\tpurpose?\n\twarlock.do_attack_damage(target, dmg, warlock.calc_spell_crit_no_bonus())\n\n\tEffect.create_simple_at_unit(\"res://src/effects/impale_hit_target.tscn\", attacker, Unit.BodyPart.ORIGIN)\n\n\tvar floating_text: String = Utils.format_float(dmg, 0)\n\twarlock.get_player().display_floating_text_x(floating_text, target, Color8(255, 0, 150, 255), 0.05, 0.0, 2.0)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/impale_hit_target.tscn\", target, Unit.BodyPart.ORIGIN)\n\n\nfunc aura_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar is_less_than_boss: bool = target.get_size() < CreepSize.enm.BOSS\n\tvar low_health_threshold: float = 0.055 + 0.0006 * caster.get_level()\n\tvar is_low_health: bool = target.get_health_ratio() <= low_health_threshold\n\n\tif is_low_health && is_less_than_boss:\n\t\tcaster.kill_instantly(target)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", target)\n\n\nfunc wave_shadowbolt_pt_on_expire(projectile: Projectile):\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\n\tif it.count() != 0:\n\t\tvar random_creep: Unit = it.next_random()\n\t\tvar projectile_pos: Vector3 = projectile.get_position_wc3()\n\t\tProjectile.create_from_point_to_unit(attack_shadowbolt_pt, tower, 1.0, 1.0, projectile_pos, random_creep, true, false, false)\n\n\nfunc attack_shadowbolt_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = _stats.bolt_damage + _stats.bolt_damage_add * tower.get_level()\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/charged_obelisk.gd",
    "content": "extends TowerBehavior\n\n\nvar stun_bt: BuffType\nvar charge_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"charged_obelisk_stun\", 0, 0, false, self)\n\n\tcharge_bt = BuffType.new(\"charge_bt\", 10, 0, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.25, 0.001)\n\tcharge_bt.set_buff_modifier(mod)\n\tcharge_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\tcharge_bt.set_buff_tooltip(tr(\"NJH8\"))\n\tcharge_bt.add_periodic_event(charge_bt_periodic, 1.0)\n\n\nfunc on_attack(_event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\tvar random_creep: Unit = it.next_random()\n\n\tif random_creep == null:\n\t\treturn\n\n\ttower.do_spell_damage(random_creep, 1000 + 40 * lvl, tower.calc_spell_crit(0.20 + 0.004 * lvl, 0))\n\n\tif random_creep.get_size() < CreepSize.enm.BOSS:\n\t\tstun_bt.apply_only_timed(tower, random_creep, 0.2)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", random_creep)\n\n\nfunc on_autocast(event: Event):\n\tcharge_bt.apply(tower, event.get_target(), tower.get_level() * 6)\n\n\nfunc charge_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar new_level: int = buff.get_level() + 50 + caster.get_level()\n\tvar duration: float = buff.get_remaining_duration()\n\n\tbuff = charge_bt.apply_custom_timed(caster, target, new_level, duration)\n\tbuff.set_remaining_duration(duration)\n"
  },
  {
    "path": "src/towers/tower_behaviors/chilled_spire.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] fixed two bugs which were\n# present in original script.\n# \n# 1. Health regen values were same for tier 1 and tier 2.\n#    They should be different according to the tooltip.\n#\n# 2. Health regen reduction was not halved for bosses, only\n#    the per level portion was halved. Fixed so that the\n#    total regen reduction is halved for bosses.\n\n# NOTE: removed \"freezing\" movement of creeps effect which\n# called SetUnitTimeScale(). This f-n is only used by this\n# script and it's too complex to implement to work together\n# with creep's already existing scaling of animation speed\n# to movement speed.\n\n\nvar frozen_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {freeze_chance = 0.20, freeze_chance_add = 0.004, freeze_duration = 1.0, mod_regen = 0.20, mod_regen_add = 0.006},\n\t\t2: {freeze_chance = 0.25, freeze_chance_add = 0.005, freeze_duration = 1.2, mod_regen = 0.30, mod_regen_add = 0.008},\n\t}\n\n\nconst FREEZE_DURATION_ADD: float = 0.05\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tfrozen_bt = CbStun.new(\"frozen_bt\", -1, 0, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_HP_REGEN_PERC, 0.0, -0.001)\n\tfrozen_bt.set_buff_modifier(mod)\n\tfrozen_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\tfrozen_bt.set_buff_tooltip(tr(\"RVIN\"))\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar creep: Creep = event.get_target()\n\tvar already_has_buff: bool = creep.get_buff_of_type(frozen_bt) != null\n\tvar effects_multiplier: float\n\tif creep.get_size() >= CreepSize.enm.BOSS:\n\t\teffects_multiplier = 0.5\n\telse:\n\t\teffects_multiplier = 1.0\n\tvar chance: float = (_stats.freeze_chance + _stats.freeze_chance_add * level) * effects_multiplier\n\tvar buff_level: int = int((_stats.mod_regen + _stats.mod_regen_add * level) * 1000 * effects_multiplier)\n\tvar buff_duration: float = (_stats.freeze_duration + FREEZE_DURATION_ADD * level) * effects_multiplier\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tif creep.is_immune() || already_has_buff:\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Cold\")\n\n\tfrozen_bt.apply_custom_timed(tower, creep, buff_level, buff_duration)\n\tEffect.create_simple_at_unit(\"res://src/effects/freezing_breath.tscn\", creep)\n"
  },
  {
    "path": "src/towers/tower_behaviors/cloud_warrior.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {lightning_dmg = 100, lightning_dmg_add = 5},\n\t\t2: {lightning_dmg = 300, lightning_dmg_add = 15},\n\t\t3: {lightning_dmg = 750, lightning_dmg_add = 37.5},\n\t\t4: {lightning_dmg = 1875, lightning_dmg_add = 93.75},\n\t\t5: {lightning_dmg = 3750, lightning_dmg_add = 187.5},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\t\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\n\tif event.is_main_target() == true:\n\t\ttower.user_int = 1\n\telse:\n\t\ttower.user_int = 0\n\n\tawait Utils.create_manual_timer(0.4, self).timeout\n\n\tif tower.user_int == 1 && Utils.unit_is_valid(creep):\n\t\tCombatLog.log_ability(tower, creep, \"Lightning Strike\")\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", creep)\n\t\ttower.do_attack_damage(creep, _stats.lightning_dmg + (_stats.lightning_dmg_add * tower.get_level()), tower.calc_attack_multicrit(0.0, 0.0, 0.0))\n"
  },
  {
    "path": "src/towers/tower_behaviors/cloudy_temple_of_absorption.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: changed how storm is enabled/disabled. In original\n# script it's done using PeriodicEvent. In this script it's\n# done using \"storm_is_enabled\" flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] original script has a bug where\n# it defines special values for challenge sizes in\n# storm_mana_reduction_values map but fails to use them\n# because it uses creep.get_size() which returns BOSS\n# instead of CHALLENGE_BOSS. Fixed this bug by calling\n# creep.get_size_including_challenge_sizes().\n\n\nvar aura_bt: BuffType\nvar storm_bt: BuffType\nvar missile_pt: ProjectileType\nvar multiboard: MultiboardValues\n\nvar storm_is_enabled: bool = false\nvar threshold_for_cloudy_thunderstorm_autocast: float = 1.0\nvar storm_effect: int = 0\nvar storm_timeout_counter: int = 0\n\nconst AURA_RANGE: int = 1000\n\nconst storm_mana_reduction_values: Dictionary = {\n\tCreepSize.enm.MASS: 5,\n\tCreepSize.enm.NORMAL: 10,\n\tCreepSize.enm.AIR: 20,\n\tCreepSize.enm.CHAMPION: 20,\n\tCreepSize.enm.CHALLENGE_MASS: 13,\n\tCreepSize.enm.BOSS: 20,\n\tCreepSize.enm.CHALLENGE_BOSS: 130,\n}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 1000, TargetType.new(TargetType.CREEPS))\n\ttriggers.add_periodic_event(periodic, 0.4)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\taura_bt.add_event_on_damaged(aura_bt_on_damaged)\n\taura_bt.set_buff_tooltip(tr(\"JTSQ\"))\n\n\tstorm_bt = BuffType.new(\"storm_bt\", -1.0, 0.0, false, self)\n\tstorm_bt.add_event_on_damaged(storm_bt_on_damaged)\n\tstorm_bt.set_buff_tooltip(tr(\"RO3D\"))\n\n\tmissile_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 1000 + 100, 500, self)\n\tmissile_pt.enable_homing(missile_pt_on_hit, 0.0)\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar mana_required_label: String = tr(\"NL9R\")\n\tmultiboard.set_key(0, mana_required_label)\n\n\nfunc on_autocast_cloud_thunderstorm(_event: Event):\n\tif !storm_is_enabled:\n\t\tenable_storm()\n\n\nfunc on_autocast_adjust_threshold(_event: Event):\n\tthreshold_for_cloudy_thunderstorm_autocast += 0.1\n\tif threshold_for_cloudy_thunderstorm_autocast > 1.0:\n\t\tthreshold_for_cloudy_thunderstorm_autocast = 0.0\n\n\tvar floating_text: String = Utils.format_percent(threshold_for_cloudy_thunderstorm_autocast, 0)\n\ttower.get_player().display_small_floating_text(floating_text, tower, Color8(155, 155, 255), 40.0)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar mana_required: String = Utils.format_percent(threshold_for_cloudy_thunderstorm_autocast, 0)\n\tmultiboard.set_value(0, mana_required)\n\n\treturn multiboard\n\n\nfunc on_destruct():\n\tif storm_effect != 0:\n\t\tEffect.destroy_effect(storm_effect)\n\n\nfunc on_unit_in_range(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif !storm_is_enabled && !target.is_immune():\n\t\tvar threshold_reached: bool = tower.get_mana_ratio() > threshold_for_cloudy_thunderstorm_autocast\n\n\t\tif threshold_reached:\n\t\t\tenable_storm()\n\n\nfunc periodic(_event: Event):\n\tvar mana: float = tower.get_mana()\n\n#\tThe next strike will be realeased, if\n#\ta) The storm is enabled AND\n#\tb) The tower has still some mana AND\n#\tc) No timeout is reached\n\tif storm_is_enabled && mana > 1000 && storm_timeout_counter < 10:\n#\t\tRelease next strike\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\t\tvar target: Unit = it.next_random()\n\n\t\tif target != null:\n\t\t\tstorm_timeout_counter = 0\n\t\t\tstorm_bt.apply(tower, target, 1)\n\t\t\tvar damage: float = tower.get_mana() * (0.5 + 0.02 * tower.get_level())\n\t\t\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\t\t\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", target)\n\t\telse:\n\t\t\tstorm_timeout_counter += 1\n\telse:\n\t\tstorm_is_enabled = false\n\n\t\tif storm_effect != 0:\n\t\t\tEffect.destroy_effect(storm_effect)\n\t\t\tstorm_effect = 0\n\n\t\tstorm_timeout_counter = 0\n\n\n# --- Storm Buff Handling ---\nfunc storm_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar target: Creep = buff.get_buffed_unit()\n#\tCalculate how much damage is really dealt\n\tvar target_health: float = target.get_health()\n\tvar dmg_taken: float = min(event.damage, target_health)\n\tvar target_size: CreepSize.enm = target.get_size_including_challenge_sizes()\n\tvar mana_loss: float = dmg_taken * 0.1 * storm_mana_reduction_values[target_size] * Utils.divide_safe(dmg_taken, target_health)\n\n#\tRemove mana from the tower according to the damage taken\n#\tand the size of the creep\n\tcaster.subtract_mana(mana_loss, true)\n\tbuff.remove_buff()\n\n\nfunc enable_storm():\n\tif storm_is_enabled:\n\t\treturn\n\n\tstorm_is_enabled = true\n\tstorm_effect = Effect.create_animated(\"res://src/effects/cloud_of_fog_cycle.tscn\", Vector3(tower.get_x(), tower.get_y(), tower.get_z() + Constants.TILE_SIZE_WC3), 0.0)\n\tEffect.set_auto_destroy_enabled(storm_effect, false)\n\n\n# --- Aura Buff + Projectile Handling ---\n# If a creep with the auras buff is killed, a projectile spawns\n# Reaction of a natac_obsorption_AuraBuffType on Damage\nfunc aura_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar caster: Unit = buff.get_caster()\n\tvar damage: float = event.damage\n\tvar life: float = target.get_health()\n\n\tvar target_will_die: bool = damage > life\n\tvar target_is_affected_by_storm: bool = target.get_buff_of_type(storm_bt) != null\n\n\tif target_will_die && !target_is_affected_by_storm:\n\t\tvar mana_ball: Projectile = Projectile.create_from_unit_to_unit(missile_pt, caster, 0.0, 0.0, target, caster, true, false, false)\n\t\tvar redundant_damage: float = damage - life\n\t\tmana_ball.user_real = redundant_damage\n\n\nfunc missile_pt_on_hit(projectile: Projectile, target: Unit):\n\tif target == null || !Utils.unit_is_valid(target):\n\t\treturn\n\n\tvar max_mana: float = target.get_overall_mana()\n\tvar current_mana: float = target.get_mana()\n\tvar redundant_damage: float = projectile.user_real\n\tvar granted_mana: float = redundant_damage * (1.0 + 0.05 * target.get_level())\n\n\tif granted_mana > 0:\n\t\ttarget.add_mana(granted_mana)\n\n\tvar actual_granted_mana: float = min(max_mana - current_mana, granted_mana)\n\tvar floating_text: String = \"+%s\" % str(int(actual_granted_mana))\n\ttarget.get_player().display_small_floating_text(floating_text, target, Color8(0, 0, 255), 40)\n\n\tvar mana_is_full: bool = current_mana + granted_mana >= max_mana\n\n\tif !storm_is_enabled && mana_is_full:\n\t\tenable_storm()\n"
  },
  {
    "path": "src/towers/tower_behaviors/coconut_sapling.gd",
    "content": "extends TowerBehavior\n\n\nvar cooldown_bt: BuffType\nvar stun_bt: BuffType\nvar coco_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {coconut_chance_decrease = 0.20, coconut_damage = 1625, coconut_damage_add = 162.5, coconut_aoe = 150},\n\t\t2: {coconut_chance_decrease = 0.17, coconut_damage = 2600, coconut_damage_add = 260.0, coconut_aoe = 190},\n\t}\n\n\nconst STUN_DURATION: float = 0.5\nconst STUN_CD: float = 1.5\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tcoco_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 0, self)\n\tcoco_pt.enable_physics(coco_pt_on_impact, -15.0)\n\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tcooldown_bt = BuffType.new(\"cooldown_bt\", STUN_CD, 0, false, self)\n\tcooldown_bt.set_buff_icon(\"res://resources/icons/generic_icons/turtle_shell.tres\")\n\tcooldown_bt.set_buff_tooltip(tr(\"OC56\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tvar cast_count: int = 0\n\tvar current_chance: float = 1.0\n\twhile true:\n\t\tif cast_count > 100:\n\t\t\tbreak\n\t\telif tower.calc_chance(current_chance):\n\t\t\tcast_count += 1\n\t\t\tcurrent_chance *= (1.0 - _stats.coconut_chance_decrease)\n\t\telse:\n\t\t\tbreak\n\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\n\tfor i in range(0, cast_count):\n\t\tvar radius: float = Globals.synced_rng.randf_range(0, 300)\n\t\tvar angle: float = deg_to_rad(Globals.synced_rng.randf_range(0, 360))\n\t\tvar offset_vector: Vector2 = Vector2(radius, 0).rotated(angle)\n\t\tvar coconut_pos: Vector2 = target_pos + offset_vector\n\t\tvar projectile: Projectile = Projectile.create(coco_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), Vector3(coconut_pos.x, coconut_pos.y, 1000), 90)\n\t\tprojectile.set_projectile_scale(0.30)\n\t\tvar gravity: float = Globals.synced_rng.randf_range(1.0, 1.5)\n\t\tprojectile.set_gravity(gravity)\n\n\n# NOTE: cedi_Coco_Impact() in original script\nfunc coco_pt_on_impact(p: Projectile):\n\tvar caster: Unit = p.get_caster()\n\tvar pos: Vector2 = p.get_position_wc3_2d()\n\tvar it: Iterate = Iterate.over_units_in_range_of(caster, TargetType.new(TargetType.CREEPS), Vector2(pos.x, pos.y), 150)\n\tvar dmg: float = _stats.coconut_damage + _stats.coconut_damage_add * caster.get_level()\n\n\tvar effect: int = Effect.add_special_effect(\"res://src/effects/warstomp_caster.tscn\", pos)\n\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\n\twhile true:\n\t\tvar target: Unit = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tcaster.do_spell_damage(target, dmg, caster.calc_spell_crit_no_bonus())\n\n\t\tif target.get_buff_of_type(cooldown_bt) == null:\n\t\t\tstun_bt.apply_only_timed(caster, target, STUN_DURATION)\n\t\t\tcooldown_bt.apply_only_timed(caster, target, STUN_CD)\n"
  },
  {
    "path": "src/towers/tower_behaviors/coin_machine.gd",
    "content": "extends TowerBehavior\n\n\nvar golden_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_income = 0.05, buff_duration = 10, mod_bounty_gain = 0.40, gold_per_cast = 5},\n\t\t2: {mod_income = 0.10, buff_duration = 12, mod_bounty_gain = 0.60, gold_per_cast = 7},\n\t}\n\n\nconst AUTOCAST_RANGE: float = 400\nconst BUFF_DURATION_ADD: float = 0.4\nconst MOD_BOUNTY_GAIN_ADD: float = 0.006\n\n\nfunc tower_init():\n\tgolden_bt = BuffType.new(\"golden_bt\", _stats.buff_duration, BUFF_DURATION_ADD, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_BOUNTY_RECEIVED, _stats.mod_bounty_gain, MOD_BOUNTY_GAIN_ADD)\n\tgolden_bt.set_buff_modifier(mod)\n\tgolden_bt.set_buff_icon(\"res://resources/icons/generic_icons/holy_grail.tres\")\n\tgolden_bt.set_buff_tooltip(tr(\"W9ET\"))\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\t\n\tgolden_bt.apply(tower, target, level)\n\ttower.get_player().give_gold(_stats.gold_per_cast, tower, true, true)\n\n\nfunc on_create(_preceding: Tower):\n\ttower.get_player().modify_income_rate(_stats.mod_income)\n\n\nfunc on_destruct():\n\ttower.get_player().modify_income_rate(-_stats.mod_income)\n"
  },
  {
    "path": "src/towers/tower_behaviors/cold_obelisk.gd",
    "content": "extends TowerBehavior\n\n\nvar slow_bt: BuffType\n\n\nconst SLOW_DURATION: float = 4.0\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_movespeed = 0.18, mod_movespeed_add = 0.0040},\n\t\t2: {mod_movespeed = 0.24, mod_movespeed_add = 0.0045},\n\t\t3: {mod_movespeed = 0.30, mod_movespeed_add = 0.0050},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", SLOW_DURATION, 0, false, self)\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.mod_movespeed, -_stats.mod_movespeed_add)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_tooltip(tr(\"YCQN\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tslow_bt.apply(tower, target, level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/cold_troll.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where tooltip had\n# incorrect value (but logic was correct). For tier 1 troll,\n# Blizzard spell, tooltip says level bonus is \"+0.1% slow\"\n# when it's really \"+0.01% slow\" like it is for all other\n# tiers.\n\n\nvar slow_bt: BuffType\nvar blizzard_st: SpellType\nvar stun_bt: BuffType\n\n\nconst SLOW_CHANCE_ADD: float = 0.01\nconst STUN_CHANCE_ADD: float = 0.001\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {slow_chance = 0.30, mod_movespeed = 0.07, mod_movespeed_add = 0.0001, slow_duration = 4.0, stun_chance = 0.10, stun_duration = 0.25, blizzard_damage = 60, blizzard_radius = 200, blizzard_wave_count = 5, damage_ratio_add = 0.1},\n\t\t2: {slow_chance = 0.35, mod_movespeed = 0.09, mod_movespeed_add = 0.0001, slow_duration = 4.5, stun_chance = 0.15, stun_duration = 0.50, blizzard_damage = 333, blizzard_radius = 300, blizzard_wave_count = 6, damage_ratio_add = 0.036},\n\t\t3: {slow_chance = 0.40, mod_movespeed = 0.11, mod_movespeed_add = 0.0001, slow_duration = 5.0, stun_chance = 0.20, stun_duration = 0.75, blizzard_damage = 572, blizzard_radius = 400, blizzard_wave_count = 7, damage_ratio_add = 0.033},\n\t\t4: {slow_chance = 0.45, mod_movespeed = 0.14, mod_movespeed_add = 0.0001, slow_duration = 5.5, stun_chance = 0.25, stun_duration = 1.00, blizzard_damage = 1000, blizzard_radius = 500, blizzard_wave_count = 8, damage_ratio_add = 0.05},\n\t}\n\n\nfunc on_autocast(event: Event):\n\tvar u: Unit = event.get_target()\n\tblizzard_st.point_cast_from_caster_on_point(tower, Vector2(u.get_x(), u.get_y()), 1.00 + int(tower.get_level()) * _stats.damage_ratio_add, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: OnBlizzard() in original script\nfunc blizzard_st_on_damage(event: Event, _dummy: DummyUnit):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar slow_chance: float = _stats.slow_chance + SLOW_CHANCE_ADD * level\n\tvar stun_chance: float = _stats.stun_chance + STUN_CHANCE_ADD * level\n\n\tif tower.calc_chance(slow_chance):\n\t\tslow_bt.apply(tower, target, level)\n\n\tif tower.calc_chance(stun_chance):\n\t\tstun_bt.apply(tower, target, level)\n\n\nfunc tower_init():\n\tvar mod2: Modifier = Modifier.new()\n\tslow_bt = BuffType.new(\"slow_bt\", _stats.slow_duration, 0.0, false, self)\n\tmod2.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.mod_movespeed, -_stats.mod_movespeed_add)\n\tslow_bt.set_buff_modifier(mod2)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\n\tslow_bt.set_buff_tooltip(tr(\"UPAM\"))\n\n\tstun_bt = CbStun.new(\"stun_bt\", _stats.stun_duration, 0, false, self)\n\n\tblizzard_st = SpellType.new(SpellType.Name.BLIZZARD, 9.00, self)\n\tblizzard_st.set_damage_event(blizzard_st_on_damage)\n\tblizzard_st.data.blizzard.damage = _stats.blizzard_damage\n\tblizzard_st.data.blizzard.radius = _stats.blizzard_radius\n\tblizzard_st.data.blizzard.wave_count = _stats.blizzard_wave_count\n"
  },
  {
    "path": "src/towers/tower_behaviors/contraption.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mana_burned = 6, mana_burned_add = 0.08, dmg_bonus_per_mana = 0.08},\n\t\t2: {mana_burned = 8, mana_burned_add = 0.12, dmg_bonus_per_mana = 0.09},\n\t\t3: {mana_burned = 10, mana_burned_add = 0.16, dmg_bonus_per_mana = 0.10},\n\t\t4: {mana_burned = 12, mana_burned_add = 0.20, dmg_bonus_per_mana = 0.12},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tvar level: int = tower.get_level()\n\tvar mana_burned: float = _stats.mana_burned + _stats.mana_burned_add * level\n\tvar mana_burned_actual: float = target.subtract_mana(mana_burned, true)\n\tvar dmg_multiplier: float = 1.0 + _stats.dmg_bonus_per_mana * mana_burned_actual\n\n\tevent.damage *= dmg_multiplier\n"
  },
  {
    "path": "src/towers/tower_behaviors/crimson_wyrm.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed tower details displaying\n# dmg bonus from gold hoarded incorrectly. It was dividing\n# by 100 instead of 5000.\n\n\nvar wyrm_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar fireball_cd: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(3)\n\tvar gold_hoarded_label: String = tr(\"GRZ6\")\n\tvar bonus_damage_label: String = tr(\"YQK4\")\n\tvar atks_to_fireballs_label: String = tr(\"CE54\")\n\tmultiboard.set_key(0, gold_hoarded_label)\n\tmultiboard.set_key(1, bonus_damage_label)\n\tmultiboard.set_key(2, atks_to_fireballs_label)\n\n\twyrm_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 700, self)\n\twyrm_pt.set_event_on_interpolation_finished(wyrm_pt_on_hit)\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\n#\tcheck if 0 attacks remain till fireballs\n\tif fireball_cd > 0:\n\t\tfireball_cd -= 1\n\telse:\n#\t\tsetting minimum number of attacks before next fireballs\n\t\tif level == 25:\n\t\t\tfireball_cd = 5\n\t\telif level >= 15:\n\t\t\tfireball_cd = 6\n\t\telse:\n\t\t\tfireball_cd = 7\n\n#\t\tset +0,+1 or +2 attacks and release bolts afterwards\n\t\tfireball_cd += Globals.synced_rng.randi_range(0, 4)\n\n\t\tif level >= 10:\n\t\t\trelease_fireballs(4)\n\t\telse:\n\t\t\trelease_fireballs(3)\n\n\nfunc on_kill(event: Event):\n\tvar creep: Creep = event.get_target()\n\tvar value: float = 0.75 * creep.get_base_bounty_value() * creep.get_prop_bounty_granted() * tower.get_prop_bounty_received()\n\tvar hoard_size: float = 90000\n\n\tif tower.user_real >= hoard_size:\n\t\tvalue = 0\n\telif tower.user_real + value > hoard_size:\n\t\tvalue = hoard_size - tower.user_real\n\n\tif value != 0:\n\t\tsir_update(value)\n\t\ttower.get_player().give_gold(-value, tower, true, false)\n\n\nfunc on_create(preceding: Tower):\n#\tSomebody might replace this tower with this tower\n\ttower.user_real = 0\n\tif preceding != null && preceding.get_family() == tower.get_family():\n\t\tsir_update(preceding.user_real)\n\n#\tMediocre cd for first wave of fireballs\n\tfireball_cd = 9\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar gold_hoard_string: String = Utils.format_float(tower.user_real, 0)\n\tvar dmg_bonus_string: String = Utils.format_percent(tower.user_real / 5000, 0)\n\tvar fireball_cd_string: String = str(fireball_cd)\n\n\tmultiboard.set_value(0, gold_hoard_string)\n\tmultiboard.set_value(1, dmg_bonus_string)\n\tmultiboard.set_value(2, fireball_cd_string)\n\n\treturn multiboard\n\n\nfunc sir_update(new_gold: float):\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, -tower.user_real / 5000)\n\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -tower.user_real / 5000)\n\ttower.user_real += new_gold\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, tower.user_real / 5000)\n\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, tower.user_real / 5000)\n\n\nfunc wyrm_pt_on_hit(p: Projectile, _target: Unit):\n\tvar level: int = tower.get_level()\n\n\tvar crit_mod: float\n\tif level >= 20:\n\t\tcrit_mod = 0.10\n\telif level >= 5 && level < 20:\n\t\tcrit_mod = 0.05\n\telse:\n\t\tcrit_mod = 0.00\n\n\tvar radius: float = 250\n\tvar damage: float = 3750 + 150 * level\n\n\ttower.do_spell_damage_aoe(Vector2(p.get_x(), p.get_y()), radius, damage, tower.calc_spell_crit(crit_mod, 0), 0)\n\n\nfunc release_fireballs(fireball_count: int):\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 950)\n\tvar last_target: Unit = null\n\n\tCombatLog.log_ability(tower, null, \"Fireballs count=%d\" % fireball_count)\n\n\twhile true:\n\t\tvar next: Unit = it.next_random()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar p: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(wyrm_pt, tower, 1, 1, tower, next, 0, Globals.synced_rng.randf_range(-0.35, 0.35), Globals.synced_rng.randf_range(0.17, 0.4), true)\n\t\tp.set_projectile_scale(2.0)\n\n\t\tfireball_count -= 1\n\n\t\tlast_target = next\n\n\t\tif fireball_count == 0:\n\t\t\tbreak\n\n\tif fireball_count > 0:\n\t\tif last_target != null:\n# \t\t\tShoot remaining balls at last target\n\t\t\tfor i in range(0, fireball_cd):\n\t\t\t\tvar p: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(wyrm_pt, tower, 1, 1, tower, last_target, 0, Globals.synced_rng.randf_range(-0.35, 0.35), Globals.synced_rng.randf_range(0.17, 0.4), true)\n\t\t\t\tp.set_projectile_scale(2.0)\n\t\telse:\n# \t\t\tShoot remaining balls during next attack\n\t\t\tfireball_cd = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/cruel_fire.gd",
    "content": "extends TowerBehavior\n\n\nvar fire_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_crit = 0.050, mod_crit_add = 0.002},\n\t\t2: {mod_crit = 0.075, mod_crit_add = 0.003},\n\t\t3: {mod_crit = 0.100, mod_crit_add = 0.004},\n\t}\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, _stats.mod_crit, _stats.mod_crit_add)\n\tfire_bt = BuffType.create_aura_effect_type(\"fire_bt\", true, self)\n\tfire_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\tfire_bt.set_buff_modifier(m)\n\tfire_bt.set_buff_tooltip(tr(\"SMKF\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/cursed_grounds.gd",
    "content": "extends TowerBehavior\n\n\nvar slow_bt: BuffType\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {cursed_attack_damage = 200, cursed_attack_damage_add = 10, mod_movespeed = 0.20, mod_spell_dmg_received = 0.100, aura_effect = 0.10, aura_effect_add = 0.004},\n\t\t2: {cursed_attack_damage = 320, cursed_attack_damage_add = 16, mod_movespeed = 0.25, mod_spell_dmg_received = 0.125, aura_effect = 0.15, aura_effect_add = 0.006},\n\t\t3: {cursed_attack_damage = 560, cursed_attack_damage_add = 28, mod_movespeed = 0.30, mod_spell_dmg_received = 0.150, aura_effect = 0.20, aura_effect_add = 0.008},\n\t}\n\nconst CURSED_ATTACK_CHANCE: float = 0.25\nconst CURSED_ATTACK_CHANCE_ADD: float = 0.01\nconst CURSED_DURATION: float = 4\nconst CURSED_DURATION_ADD: float = 0.1\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", CURSED_DURATION, CURSED_DURATION_ADD, false, self)\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.mod_movespeed, 0)\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, _stats.mod_spell_dmg_received, 0)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"D4LZ\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar aura_bt_mod: Modifier = Modifier.new()\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_DMG_TO_HUMANOID, _stats.aura_effect, _stats.aura_effect_add)\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_DMG_TO_ORC, _stats.aura_effect, _stats.aura_effect_add)\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_DMG_TO_NATURE, _stats.aura_effect, _stats.aura_effect_add)\n\taura_bt.set_buff_modifier(aura_bt_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/over_infinity.tres\")\n\taura_bt.set_buff_tooltip(tr(\"O5X3\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tvar cursed_attack_chance: float = CURSED_ATTACK_CHANCE + CURSED_ATTACK_CHANCE_ADD * level\n\n\tif !tower.calc_chance(cursed_attack_chance):\n\t\treturn\n\n\tif !target.is_immune():\n\t\tCombatLog.log_ability(tower, target, \"Cursed Attack\")\n\n\t\tvar damage: float = _stats.cursed_attack_damage + _stats.cursed_attack_damage_add * level\n\t\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\t\tslow_bt.apply(tower, target, level)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/spell_aima.tscn\", target)\n"
  },
  {
    "path": "src/towers/tower_behaviors/cute_small_spider.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: in original script an EventTypeList is used to add\n# \"on_damage\" event handler. Changed script to add handler\n# directly to tower.\n\n# NOTE: [ORIGINAL_GAME_BUG] fixed bug in poison buff logic.\n# Original script compares the spell_damage_dealt stat of\n# active buff's caster with current tower. If current tower\n# has higher spell_damage_dealt stat, the buff will be\n# replaced. The problem is that original script didn't\n# consider the case where there is one Cute Small Spider\n# tower and it's spell_damage_dealt stat changes frequently\n# because of buffs from another tower or items. The buff\n# will get replaced everytime spell_damage_dealt stat\n# changes. If tower's spell_damage_dealt stat went up and\n# down frequently, then buff would get reset frequently.\n# This would cause the buff's periodic timer for damage to\n# get constantly reset. If spell_damage_dealt stat changed\n# every second, then it's possible for poison damage ticks\n# to never happen at all!\n\n\nvar poison_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 30, damage_add = 1.5, max_damage = 150, max_damage_add = 7.5},\n\t\t2: {damage = 90, damage_add = 4.5, max_damage = 450, max_damage_add = 22.5},\n\t\t3: {damage = 270, damage_add = 13.5, max_damage = 1350, max_damage_add = 67.5},\n\t\t4: {damage = 750, damage_add = 37.5, max_damage = 3750, max_damage_add = 187.5},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\n# NOTE: D1000_Spider_Damage() in original script\nfunc poison_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar poison_damage: float = buff.user_real\n\t\n\ttower.do_spell_damage(target, poison_damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tvar active_buff: Buff = target.get_buff_of_type(poison_bt)\n\t\n\tvar active_stacks: int = 0\n\tvar active_damage: float = 0\n\tvar active_damage_cap: float = 0\n\tvar active_spell_damage_dealt: float = -1\n\tif active_buff != null:\n\t\tactive_stacks = active_buff.user_int\n\t\tactive_damage = active_buff.user_real\n\t\tactive_damage_cap = active_buff.user_real2\n\t\tactive_spell_damage_dealt = active_buff.user_real3\n\n\tvar new_stacks: int = min(active_stacks + 1, 5)\n\tvar added_damage: float = _stats.damage + _stats.damage_add * level\n\tvar this_damage_cap: float = _stats.max_damage + _stats.max_damage_add * level\n\tvar new_damage_cap: float = max(active_damage_cap, this_damage_cap)\n\tvar new_damage: float = min(active_damage + added_damage, new_damage_cap)\n\tvar new_spell_damage_dealt: float = tower.get_prop_spell_damage_dealt()\n\n#\tNOTE: [ORIGINAL_GAME_DEVIATION] in original game, the\n#\tspell power comparison and buff replacement did not\n#\tconsider the tier of the tower. Add it so that higher\n#\ttier towers always have prio.\n\tif active_buff != null && active_buff.get_caster() != tower:\n\t\tvar active_tier: int = active_buff.get_tower_tier()\n\t\tvar new_tier: int = tower.get_tier()\n\n\t\tvar this_tower_is_more_powerful: bool = new_tier >= active_tier && new_spell_damage_dealt > active_spell_damage_dealt\n\n\t\tif this_tower_is_more_powerful:\n\t\t\tactive_buff.remove_buff()\n\n\tactive_buff = poison_bt.apply(tower, target, 1)\n\tactive_buff.user_int = new_stacks\n\tactive_buff.set_displayed_stacks(new_stacks)\n\tactive_buff.user_real = new_damage\n\tactive_buff.user_real2 = new_damage_cap\n\tif new_spell_damage_dealt > active_spell_damage_dealt:\n\t\tactive_buff.user_real3 = new_spell_damage_dealt\n\n\nfunc tower_init():\n\tpoison_bt = BuffType.new(\"poison_bt\", 5, 0.05, false, self)\n\tpoison_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tpoison_bt.add_periodic_event(poison_bt_periodic, 1)\n\tpoison_bt.set_buff_tooltip(tr(\"TTST\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/dark_battery.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: rewrote script a bit. Instead of enabling/disabling\n# periodic event I added a flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where it refunds the cost of autocast in\n# on_autocast(). It refunds the cost by calling set_mana()\n# but the problem is that at the time when on_autocast() is\n# called, the mana cost has not been spent yet. Therefore,\n# refund fails if tower is at max mana because set_mana()\n# can't go above max mana. Not critical - don't need to fix.\n\n\nvar corruption_bt: BuffType\nvar missile_pt: ProjectileType\n\nvar _battery_overload_is_active: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 300, projectile_damage_add = 12, mod_spell_damage = 0.05, mod_spell_damage_add = 0.002, mod_attack_damage = 0.10, mod_attack_damage_add = 0.004},\n\t\t2: {projectile_damage = 750, projectile_damage_add = 30, mod_spell_damage = 0.10, mod_spell_damage_add = 0.003, mod_attack_damage = 0.20, mod_attack_damage_add = 0.008},\n\t\t3: {projectile_damage = 1800, projectile_damage_add = 72, mod_spell_damage = 0.15, mod_spell_damage_add = 0.006, mod_attack_damage = 0.30, mod_attack_damage_add = 0.012},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc on_autocast(_event: Event):\n\ttower.set_mana(tower.get_mana() + 100)\n\t_battery_overload_is_active = true\n\n\nfunc hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.projectile_damage + _stats.projectile_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tcorruption_bt.apply(tower, creep, level)\n\n\nfunc tower_init():\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, _stats.mod_spell_damage, _stats.mod_spell_damage_add)\n\tmodifier.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, _stats.mod_attack_damage, _stats.mod_attack_damage_add)\n\n\tcorruption_bt = BuffType.new(\"corruption_bt\", 9, 0.3, false, self)\n\tcorruption_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tcorruption_bt.set_buff_modifier(modifier)\n\tcorruption_bt.set_buff_tooltip(tr(\"K2J4\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\tmissile_pt.enable_homing(hit, 0)\n\n\nfunc on_damage(event: Event):\n\tcorruption_bt.apply(tower, event.get_target(), tower.get_level())\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.set_mana(0)\n\n\nfunc periodic(_event: Event):\n\tif !_battery_overload_is_active:\n\t\treturn\n\n\tif tower.get_mana() > 10:\n\t\tvar in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar target: Unit = in_range.next_random()\n\n\t\tif target != null:\n# \t\t\tNOTE: original script used createFromPointToUnit and made projectiles from high above the tower\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\t\tp.set_projectile_scale(0.5)\n\n#\t\tSpend mana, note that mana is used for unsuccessful\n#\t\tattempts as well\n\t\ttower.set_mana(tower.get_mana() - 10)\n\telse:\n#\t\tTower is out of mana so stop shooting\n\t\t_battery_overload_is_active = false\n"
  },
  {
    "path": "src/towers/tower_behaviors/death_knight.gd",
    "content": "extends TowerBehavior\n\n\nvar will_positive_bt: BuffType\nvar will_negative_bt: BuffType\nvar withering_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 900, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\twill_positive_bt = BuffType.new(\"will_positive_bt\", 5, 0, true, self)\n\tvar will_positive_bt_mod: Modifier = Modifier.new()\n\twill_positive_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.0, 0.002)\n\twill_positive_bt.set_buff_modifier(will_positive_bt_mod)\n\twill_positive_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\twill_positive_bt.set_buff_tooltip(tr(\"Q60A\"))\n\n\twill_negative_bt = BuffType.new(\"will_negative_bt\", 5, 0, false, self)\n\tvar will_negative_bt_mod: Modifier = Modifier.new()\n\twill_negative_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.0, -0.002)\n\twill_negative_bt.set_buff_modifier(will_negative_bt_mod)\n\twill_negative_bt.set_buff_icon(\"res://resources/icons/generic_icons/pisces.tres\")\n\twill_negative_bt.set_buff_tooltip(tr(\"BK97\"))\n\n\twithering_bt = BuffType.new(\"withering_bt\", 4, 0, false, self)\n\tvar withering_bt_mod: Modifier = Modifier.new()\n\twithering_bt_mod.add_modification(ModificationType.enm.MOD_HP_REGEN_PERC, -0.5, -0.1)\n\twithering_bt_mod.add_modification(ModificationType.enm.MOD_EXP_GRANTED, -0.5, 0.01)\n\twithering_bt_mod.add_modification(ModificationType.enm.MOD_BOUNTY_GRANTED, -0.5, 0.01)\n\twithering_bt.set_buff_modifier(withering_bt_mod)\n\twithering_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\twithering_bt.set_buff_tooltip(tr(\"JRGL\"))\n\twithering_bt.add_periodic_event(withering_bt_periodic, 1.0)\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar mana: float = tower.get_mana()\n\tvar max_mana: float = tower.get_overall_mana()\n\tvar mana_gain: float = max_mana * 0.01\n\tvar damage_bonus_from_mana: float = event.damage * (max_mana - mana) * (0.025 + 0.001 * level)\n\n\ttower.add_mana(mana_gain)\n\tevent.damage += damage_bonus_from_mana\n\n\nfunc on_kill(_event: Event):\n\tvar max_mana: float = tower.get_overall_mana()\n\tvar mana_gain: float = max_mana * 0.05\n\n\ttower.add_mana(mana_gain)\n\n\nfunc on_unit_in_range(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar withering_presence_chance: float = 0.15 + 0.004 * level\n\n\tif !tower.calc_chance(withering_presence_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Withering Presence\")\n\n\twithering_bt.apply(tower, target, level)\n\n\nfunc on_autocast(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 200)\n\tvar mana: float = tower.get_mana()\n\tvar tower_count: int = 0\n\n\ttower.set_mana(mana / 2)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next == tower || next.get_gold_cost() < 1300:\n\t\t\tcontinue\n\n\t\ttower_count += 1\n\n\t\twill_negative_bt.apply(tower, next, 50 + level)\n\n\tif tower_count > 0:\n\t\twill_positive_bt.apply(tower, tower, (75 + level) * tower_count)\n\n\tif tower_count == 0:\n\t\tCombatLog.log_ability(tower, null, \"Will of the Undying failed because nearby towers are cheap\")\n\n\nfunc withering_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar hp: float = buffed_unit.get_health()\n\tvar hp_loss: float = hp * 0.05\n\n\tbuffed_unit.set_health(hp - hp_loss)\n"
  },
  {
    "path": "src/towers/tower_behaviors/dimensional_flux_collector.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original script does weird things with putting\n# creeps into list/hashtable and counting creeps in range.\n# Removed that, same behavior can be achieved without it.\n# What's the point of checking that creeps are in range? The\n# aura does that already and removes the buff when creeps go\n# out of range.\n\n\nvar aura_bt: BuffType\nvar link_bt: BuffType\nvar flux_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar linked_tower: Tower = null\nvar saved_lightning: InterpolatedSprite = null\nvar spell_damage_by_linked_tower: float = 0.0\nvar link_time: float = 0.0\nvar logged_link_ability: bool = false\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.add_event_on_damaged(aura_bt_on_damaged)\n\taura_bt.set_hidden()\n\n\tlink_bt = BuffType.new(\"link_bt\", -1, 0, true, self)\n\tlink_bt.add_event_on_create(aura_bt_on_create)\n\tlink_bt.add_event_on_cleanup(aura_bt_on_cleanup)\n\tlink_bt.set_buff_icon(\"res://resources/icons/generic_icons/aquarius.tres\")\n\tlink_bt.set_buff_tooltip(tr(\"DM73\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar dps_label: String = tr(\"YWRV\")\n\tmultiboard.set_key(0, dps_label)\n\n\tflux_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\tflux_pt.set_event_on_interpolation_finished(flux_pt_on_hit)\n\n\nfunc on_destruct():\n#\tRemove link on destroy of this tower\n\tif linked_tower != null:\n\t\tvar buff: Buff = linked_tower.get_buff_of_type(link_bt)\n\t\tbuff.remove_buff()\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar buff_on_new_target: Buff = target.get_buff_of_type(link_bt)\n\n\tif buff_on_new_target != null:\n#\t\tTarget is linked to another one of these towers.\n#\t\tDestroy that link\n\t\tbuff_on_new_target.remove_buff()\n\n#\tIt should be impossible for this to create a double free as this can only be true if the\n#\tlinked tower and the target aren't the same. Else the buff is destroyed before this\n#\t-> linked_tower == null (buff cleanup)\n\tif linked_tower != null:\n\t\tvar buff_on_old_target: Buff = linked_tower.get_buff_of_type(link_bt)\n\t\tbuff_on_old_target.remove_buff()\n\n\tlinked_tower = target\n\tlink_bt.apply(tower, target, 0)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar dps: float = get_dps_from_link()\n\tvar dps_string: String = Utils.format_float(dps, 0)\n\n\tmultiboard.set_value(0, dps_string)\n\n\treturn multiboard\n\n\nfunc periodic(event: Event):\n\tvar attack_speed: float = tower.get_current_attack_speed()\n\n\tevent.enable_advanced(attack_speed, false)\n\n\tif linked_tower == null:\n#\t\tNOT LINKED! Do nothing!\n\t\tlink_time = 0.0\n\t\tlogged_link_ability = false\n\n\t\treturn\n\n\tif spell_damage_by_linked_tower <= 0.0:\n#\t\tNo dmg to deal! Do nothing!\n\t\treturn\n\n\tlink_time += attack_speed\n\n\tvar linked_for_10_sec: bool = link_time >= 10.0\n\n\tif !linked_for_10_sec:\n\t\treturn\n\n\tif linked_for_10_sec && !logged_link_ability:\n\t\tCombatLog.log_ability(tower, null, \"Link damage active\")\n\t\tlogged_link_ability = true\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 800)\n\tvar next: Unit = it.next_random()\n\n\tif next != null:\n\t\tProjectile.create_bezier_interpolation_from_unit_to_unit(flux_pt, tower, 1.0, 1.0, tower, next, 0.35, 0, 0, true)\n\n\n# NOTE: \"ProjHit()\" in original script\nfunc flux_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = get_dps_from_link()\n\ttower.do_custom_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus(), AttackType.enm.ENERGY)\n\n\n# NOTE: \"BuffTrigger()\" in original script\nfunc aura_bt_on_damaged(event: Event):\n\tvar attacker: Unit = event.get_target()\n\n\tif event.is_spell_damage() && attacker == linked_tower:\n\t\tspell_damage_by_linked_tower += event.damage\n\n\n# NOTE: \"LinkCreate()\" in original script\nfunc aura_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, Vector3(caster.get_x(), caster.get_y(), 220), linked_tower)\n\tlightning.modulate = Color.LIGHT_BLUE\n\tsaved_lightning = lightning\n\n\n# NOTE: \"LinkEnd()\" in original script\nfunc aura_bt_on_cleanup(_event: Event):\n\tif saved_lightning != null:\n\t\tsaved_lightning.queue_free()\n\t\tsaved_lightning = null\n\n\tlinked_tower = null\n\n\nfunc get_dps_from_link() -> float:\n\tif link_time <= 0.0:\n\t\treturn 0.0\n\n\tvar spell_dps_by_linked_tower: float = spell_damage_by_linked_tower / link_time\n\tvar multiplier: float = 0.25 + 0.01 * tower.get_level()\n\tvar dps: float = spell_dps_by_linked_tower * multiplier\n\n\treturn dps\n"
  },
  {
    "path": "src/towers/tower_behaviors/dragon_sorcerer.gd",
    "content": "extends TowerBehavior\n\n\nvar mark_bt: BuffType\n\n\nfunc tower_init():\n\tmark_bt = BuffType.new(\"mark_bt\", 10.0, 0.4, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 1.0, 0.0)\n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.075, 0.002)\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.25, 0.006)\n\tmark_bt.set_buff_modifier(mod)\n\tmark_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tmark_bt.set_buff_tooltip(tr(\"FYXT\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/drake_whisperer.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: fixed error in original script where drake\n# projectiles used Projectile API's for both interpolated\n# and normal projectile types.\n# For example:\n# ProjectileType.create() - normal\n# ProjectileType.setEventOnInterpolationFinished() - interpolated\n# Switched to using exclusively interpolated API.\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed slow buff being friendly.\n\n\nenum DrakeState {\n\tIDLE,\n\tATTACKING,\n\tCOMING_BACK\n};\n\nclass Drake:\n\tvar projectile: Projectile\n\tvar state: DrakeState\n\tvar start_pos: Vector3\n\n\n# NOTE: \"maxFedDrakes\" in original script\nconst FEED_COUNT_MAX: int = 5\nconst BLUE_I: int = 0\nconst GREEN_I: int = 1\nconst RED_I: int = 2\n\nvar stun_bt: BuffType\nvar versatile_bt: BuffType\nvar slow_bt: BuffType\nvar blue_drake_pt: ProjectileType\nvar green_drake_pt: ProjectileType\nvar red_drake_pt: ProjectileType\nvar bronze_drake_pt: ProjectileType\nvar bronze_drake_attack_pt: ProjectileType\nvar drake_list: Array[Drake] = []\nvar feed_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_periodic_event(periodic, 1.5)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tversatile_bt = BuffType.new(\"versatile_bt\", 2.5, 0, true, self)\n\tvar versatile_bt_mod: Modifier = Modifier.new()\n\tversatile_bt_mod.add_modification(ModificationType.enm.MOD_DPS_ADD, 0.0, 1.0)\n\tversatile_bt.set_buff_modifier(versatile_bt_mod)\n\tversatile_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\tversatile_bt.set_buff_tooltip(tr(\"A5KK\"))\n\n\tslow_bt = BuffType.new(\"slow_bt\", 3.0, 0, false, self)\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.25, 0.0)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/energy_breath.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"FZBS\"))\n\n\tblue_drake_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\tblue_drake_pt.disable_explode_on_hit()\n\tblue_drake_pt.disable_explode_on_expiration()\n\tblue_drake_pt.set_event_on_interpolation_finished(generic_drake_pt_on_hit)\n\tblue_drake_pt.enable_periodic(generic_drake_pt_periodic, 0.1)\n\n\tred_drake_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\tred_drake_pt.disable_explode_on_hit()\n\tred_drake_pt.disable_explode_on_expiration()\n\tred_drake_pt.set_event_on_interpolation_finished(generic_drake_pt_on_hit)\n\tred_drake_pt.enable_periodic(generic_drake_pt_periodic, 0.1)\n\n\tgreen_drake_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\tgreen_drake_pt.disable_explode_on_hit()\n\tgreen_drake_pt.disable_explode_on_expiration()\n\tgreen_drake_pt.set_event_on_interpolation_finished(generic_drake_pt_on_hit)\n\tgreen_drake_pt.enable_periodic(generic_drake_pt_periodic, 0.1)\n\n\tbronze_drake_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\tbronze_drake_pt.disable_explode_on_hit()\n\tbronze_drake_pt.disable_explode_on_expiration()\n\tbronze_drake_pt.enable_periodic(bronze_drake_pt_periodic, 0.2)\n\n\tbronze_drake_attack_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\tbronze_drake_attack_pt.set_event_on_interpolation_finished(bronze_drake_attack_pt_on_hit)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar unleash_chance: float = 0.125 + 0.003 * tower.get_level()\n\n\tif !tower.calc_chance(unleash_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Unleash\")\n\n\tvar final_x: float = tower.get_x() + (target.get_x() - tower.get_x()) * 6\n\tvar final_y: float = tower.get_y() + (target.get_y() - tower.get_y()) * 6\n\tvar final_pos: Vector3 = Vector3(final_x, final_y, tower.get_z())\n\n\tvar p: Projectile = Projectile.create_from_unit_to_point(bronze_drake_pt, tower, 0, 0, tower, final_pos, true, false)\n\tp.set_projectile_scale(0.6)\n\n\nfunc on_create(_preceding_tower: Tower):\n\tvar blue_drake: Drake = Drake.new()\n\tvar green_drake: Drake = Drake.new()\n\tvar red_drake: Drake = Drake.new()\n\t\n\tblue_drake.projectile = Projectile.create_linear_interpolation_from_unit_to_point(blue_drake_pt, tower, 0, 0, tower, Vector3(tower.get_x() + 36, tower.get_y() - 30, tower.get_z() - 30), 0.0)\n\tgreen_drake.projectile = Projectile.create_linear_interpolation_from_unit_to_point(green_drake_pt, tower, 0, 0, tower, Vector3(tower.get_x() - 50, tower.get_y() - 13, tower.get_z() - 30), 0.0)\n\tred_drake.projectile = Projectile.create_linear_interpolation_from_unit_to_point(red_drake_pt, tower, 0, 0, tower, Vector3(tower.get_x() + 27, tower.get_y() + 59, tower.get_z() - 30), 0.0)\n\n\tdrake_list.resize(3)\n\tdrake_list[BLUE_I] = blue_drake\n\tdrake_list[GREEN_I] = green_drake\n\tdrake_list[RED_I] = red_drake\n\n\tdrake_list[BLUE_I].projectile.user_int2 = BLUE_I\n\tdrake_list[GREEN_I].projectile.user_int2 = GREEN_I\n\tdrake_list[RED_I].projectile.user_int2 = RED_I\n\n\tdrake_list[BLUE_I].start_pos = Vector3(tower.get_x() + 36, tower.get_y() - 30, tower.get_z() - 30)\n\tdrake_list[GREEN_I].start_pos = Vector3(tower.get_x() - 50, tower.get_y() - 13, tower.get_z() - 30)\n\tdrake_list[RED_I].start_pos = Vector3(tower.get_x() + 27, tower.get_y() + 59, tower.get_z() - 30)\n\n\tfor drake in drake_list:\n\t\tdrake.projectile.disable_periodic()\n\t\tdrake.projectile.set_projectile_scale(0.25)\n\t\tdrake.state = DrakeState.IDLE\n\n\tdrake_list[BLUE_I].projectile.set_color(Color.LIGHT_BLUE)\n\tdrake_list[GREEN_I].projectile.set_color(Color.DARK_GREEN)\n\tdrake_list[RED_I].projectile.set_color(Color.DARK_RED)\n\n\nfunc on_destruct():\n\tfor drake in drake_list:\n\t\tdrake.projectile.remove_from_game()\n\n\tdrake_list.clear()\n\n\nfunc periodic(_event: Event):\n\tfeeding()\n\n\n# NOTE: \"allDrakesBusy()\" in original script\nfunc all_drakes_busy() -> bool:\n\tvar all_busy: bool = true\n\n\tfor drake in drake_list:\n\t\tif drake.state == DrakeState.IDLE:\n\t\t\tall_busy = false\n\n\t\t\tbreak\n\n\treturn all_busy\n\n\n# NOTE: \"launchDrakeling()\" in original script\nfunc launch_drakeling(drake: Drake, target: Unit):\n\tdrake.projectile.set_speed(600)\n\tdrake.projectile.start_bezier_interpolation_to_unit(target, 0.15, 0.15, 0.17, true)\n\tdrake.state = DrakeState.ATTACKING\n\tfeed_count -= 1\n\n\n\n# NOTE: \"launchRandomDrakeling()\" in original script\nfunc launch_random_drakeling(target: Unit):\n\tvar i: int = Globals.synced_rng.randi_range(0, 2)\n\n\twhile true:\n\t\tvar drake: Drake = drake_list[i]\n\n\t\tif drake.state == DrakeState.IDLE:\n\t\t\tlaunch_drakeling(drake, target)\n\n\t\t\treturn\n\n\t\ti = (i + 1) % 3\n\n\n# NOTE: \"feeding()\" in original script\nfunc feeding():\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\tvar feed_two_chance: float = 0.15 + 0.004 * tower.get_level()\n\n\tif feed_count < FEED_COUNT_MAX:\n\t\tvar it_corpse: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CORPSES), Vector2(tower.get_x(), tower.get_y()), 1000)\n\t\tvar corpse: CreepCorpse = it_corpse.next_corpse()\n\n\t\tif corpse != null:\n\t\t\tcorpse.hide()\n\n\t\t\tvar effect: int = Effect.create_scaled(\"res://src/effects/blood_splatter.tscn\", Vector3(tower.get_x() + 10, tower.get_y(), tower.get_z() - 120), 0, 2)\n\t\t\tEffect.set_lifetime(effect, 0.8)\n\n\t\t\tvar feed_amount: int\n\t\t\tif tower.calc_chance(feed_two_chance):\n\t\t\t\tfeed_amount = 2\n\t\t\telse:\n\t\t\t\tfeed_amount = 1\n\n\t\t\tfeed_count += feed_amount\n\n\t\t\tif feed_count > FEED_COUNT_MAX:\n\t\t\t\tfeed_count = FEED_COUNT_MAX\n\n\twhile true:\n\t\tif feed_count <= 0 || all_drakes_busy():\n\t\t\treturn\n\n\t\tvar next: Unit = it.next_random()\n\n\t\tif next == null:\n\t\t\tbreak\n\n#\t\tOnly red drakes deal physical, so unleash only them vs immune\n\t\tif next.is_immune():\n\t\t\tvar red_drake: Drake = drake_list[RED_I]\n\n\t\t\tif red_drake.state == DrakeState.IDLE:\n\t\t\t\tlaunch_drakeling(red_drake, next)\n\t\telse:\n\t\t\tlaunch_random_drakeling(next)\n\n\n# NOTE: \"refreshBuff()\" in original script\nfunc refresh_buff(damage_dealt: float):\n\tvar versatile_buff: Buff = tower.get_buff_of_type(versatile_bt)\n\tvar max_damage: float = 200 * tower.get_player().get_team().get_level()\n\n\tif damage_dealt <= 0:\n\t\treturn\n\n\tvar powerup: float = damage_dealt * (0.015 + 0.004 * tower.get_level())\n\n\tvar active_buff_level: int\n\tif versatile_buff != null:\n\t\tactive_buff_level = versatile_buff.get_level()\n\telse:\n\t\tactive_buff_level = 0\n\n\tvar new_buff_level: int = active_buff_level + floori(powerup)\n\tnew_buff_level = min(new_buff_level, max_damage)\n\n\tversatile_bt.apply(tower, tower, new_buff_level)\n\n\n# NOTE: \"spreadBuff()\" in original script\nfunc spread_buff():\n\tvar versatile_buff: Buff = tower.get_buff_of_type(versatile_bt)\n\tvar level: int = tower.get_level()\n\tvar buff_duration: float =  2.5 + 0.04 * level\n\n\tif versatile_buff == null:\n\t\treturn\n\n\tvar buff_level: int = versatile_buff.get_level()\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 175)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next != tower:\n\t\t\tversatile_bt.apply_custom_timed(tower, next, buff_level, buff_duration)\n\n\n# NOTE: \"blueDrakeHit()\" in original script\nfunc blue_drake_on_hit(p: Projectile, _target: Unit):\n\tvar damage_before: float = tower.get_total_damage()\n\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(p.get_x(), p.get_y()), 125)\n\n\tif it.count() == 0:\n\t\treturn\n\n\tEffect.create_scaled(\"res://src/effects/freezing_breath.tscn\", p.get_position_wc3(), 0, 2)\n\n\tvar drake_damage: float = 6000 + 150 * tower.get_level()\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tslow_bt.apply(tower, next, 1)\n\t\ttower.do_spell_damage(next, drake_damage, tower.calc_spell_crit_no_bonus())\n\n\tvar damage_after: float = tower.get_total_damage()\n\tvar damage_dealt: float = damage_after - damage_before\n\trefresh_buff(damage_dealt)\n\n\n# NOTE: \"greenDrakeHit()\" in original script\nfunc green_drake_on_hit(_p: Projectile, target: Unit):\n\tvar damage_before: float = tower.get_total_damage()\n\n\tif target == null:\n\t\tspread_buff()\n\n\t\treturn\n\n\ttower.do_spell_damage(target, 5000, tower.calc_spell_crit_no_bonus())\n\n\tvar damage_after: float = tower.get_total_damage()\n\tvar damage_dealt: float = damage_after - damage_before\n\trefresh_buff(damage_dealt)\t\n\tspread_buff()\n\n\n# NOTE: \"redDrakeHit()\" in original script\nfunc red_drake_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar drake_damage: float = tower.get_current_attack_damage_with_bonus() * (2.0 + 0.08 * tower.get_level())\n\tstun_bt.apply_only_timed(tower, target, 3)\n\ttower.do_attack_damage(target, drake_damage, tower.calc_attack_crit_no_bonus())\n\n\n# NOTE: \"sendDrakelingHome ()\" in original script\nfunc send_drakeling_home(p: Projectile):\n\tvar which: int = p.user_int2\n\n\tvar drake: Drake = drake_list[which]\n\tdrake.projectile.set_speed(600)\n\tdrake.projectile.start_bezier_interpolation_to_point(drake.start_pos, 0.15, 0.15, 0.17)\n\tdrake.state = DrakeState.COMING_BACK\n\n\n# NOTE: \"onDrakelingEndInterpol()\" in original script\nfunc generic_drake_pt_on_hit(p: Projectile, target: Unit):\n\tp.avert_destruction()\n\n\tvar which: int = p.user_int2\n\tvar drake: Drake = drake_list[which]\n\n\tif drake.state == DrakeState.COMING_BACK:\n#\t\tWill be used to reset the drake, otherwise the code in Projectile messes with our position right after this event handler\n\t\tp.enable_periodic(1)\n\t\tp.set_remaining_lifetime(999999)\n\n\t\treturn\n\n\tif target != null:\n\t\tif which == RED_I:\n\t\t\tred_drake_on_hit(p, target)\n\t\telif which == BLUE_I:\n\t\t\tblue_drake_on_hit(p, target)\n\t\telse:\n\t\t\tgreen_drake_on_hit(p, target)\n\n\tsend_drakeling_home(p)\n\n\n# NOTE: \"bronzeDrakeTick()\" in original script\nfunc bronze_drake_pt_periodic(p: Projectile):\n\tif p.get_age() > 2:\n\t\tvar color: Color = Color8(255, 255, 255, 255 - int((p.get_age() - 2) / (3 - 2)) * 255)\n\t\tp.set_color(color)\n\n\t\treturn\n\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(p.get_x(), p.get_y()), 600)\n\n\twhile true:\n\t\tvar next: Unit = it.next_random()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next.is_immune():\n\t\t\tbreak\n\n#\t\tTest if the target is in a 90 degree cone in front\n#\t\tof the drake\n\t\tvar position_diff: Vector2 = next.get_position_wc3_2d() - p.get_position_wc3_2d()\n\t\tvar angle_to_creep: float = rad_to_deg(position_diff.angle())\n\t\tvar angle_diff: float = angle_to_creep - p.get_direction()\n\n\t\tvar angle_diff_is_ok: bool = angle_diff <= -310 || angle_diff >= 310 || (angle_diff >= 50 && angle_diff <= 50)\n\n\t\tif !angle_diff_is_ok:\n\t\t\tbreak\n\n\t\tvar offset_vector: Vector2 = Vector2(100, 0).rotated(rad_to_deg(p.get_direction()))\n\t\tvar from_pos: Vector3 = p.get_position_wc3() + Vector3(offset_vector.x, offset_vector.y, 0)\n\n\t\tvar atk_proj: Projectile = Projectile.create_linear_interpolation_from_point_to_unit(bronze_drake_attack_pt, tower, 0, 0, from_pos, next, 0.30, true)\n\t\tatk_proj.set_projectile_scale(0.55)\n\n\n# NOTE: \"onBronzeDrakeHit()\" in original script\nfunc bronze_drake_attack_pt_on_hit(_p: Projectile, target: Unit):\n\tvar damage_before: float = tower.get_total_damage()\n\n\tif target == null:\n\t\treturn\n\n\tvar drake_damage: float = 1250 + 40 * tower.get_level()\n\ttower.do_spell_damage(target, drake_damage, tower.calc_spell_crit_no_bonus())\n\n\tvar damage_after: float = tower.get_total_damage()\n\tvar damage_dealt: float = damage_after - damage_before\n\trefresh_buff(damage_dealt)\n\n\n# NOTE: \"resetPosition()\" in original script\nfunc generic_drake_pt_periodic(p: Projectile):\n\tvar which: int = p.user_int2\n\n\tvar drake: Drake = drake_list[which]\n\n\tp.disable_periodic()\n\n\tp.set_position_wc3(drake.start_pos)\n\tp.set_speed(0)\n\tdrake.state = DrakeState.IDLE\n\n\tvar final_x: float = p.get_x() + (tower.get_x() - p.get_x()) * 10\n\tvar final_y: float = p.get_y() + (tower.get_y() - p.get_y()) * 10\n\tp.aim_at_point(Vector3(final_x, final_y, p.get_z()), false, false)\n"
  },
  {
    "path": "src/towers/tower_behaviors/dreadlord.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed Awakening buff being\n# applied with level 1 always. Use tower's level.\n\n# NOTE: original script uses \"frenzy\" spell as a visual\n# effect. Didn't implement that. Can implement using an\n# Effect.\n\nvar awakening_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tawakening_bt = BuffType.new(\"awakening_bt\", 10, 0, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.5, 0.02)\n\tmod.add_modification(ModificationType.enm.MOD_MANA_REGEN, 20, 0.8)\n\tawakening_bt.set_buff_modifier(mod)\n\tawakening_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_dot.tres\")\n\tawakening_bt.set_buff_tooltip(tr(\"CYSV\"))\n\n\tmultiboard = MultiboardValues.new(2)\n\tvar attack_speed_bonus_label: String = tr(\"CYIQ\")\n\tvar mana_bonus_label: String = tr(\"CUYM\")\n\tmultiboard.set_key(0, attack_speed_bonus_label)\n\tmultiboard.set_key(1, mana_bonus_label)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar damage: float = (1 + 0.04 * tower.get_level()) * tower.get_overall_mana()\n\tvar mana: float = tower.get_mana()\n\n\tif mana >= 80:\n\t\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\t\ttower.subtract_mana(80, 0)\n\t\tEffect.create_scaled(\"res://src/effects/devour.tscn\", Vector3(creep.get_x(), creep.get_y(), 30), 0, 2)\n\n\nfunc on_kill(_event: Event):\n\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.005)\n\ttower.user_real2 += 0.005\n\n\tif tower.user_real <= 2:\n\t\ttower.user_real += 0.01\n\t\ttower.modify_property(ModificationType.enm.MOD_MANA, 10)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar attack_speed_bonus: String = Utils.format_percent(tower.user_real2, 1)\n\tvar mana_bonus: String = str(int(tower.user_real * 1000))\n\tmultiboard.set_value(0, attack_speed_bonus)\n\tmultiboard.set_value(1, mana_bonus)\n\t\n\treturn multiboard\n\n\nfunc on_autocast(_event: Event):\n\tawakening_bt.apply(tower, tower, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/dutchmans_grave.gd",
    "content": "extends TowerBehavior\n\n\nvar panic_bt: BuffType\nvar dutchman_pt: ProjectileType\nvar cannonball_pt: ProjectileType\nvar soul_pt: ProjectileType\nvar soulstorm_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar soul_count: int = 0\nvar soulstorm_is_active: bool = false\nvar timer_soulstorm: float = 0.0\nvar timer_cannonball: float = 0.0\nvar timer_soul: float = 0.0\nvar timer_reorder: float = 0.0\nvar dutchman: Projectile\nvar current_target: Unit = null\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\t\n\tdutchman_pt = ProjectileType.create(\"path_to_projectile_sprite\", 999999, 550, self)\n\tdutchman_pt.enable_periodic(dutchman_pt_periodic, 0.1)\n\tdutchman_pt.enable_homing(dutchman_pt_on_hit, 4.0)\n\n\tcannonball_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\tcannonball_pt.set_event_on_interpolation_finished(cannonball_pt_on_hit)\n\n\tsoul_pt = ProjectileType.create(\"path_to_projectile_sprite\", 6, 300, self)\n\tsoul_pt.enable_homing(soul_pt_on_hit, 4.0)\n\tsoul_pt.set_start_rotation(6.0)\n\n\tsoulstorm_pt = ProjectileType.create(\"path_to_projectile_sprite\", 6, 300, self)\n\tsoulstorm_pt.set_acceleration(10)\n\tsoulstorm_pt.enable_collision(soulstorm_pt_on_collision, 100, TargetType.new(TargetType.CREEPS), false)\n\n\tpanic_bt = BuffType.new(\"panic_bt\", 5, 0, false, self)\n\tvar panic_bt_mod: Modifier = Modifier.new()\n\tpanic_bt_mod.add_modification(ModificationType.enm.MOD_ARMOR, -25.0, -1.0)\n\tpanic_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.20, -0.002)\n\tpanic_bt.set_buff_modifier(panic_bt_mod)\n\tpanic_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\tpanic_bt.set_buff_tooltip(tr(\"EC2N\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar soul_count_label: String = tr(\"X8AI\")\n\tmultiboard.set_key(0, soul_count_label)\n\n\nfunc on_create(_preceding: Tower):\n\tdutchman = Projectile.create_from_unit_to_unit(dutchman_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, tower, true, true, false)\n\tdutchman.set_color(Color8(100, 100, 100, 180))\n\tdutchman.set_projectile_scale(1.0)\n\n\nfunc on_destruct():\n\tdutchman.remove_from_game()\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tdutchman.set_homing_target(target)\n\tcurrent_target = target\n\n\n# NOTE: set damage to 0 because actual damage is dealt via\n# cannonball_pt_on_hit()\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\nfunc on_kill(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar lvl: int = tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 300)\n\n\tsoul_count += 1\n\n\tEffect.create_simple_at_unit(\"res://src/effects/spell_aiso.tscn\", target)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\treturn\n\n\t\tpanic_bt.apply(tower, next, lvl)\n\n\nfunc on_autocast(_event: Event):\n\tsoulstorm_is_active = true\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, str(soul_count))\n\n\treturn multiboard\n\n\n# NOTEL \"Periodic()\" in original script\nfunc dutchman_pt_periodic(_p: Projectile):\n\tif current_target == null || !Utils.unit_is_valid(current_target):\n\t\tcurrent_target = tower\n\t\tdutchman.set_homing_target(tower)\n\n\ttimer_cannonball -= 0.1\n\tif timer_cannonball <= 0.0:\n\t\ttimer_cannonball += tower.get_current_attack_speed()\n\t\tshoot_cannonball()\n\n\ttimer_soul -= 0.1\n\tif timer_soul <= 0.0:\n\t\ttimer_soul = 5.0\n\t\tshoot_soul()\n\n\ttimer_reorder -= 0.1\n\tif timer_reorder <= 0.0:\n\t\ttimer_reorder = 2.0\n\t\tdutchman.set_homing_target(current_target)\n\n\tif soulstorm_is_active:\n\t\ttimer_soulstorm -= 0.1\n\n\t\tif timer_soulstorm <= 0.0:\n\t\t\ttimer_soulstorm = 0.3\n\t\t\tdo_soulstorm()\n\n\n# NOTEL \"Hit()\" in original script\nfunc dutchman_pt_on_hit(p: Projectile, _target: Unit):\n\tp.avert_destruction()\n\n\n# NOTEL \"NAttackHit()\" in original script\nfunc cannonball_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = tower.get_current_attack_damage_with_bonus()\n\ttower.do_attack_damage_aoe_unit(target, 250, damage, tower.calc_attack_multicrit_no_bonus(), 0)\n\n\n# NOTEL \"SoulHit()\" in original script\nfunc soulstorm_pt_on_collision(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", target)\n\n\tvar damage: float = p.user_real\n\tp.do_spell_damage(target, damage)\n\tp.user_real *= 0.5\n\n\n# NOTE: \"Storm()\" in original script\nfunc do_soulstorm():\n\tvar shoot_pos: Vector3 = dutchman.get_position_wc3()\n\n\tif soul_count >= 2:\n\t\tsoul_count -= 2\n\n\t\tvar p1: Projectile = Projectile.create(soulstorm_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), shoot_pos, 0.0)\n\t\tp1.user_real = 14000.0\n\t\tvar p2: Projectile = Projectile.create(soulstorm_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), shoot_pos, 180.0)\n\t\tp2.user_real = 14000.0\n\telse:\n\t\tsoulstorm_is_active = false\n\n\nfunc soul_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = 14000 + 1400 * tower.get_level()\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: \"NAttackFunc()\" in original script\nfunc shoot_cannonball():\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(dutchman.get_x(), dutchman.get_y()), 800)\n\tvar next: Unit = it.next_random()\n\n\tif next != null:\n\t\tvar shoot_pos: Vector3 = dutchman.get_position_wc3()\n\t\tProjectile.create_linear_interpolation_from_point_to_unit(cannonball_pt, tower, 1, 1, shoot_pos, next, 0.4, true)\n\n\n# NOTE: \"SAttackFunc()\" in original script\n# NOTE: original script uses an \"acidbomb\" Cast. Youtd2\n# engine doesn't implement \"acidbomb\" cast/spelltype, so\n# used a projectile instead.\nfunc shoot_soul():\n\tif soul_count < 1:\n\t\treturn\n\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(dutchman.get_x(), dutchman.get_y()), 1200)\n\n\tvar shoot_pos: Vector3 = dutchman.get_position_wc3()\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\treturn\n\n\t\tif next.is_immune():\n\t\t\tcontinue\n\n\t\tsoul_count -= 1\n\n\t\tProjectile.create_from_point_to_unit(soul_pt, tower, 1.0, 1.0, shoot_pos, next, true, false, false)\n\t\t\n\t\tbreak\n"
  },
  {
    "path": "src/towers/tower_behaviors/dwarven_forgery.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL, 0.15, 0.004)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\taura_bt.set_buff_tooltip(tr(\"RSGI\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/ebonfrost_crystal.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original script used a weird method of storing and\n# manipulating Icicle structs. Changed to a different method\n# which is less complex.\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where if you\n# transformed another tower into Ebonfrost, it would not\n# adjust the max icicle count based on tower level. The max\n# icicle count would only get adjusted when the tower\n# leveled up or down, which is bad if the tower is already\n# max level.\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where the effect\n# of Shattering Barrage scaled by tower level when it\n# shouldn't. According to ability description, the debuff\n# \"increases damage taken by 100%\". The actual value was\n# 100% * [tower level], because the Modifier for shatter_bt\n# incorrectly had \"1.0\" args in the \"level_add\" portion\n# (last arg). This caused this tower to occasionally\n# instakill creeps with Shattering Barrage.\n\n\nclass Icicle:\n\tvar projectile: Projectile\n\tvar effect: int\n\tvar position: Vector2\n\n\nconst ICICLE_MAX_BASE: int = 5\n\n\nvar stun_bt: BuffType\nvar frostburn_bt: BuffType\nvar shatter_bt: BuffType\nvar icicle_bt: BuffType\nvar bombardment_pt: ProjectileType\nvar icicle_prop_pt: ProjectileType\nvar icicle_missile_pt: ProjectileType\n\nvar icicle_list: Array[Icicle]\nvar fired_icicle_count: int = 0\nvar fire_all_in_progress: bool = false\nvar prev_stored_icicle_angle: float = 0.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tfrostburn_bt = BuffType.new(\"frostburn_bt\", 5, 0, false, self)\n\tfrostburn_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_dot.tres\")\n\tfrostburn_bt.add_periodic_event(frostburn_bt_periodic, 1.0)\n\tfrostburn_bt.set_buff_tooltip(tr(\"BJQ4\"))\n\n\tshatter_bt = BuffType.new(\"shatter_bt\", 5, 0, false, self)\n\tshatter_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\tvar ashbringer_ebonfrost_shatter_mod: Modifier = Modifier.new()\n\tashbringer_ebonfrost_shatter_mod.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, 1.0, 0.0)\n\tashbringer_ebonfrost_shatter_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 1.0, 0.0)\n\tshatter_bt.set_buff_modifier(ashbringer_ebonfrost_shatter_mod)\n\tshatter_bt.add_event_on_create(shatter_bt_on_create)\n\tshatter_bt.set_buff_tooltip(tr(\"IFK5\"))\n\n\ticicle_bt = BuffType.new(\"icicle_bt\", -1, 0, true, self)\n\tvar ashbringer_ebonfrost_icicle_mod: Modifier = Modifier.new()\n\tashbringer_ebonfrost_icicle_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.05)\n\tashbringer_ebonfrost_icicle_mod.add_modification(ModificationType.enm.MOD_MANA_REGEN, 0.0, 0.5)\n\ticicle_bt.set_buff_modifier(ashbringer_ebonfrost_icicle_mod)\n\ticicle_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\ticicle_bt.set_buff_tooltip(tr(\"XNT1\"))\n\n# \tNOTE: in original script, this ProjectileType.create()\n# \tis called here but this ProjectileType is later used as\n# \tan interpolated projectile. Changed to use\n# \tcreate_interpolate().\n\tbombardment_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1650, self)\n\tbombardment_pt.set_event_on_cleanup(bombardment_pt_on_hit)\n\n\ticicle_prop_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 200, self)\n\ticicle_prop_pt.set_event_on_interpolation_finished(icicle_prop_pt_on_finished)\n\ticicle_prop_pt.disable_explode_on_expiration()\n\n\ticicle_missile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 5, 1400, self)\n\ticicle_missile_pt.enable_homing(icicle_missile_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar icy_bombardment_chance: float = 0.15 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(icy_bombardment_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Icy Bombardment\")\n\tashbringer_icy_bombardment(target)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar damage: float = event.damage\n\tvar icicle_chance: float = 0.15 + 0.004 * tower.get_level()\n\n\tashbringer_frostburn_damage(target, damage)\n\tevent.damage = 0\n\n\tif tower.calc_chance(icicle_chance):\n\t\tCombatLog.log_ability(tower, target, \"Icicle\")\n\t\tashbringer_icicle_create(target)\n\n\nfunc on_destruct():\n\tfor icicle in icicle_list:\n\t\tvar projectile: Projectile = icicle.projectile\n\t\tprojectile.remove_from_game()\n\n\t\tvar effect: int = icicle.effect\n\t\tEffect.destroy_effect(effect)\n\n\ticicle_list.clear()\n\n\nfunc on_autocast(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar tower_mana: float = tower.get_mana()\n\tvar duration: float = tower_mana / (150 - tower.get_level())\n\n\tif target.get_size() == CreepSize.enm.BOSS:\n\t\tduration *= 0.25\n\n\t\tif duration < 2.0:\n\t\t\tduration = 2.0\n\n\tshatter_bt.apply_custom_timed(tower, target, tower.get_level(), duration)\n\ttower.subtract_mana(tower_mana, true)\n\n\n# NOTE: this Icicle is fired straight from the tower so we\n# don't need to clean up it's effect or remove it from\n# icicle list because that setup was never performed for it.\nfunc ashbringer_icicle_fire_single(target: Unit):\n\tvar start_pos: Vector3 = tower.get_position_wc3()\n\t\n\tCombatLog.log_ability(tower, target, \"Fire single Icicle\")\n\tvar p: Projectile = Projectile.create_from_point_to_unit(icicle_missile_pt, tower, 0, 0, start_pos, target, true, false, false)\n\tp.set_projectile_scale(0.7)\n\n\tfired_icicle_count += 1\n\n\n# NOTE: original script performs complex logic to have\n# position \"slots\" for each icicle. Replaced this logic with\n# simpler version where new icicles are placed in a rotating\n# fashion. Position of new icicle = position of prev icicle\n# slightly rotated.\nfunc ashbringer_icicle_store():\n\tvar icicle_count_max: int = get_icicle_count_max()\n\n\tCombatLog.log_ability(tower, null, \"Store Icicle - %d\" % icicle_list.size())\n\n# \tNOTE: original script does this in a different way more\n# \tcomplicated way. Changed to this simpler method which\n# \tachieves almost the same result.\n\tvar angle: float = prev_stored_icicle_angle + 360 / icicle_count_max\n\tprev_stored_icicle_angle = angle\n\n\tvar offset: Vector2 = Vector2(100, 0).rotated(deg_to_rad(angle))\n\tvar start_pos: Vector3 = Vector3(tower.get_x(), tower.get_y(), 200)\n\tvar icicle_pos: Vector3 = Vector3(tower.get_x() + offset.x, tower.get_y() + offset.y, 200)\n\tvar p: Projectile = Projectile.create_linear_interpolation_from_point_to_point(icicle_prop_pt, tower, 1.0, 0.0, start_pos, icicle_pos, 0.0)\n\tp.set_projectile_scale(0.7)\n\tp.user_real = icicle_pos.x\n\tp.user_real2 = icicle_pos.y\n\tp.user_real3 = angle\n\n\tvar icicle: Icicle = Icicle.new()\n\ticicle.projectile = p\n\ticicle.position = VectorUtils.vector3_to_vector2(icicle_pos)\n\ticicle_list.append(icicle)\n\n\tvar icicle_count: int = icicle_list.size()\n\tvar buff: Buff = icicle_bt.apply(tower, tower, icicle_count)\n\tbuff.set_displayed_stacks(icicle_count)\n\n\nfunc icicle_prop_pt_on_finished(p: Projectile, _target: Unit):\n\tvar icicle_x: float = p.user_real\n\tvar icicle_y: float = p.user_real2\n\tvar angle: float = p.user_real3\n\n\tvar icicle: Icicle = null\n\n\tfor the_icicle in icicle_list:\n\t\tif the_icicle.projectile == p:\n\t\t\ticicle = the_icicle\n\n\tif icicle == null:\n\t\treturn\n\n#\tNOTE: added this call, doesn't exist in original script.\n#\tI think maybe in JASS engine interpolated projectiles\n#\twithout target unit are not destroyed when they reached\n#\tthe target point?\n\tp.avert_destruction()\n\n\tvar effect: int = Effect.create_scaled(\"res://src/effects/mana_shield_cycle.tscn\", Vector3(icicle_x, icicle_y, 200), angle, 0.5)\n\tEffect.set_auto_destroy_enabled(effect, false)\n\ticicle.effect = effect\n\n\nfunc ashbringer_icicle_create(target: Unit):\n\tvar icicle_count: int = icicle_list.size()\n\tvar icicle_count_max: int = get_icicle_count_max()\n\tvar have_icicle_space: bool = icicle_count < icicle_count_max\n\tvar should_store_icicle: bool = have_icicle_space && !fire_all_in_progress\n\n\tif should_store_icicle:\n\t\tashbringer_icicle_store()\n\telse:\n\t\tashbringer_icicle_fire_single(target)\n\n\nfunc ashbringer_frostburn_damage(target: Unit, damage: float):\n\tvar dot_inc = 1.0 + 0.01 * tower.get_level()\n\n\ttower.do_attack_damage(target, damage * 0.5, tower.calc_attack_multicrit_no_bonus())\n\n\tvar old_buff: Buff = target.get_buff_of_type(frostburn_bt)\n\n\tvar dot_damage: float = damage * 0.5 * dot_inc\n\tif old_buff != null:\n\t\tdot_damage += old_buff.user_real\n\n\tvar new_buff: Buff = frostburn_bt.apply(tower, target, 0)\n\tnew_buff.user_real = dot_damage\n\n\nfunc frostburn_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Creep = buff.get_buffed_unit()\n\tvar remaining: float = buff.get_remaining_duration()\n\tvar damage_tick: float = buff.user_real / remaining\n\n\tif remaining < 1:\n\t\tdamage_tick = buff.user_real\n\n\tif damage_tick > 0:\n\t\tbuff.user_real -= damage_tick\n\t\ttower.do_spell_damage(target, damage_tick, tower.calc_spell_crit_no_bonus())\n\n\nfunc icicle_missile_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = (3000 + 80 * tower.get_level()) * (1.0 + 0.02 * fired_icicle_count)\n\n\tashbringer_frostburn_damage(target, damage)\n\n\nfunc ashbringer_icicle_fire_all(target: Unit):\n#\tSet this flag so that any icicles created while this\n#\tfunction is running are fired instantly. Icicles may be\n#\tcreated because of ON_DAMAGE event.\n\tfire_all_in_progress = true\n\n\tCombatLog.log_ability(tower, target, \"Fire all Icicles - %d\" % icicle_list.size())\n\n\twhile !icicle_list.is_empty():\n\t\tvar icicle: Icicle = icicle_list.pop_front()\n\n\t\tvar start_pos: Vector3 = Vector3(icicle.position.x, icicle.position.y, 200)\n\t\tvar icicle_missile: Projectile = Projectile.create_from_point_to_unit(icicle_missile_pt, tower, 0, 0, start_pos, target, true, false, false)\n\t\ticicle_missile.set_projectile_scale(0.7)\n\t\ticicle_missile.set_speed(1400 - 70 * icicle_list.size())\n\t\tfired_icicle_count += 1\n\n\t\ticicle.projectile.remove_from_game()\n\t\tEffect.destroy_effect(icicle.effect)\n\t\t\n\t\ticicle_list.erase(icicle)\n\n\tvar buff: Buff = tower.get_buff_of_type(icicle_bt)\n\tif buff != null:\n\t\tbuff.remove_buff()\n\n\tfire_all_in_progress = false\n\n\nfunc ashbringer_icy_bombardment(target: Unit):\n\tvar chance: float = 0.3 + 0.004 * tower.get_level()\n\tvar shot_count: int = 0\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\n\twhile true:\n\t\tvar random_angle: float = deg_to_rad(Globals.synced_rng.randf_range(0, 360))\n\t\tvar random_distance: float = Globals.synced_rng.randf_range(0, 150)\n\t\tvar offset: Vector2 = Vector2(random_distance, 0).rotated(random_angle)\n\t\tvar launch_pos_2d: Vector2 = target_pos + offset\n\t\tvar launch_pos: Vector3 = Vector3(launch_pos_2d.x, launch_pos_2d.y, 0)\n\t\tvar p: Projectile = Projectile.create_linear_interpolation_from_point_to_point(bombardment_pt, tower, 0, 0, Vector3(tower.get_x(), tower.get_y(), 200), launch_pos, 0.2)\n\t\tp.user_real = launch_pos.x\n\t\tp.user_real2 = launch_pos.y\n\n\t\tshot_count += 1\n\n\t\tif !tower.calc_chance(chance) || shot_count >= 4:\n\t\t\tbreak\n\n\nfunc bombardment_pt_on_hit(p: Projectile):\n\tvar launch_x: float = p.user_real\n\tvar launch_y: float = p.user_real2\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(launch_x, launch_y), 200)\n\tvar damage: float = tower.get_current_attack_damage_with_bonus() * (0.25 + 0.006 * tower.get_level())\n\tvar icicle_chance: float = 0.05 + 0.001 * tower.get_level()\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tashbringer_frostburn_damage(next, damage)\n\n\t\tif tower.calc_chance(icicle_chance):\n\t\t\tashbringer_icicle_create(next)\n\n\nfunc shatter_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar target: Creep = buff.get_buffed_unit()\n\n\tstun_bt.apply_only_timed(caster, target, buff.get_remaining_duration())\n\tashbringer_icicle_fire_all(target)\n\n\nfunc get_icicle_count_max() -> int:\n\tvar bonus_from_lvls: int = floori(tower.get_level() / 5) \n\tvar count: int = ICICLE_MAX_BASE + bonus_from_lvls\n\n\treturn count\n"
  },
  {
    "path": "src/towers/tower_behaviors/embershell_turtle_hatchling.gd",
    "content": "extends TowerBehavior\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_attack(on_attack)\n\n\nfunc on_attack(_event: Event):\n\tvar mana: float = tower.get_mana()\n\n\tif mana < 1:\n\t\ttower.order_stop()\n\telse:\n\t\ttower.set_mana(mana - 1)\n"
  },
  {
    "path": "src/towers/tower_behaviors/empty_tower_behavior.gd",
    "content": "extends TowerBehavior\n\n# NOTE: this is an empty script to be used for towers which\n# don't have any behavior to put in a script.\n"
  },
  {
    "path": "src/towers/tower_behaviors/energy_junction.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original function removed all buffs made by this\n# tower in on_destruct() to remove visual effects. This is\n# not needed in godot engine because buffs are already\n# automatically removed when one of their event handlers is\n# removed.\n\n\nvar jolt_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {attack_speed = 0.2, attack_speed_add = 0.002, damage_on_attack = 150},\n\t\t2: {attack_speed = 0.25, attack_speed_add = 0.004, damage_on_attack = 320},\n\t\t3: {attack_speed = 0.32, attack_speed_add = 0.0052, damage_on_attack = 500},\n\t}\n\n\nfunc junction_on_create(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar buffee: Tower = b.get_buffed_unit()\n\n\tb.user_int = 0\n\n\tif tower != buffee:\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, tower, buffee)\n\t\tlightning.modulate = Color.LIGHT_BLUE\n\t\tb.user_int = lightning.get_instance_id()\n\n#\tNOTE: add & save attack speed\n\tb.user_real = tower.user_real + tower.user_real2 * tower.get_level()\n\tbuffee.modify_property(ModificationType.enm.MOD_ATTACKSPEED, b.user_real)\n\n\nfunc junction_on_damage(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar caster: Tower = b.get_caster()\n\tvar buffee: Tower = b.get_buffed_unit()\n\tvar creep: Creep = event.get_target()\n\tvar damage: float = caster.user_real3 * (1 + caster.get_level() / 25.0) * buffee.get_base_attack_speed()\n\n\tbuffee.do_spell_damage(creep, damage, buffee.calc_spell_crit_no_bonus())\n\tbuffee.do_attack_damage(creep, damage, buffee.calc_attack_multicrit(0, 0, 0))\n\n\tEffect.create_simple_at_unit(\"res://src/effects/purge_buff_target.tscn\", creep)\n\n\nfunc junction_on_cleanup(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tif b.user_int != 0:\n\t\tvar lightning: InterpolatedSprite = instance_from_id(b.user_int) as InterpolatedSprite\n\t\tif lightning != null:\n\t\t\tlightning.queue_free()\n\n\tb.get_buffed_unit().modify_property(ModificationType.enm.MOD_ATTACKSPEED, -b.user_real)\n\n\nfunc tower_init():\n\tjolt_bt = BuffType.new(\"jolt_bt\", 10, 0, true, self)\n\tjolt_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\tjolt_bt.add_event_on_create(junction_on_create)\n\tjolt_bt.add_event_on_attack(junction_on_damage)\n\tjolt_bt.add_event_on_cleanup(junction_on_cleanup)\n\tjolt_bt.set_buff_tooltip(tr(\"J0NB\"))\n\n\nfunc on_create(_preceding_tower: Tower):\n# \tbase attack_speed boost\n\ttower.user_real = _stats.attack_speed\n# \tattack speed boost add\n\ttower.user_real2 = _stats.attack_speed_add\n# \tbase dmg & spelldmg per attack (/25 for level bonus)\n\ttower.user_real3 = _stats.damage_on_attack\n"
  },
  {
    "path": "src/towers/tower_behaviors/essence_of_fury.gd",
    "content": "extends TowerBehavior\n\n\nvar poison_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {poison_damage = 25, poison_damage_add = 1, poison_duration_add = 0.1},\n\t\t2: {poison_damage = 75, poison_damage_add = 3, poison_duration_add = 0.2},\n\t\t3: {poison_damage = 150, poison_damage_add = 6, poison_duration_add = 0.3},\n\t\t4: {poison_damage = 300, poison_damage_add = 12, poison_duration_add = 0.4},\n\t\t5: {poison_damage = 625, poison_damage_add = 25, poison_duration_add = 0.5},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc deal_damage(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tvar creep: Unit = b.get_buffed_unit()\n\ttower.do_spell_damage(creep, b.user_real, tower.calc_spell_crit_no_bonus())\n\n\nfunc tower_init():\n\tpoison_bt = BuffType.new(\"poison_bt\", 9, 0.5, false, self)\n\tpoison_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\n\tpoison_bt.add_periodic_event(deal_damage, 1)\n\n\tpoison_bt.set_buff_tooltip(tr(\"LSQD\"))\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\n\tpoison_bt.apply_custom_timed(tower, creep, tower.get_level(), 6 + tower.get_level() * _stats.poison_duration_add).user_real = _stats.poison_damage + _stats.poison_damage_add * tower.get_level()\n"
  },
  {
    "path": "src/towers/tower_behaviors/felweed.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {bonus_1_attack_count = 7, bonus_1 = 1.10, bonus_2 = 1.20, bonus_3 = 1.30, bonus_4 = 1.40, bonus_1_add = 0.002, bonus_2_add = 0.004, bonus_3_add = 0.006, bonus_4_add = 0.008},\n\t\t2: {bonus_1_attack_count = 7, bonus_1 = 1.10, bonus_2 = 1.20, bonus_3 = 1.30, bonus_4 = 1.40, bonus_1_add = 0.002, bonus_2_add = 0.004, bonus_3_add = 0.006, bonus_4_add = 0.008},\n\t\t3: {bonus_1_attack_count = 6, bonus_1 = 1.125, bonus_2 = 1.25, bonus_3 = 1.375, bonus_4 = 1.50, bonus_1_add = 0.0025, bonus_2_add = 0.005, bonus_3_add = 0.0075, bonus_4_add = 0.01},\n\t\t4: {bonus_1_attack_count = 6, bonus_1 = 1.125, bonus_2 = 1.25, bonus_3 = 1.375, bonus_4 = 1.50, bonus_1_add = 0.0025, bonus_2_add = 0.005, bonus_3_add = 0.0075, bonus_4_add = 0.01},\n\t\t5: {bonus_1_attack_count = 5, bonus_1 = 1.15, bonus_2 = 1.30, bonus_3 = 1.45, bonus_4 = 1.60, bonus_1_add = 0.003, bonus_2_add = 0.006, bonus_3_add = 0.009, bonus_4_add = 0.012},\n\t\t6: {bonus_1_attack_count = 5, bonus_1 = 1.15, bonus_2 = 1.30, bonus_3 = 1.45, bonus_4 = 1.60, bonus_1_add = 0.003, bonus_2_add = 0.006, bonus_3_add = 0.009, bonus_4_add = 0.012},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.user_int2 = 0\n\ttower.user_int3 = 0\n\ttower.user_real = 0\n\n\nfunc on_damage(event: Event):\n\tvar damage: float = event.damage\n\tvar level: int = tower.get_level()\n\n\ttower.user_int = tower.user_int + 1\n\ttower.user_int2 = tower.user_int2 + 1\n\ttower.user_int3 = tower.user_int3 + 1\n\ttower.user_real = tower.user_real + 1\n\n\tvar bonus_1_attack_count: int = _stats.bonus_1_attack_count\n\tvar bonus_2_attack_count: int = _stats.bonus_1_attack_count + 1\n\tvar bonus_3_attack_count: int = _stats.bonus_1_attack_count + 2\n\tvar bonus_4_attack_count: int = _stats.bonus_1_attack_count + 3\n\n\tif tower.user_int >= bonus_1_attack_count:\n\t\tevent.damage = event.damage * (_stats.bonus_1 + level * _stats.bonus_1_add)\n\t\ttower.user_int = 0\n\n\tif tower.user_int2 >= bonus_2_attack_count:\n\t\tevent.damage = event.damage * (_stats.bonus_2 + level * _stats.bonus_2_add)\n\t\ttower.user_int2 = 0\n\n\tif tower.user_int3 >= bonus_3_attack_count:\n\t\tevent.damage = event.damage * (_stats.bonus_3 + level * _stats.bonus_3_add)\n\t\ttower.user_int3 = 0\n\n\tif tower.user_real >= bonus_4_attack_count:\n\t\tevent.damage = event.damage * (_stats.bonus_4 + level * _stats.bonus_4_add)\n\t\ttower.user_real = 0\n\n\tif event.damage > damage:\n\t\tvar bonus_damage_text: String = Utils.format_float(event.damage, 0)\n\t\ttower.get_player().display_small_floating_text(bonus_damage_text, tower, Color8(190, 50, 50), 0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/fenced_flames.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug in original script\n# where periodic() didn't multiply dmg_ratio_add value by\n# tower level.\n\n\nconst EMBER_RADIUS: float = 300\n\nvar TARGET_TYPE_COMMON_TOWERS: TargetType = TargetType.new(TargetType.TOWERS + TargetType.RARITY_COMMON)\nvar ember_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {dmg_ratio = 0.08, dmg_ratio_add = 0.0016},\n\t\t2: {dmg_ratio = 0.10, dmg_ratio_add = 0.0020},\n\t\t3: {dmg_ratio = 0.12, dmg_ratio_add = 0.0048},\n\t\t4: {dmg_ratio = 0.16, dmg_ratio_add = 0.0064},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\tember_pt = ProjectileType.create_interpolate(\"res://src/projectiles/projectile_visuals/HeadhunterWEAPONSLeft.tscn\", 650, self)\n\tember_pt.set_event_on_interpolation_finished(ember_pt_on_hit)\n\n\nfunc periodic(_event: Event):\n\tvar towers_in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TARGET_TYPE_COMMON_TOWERS, EMBER_RADIUS)\n\n\tvar common_tower: Unit = towers_in_range.next()\n\n\tif common_tower == null:\n\t\treturn\n\n#\tNOTE: need to add RANGE_CHECK_BONUS_FOR_TOWERS to\n#\taccount for tower radius, bit of a hack to get real\n#\tattack range. Iterate class only takes target radius into\n#\tconsideration.\n\tvar creeps_in_range: Iterate = Iterate.over_units_in_range_of_caster(common_tower, TargetType.new(TargetType.CREEPS), tower.get_range() + Constants.RANGE_CHECK_BONUS_FOR_TOWERS)\n\n\tvar dmg_ratio: float = _stats.dmg_ratio + _stats.dmg_ratio_add * tower.get_level()\n\n\twhile true:\n\t\tvar target: Unit = creeps_in_range.next_random()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\t# Need to change speed of ProjectileType before\n\t\t# creating projectile because cannot change\n\t\t# interpolated Projectile's speed after creation\n\t\tvar ember_speed: float = Globals.synced_rng.randf_range(500, 750)\n\t\tember_pt.set_speed(ember_speed)\n\t\tvar p: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(ember_pt, common_tower, 1, 1, common_tower, target, Globals.synced_rng.randf_range(0.0, 0.3), Globals.synced_rng.randf_range(-0.8, 0.8), Globals.synced_rng.randf_range(0.1, 0.4), true)\n\t\tp.set_color(Color.DARK_RED)\n\n\t\tvar damage: float = common_tower.get_current_attack_damage_with_bonus() * dmg_ratio\n\t\tvar crit: float = common_tower.calc_attack_multicrit_no_bonus()\n\t\tp.user_real = damage\n\t\tp.user_real2 = crit\n\n\n# NOTE: interpolateFinished() in original script\nfunc ember_pt_on_hit(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\t\n\tvar damage: float = p.user_real\n\tvar crit: float = p.user_real2\n\n\ttower.do_custom_attack_damage(target, damage, crit, AttackType.enm.ELEMENTAL)\n"
  },
  {
    "path": "src/towers/tower_behaviors/fiery_dog.gd",
    "content": "extends TowerBehavior\n\n\nvar roar_bt: BuffType\n\n# NOTE: level_multiplier here is basically a magic number.\n# Here's a table from original script demonstrating how it\n# works for tier 2:\n#\n# 0.0005  0.003, 0.0045, 0.006, 0.0075, 0.009\n# 0.05    0.05 , 0.05  , 0.05 , 0.05  , 0.05\n#         70   , 210   , 840  , 1680  , 3360\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {level_multiplier = 6},\n\t\t2: {level_multiplier = 9},\n\t\t3: {level_multiplier = 12},\n\t\t4: {level_multiplier = 15},\n\t\t5: {level_multiplier = 18},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.05, 0.0005)\n\n\troar_bt = BuffType.new(\"roar_bt\", 5.0, 0.0, true, self)\n\troar_bt.set_buff_icon(\"res://resources/icons/generic_icons/wolf_howl.tres\")\n\troar_bt.set_buff_modifier(mod)\n\n\troar_bt.set_buff_tooltip(tr(\"HWW3\"))\n\n\n# NOTE: need to skip stacking for buffs with stronger active\n# tier. apply() will reject buffs from lower tier tower, so\n# it's not possible to increase level and therefore stacks.\nfunc on_damage(_event: Event):\n\tif !tower.calc_chance(0.3):\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\n\tCombatLog.log_ability(tower, null, \"Roar\")\n\n\tvar I: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 420.0)\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/roar.tscn\", tower, Unit.BodyPart.ORIGIN)\n\n\twhile true:\n\t\tvar target: Unit = I.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tvar original_buff: Buff = target.get_buff_of_type(roar_bt)\n\n\t\tvar original_stacks: int = 0\n\t\tvar original_buff_level: int = 0\n\t\tif original_buff != null:\n\t\t\toriginal_stacks = original_buff.user_int\n\t\t\toriginal_buff_level = original_buff.get_level()\n\n\t\tvar new_stacks: int\n\t\tvar new_buff_level: int\n\t\tif original_buff == null:\n\t\t\tnew_stacks = 1\n\t\t\tnew_buff_level = _stats.level_multiplier * level\n\t\telse:\n\t\t\tif original_stacks < 100:\n\t\t\t\tnew_stacks = original_stacks + 1\n\t\t\t\tnew_buff_level = original_buff_level + _stats.level_multiplier\n\t\t\telse:\n\t\t\t\tnew_stacks = original_stacks\n\t\t\t\tnew_buff_level = original_buff_level\n\n\t\tvar new_buff: Buff = roar_bt.apply(tower, target, new_buff_level)\n\n#\t\tNOTE: need to check for this condition because\n#\t\tapply() can reject reapply if this tower has lower\n#\t\ttier than the original buff caster. In that case,\n#\t\tlower tier tower can't increase level of buff -\n#\t\ttherefore can't increase stacks.\n\t\tvar was_able_to_increase_stacks: bool = new_buff.get_level() == new_buff_level\n\t\tif was_able_to_increase_stacks:\n\t\t\tnew_buff.user_int = new_stacks\n\t\t\tnew_buff.set_displayed_stacks(new_stacks)\n"
  },
  {
    "path": "src/towers/tower_behaviors/fire_battery.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: rewrote script a bit. Instead of enabling/disabling\n# periodic event I added a flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where it refunds the cost of autocast in\n# on_autocast(). It refunds the cost by calling set_mana()\n# but the problem is that at the time when on_autocast() is\n# called, the mana cost has not been spent yet. Therefore,\n# refund fails if tower is at max mana because set_mana()\n# can't go above max mana. Not critical - don't need to fix.\n\n\nvar incinerate_bt: BuffType\nvar fireball_pt: ProjectileType\n\nvar _battery_overload_is_active: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 300, projectile_damage_add = 12, periodic_damage = 120, periodic_damage_add = 5, mod_dmg_from_fire = 0.05},\n\t\t2: {projectile_damage = 750, projectile_damage_add = 30, periodic_damage = 300, periodic_damage_add = 12, mod_dmg_from_fire = 0.10},\n\t\t3: {projectile_damage = 1800, projectile_damage_add = 72, periodic_damage = 800, periodic_damage_add = 32, mod_dmg_from_fire = 0.15},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc on_autocast(_event: Event):\n\ttower.set_mana(tower.get_mana() + 100)\n\t_battery_overload_is_active = true\n\n\nfunc damage_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.periodic_damage + _stats.periodic_damage_add * level\n\t\n\ttower.do_spell_damage(buffed_unit, damage, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: hit() in original script\nfunc fireball_pt_on_hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.projectile_damage + _stats.projectile_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tincinerate_bt.apply(tower, creep, level)\n\n\nfunc tower_init():\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_DMG_FROM_FIRE, _stats.mod_dmg_from_fire, 0)\n\n\tincinerate_bt = BuffType.new(\"incinerate_bt\", 9, 0.3, false, self)\n\tincinerate_bt.set_buff_modifier(modifier)\n\tincinerate_bt.set_buff_icon(\"res://resources/icons/mechanical/battery.tres\")\n\tincinerate_bt.add_periodic_event(damage_periodic, 1)\n\tincinerate_bt.set_buff_tooltip(tr(\"HLM9\"))\n\n\tfireball_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\tfireball_pt.enable_homing(fireball_pt_on_hit, 0)\n\n\nfunc on_damage(event: Event):\n\tincinerate_bt.apply(tower, event.get_target(), tower.get_level())\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.set_mana(0)\n\n\nfunc periodic(_event: Event):\n\tif !_battery_overload_is_active:\n\t\treturn\n\n\tif tower.get_mana() > 10:\n\t\tvar in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar target: Unit = in_range.next_random()\n\n\t\tif target != null:\n# \t\t\tNOTE: original script used createFromPointToUnit and made projectiles from high above the tower\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(fireball_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\t\tp.set_projectile_scale(0.5)\n\n#\t\tSpend mana, note that mana is used for unsuccessful\n#\t\tattempts as well\n\t\ttower.set_mana(tower.get_mana() - 10)\n\telse:\n#\t\tTower is out of mana so stop shooting\n\t\t_battery_overload_is_active = false\n"
  },
  {
    "path": "src/towers/tower_behaviors/fire_star.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where Ignite stacks\n# did not get increased damage because that was implemented\n# in REFRESH callback, which never got called. REFRESH\n# callback gets called if buff is applied with same level\n# and less or lower power. Everytime Ignite is reapplied, it\n# gets increased power, so therefore it always triggers\n# UPGRADE instead of REFRESH.\n# \n# Instead, multiplier is calculated right before it's needed.\n\n\nvar ignite_bt: BuffType\nvar firestar_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tignite_bt = BuffType.new(\"ignite_bt\", 2.5, 0, false, self)\n\tvar ignite_bt_mod: Modifier = Modifier.new()\n\tignite_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.05, -0.01)\n\tignite_bt.set_buff_modifier(ignite_bt_mod)\n\tignite_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\tignite_bt.set_buff_tooltip(tr(\"YCEP\"))\n\tignite_bt.add_periodic_event(ignite_bt_periodic, 2.0)\n\n\tfirestar_pt = ProjectileType.create(\"path_to_projectile_sprite\", 7.0, 1000, self)\n\tfirestar_pt.enable_homing(firestar_pt_on_hit, 0)\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar target: Unit = event.get_target()\n\n\tapply_ignite(target)\n\n\tvar double_trouble_chance: float = 0.125 + 0.005 * level\n\n\tif !tower.calc_chance(double_trouble_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Double the Trouble\")\n\n\tProjectile.create_from_unit_to_unit(firestar_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\n\nfunc firestar_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tapply_ignite(target)\n\n\ttower.do_attack_damage(target, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit_no_bonus())\n\n\nfunc ignite_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar level: int = tower.get_level()\n\n\tvar base_multiplier: float = 1.0 + 0.04 * level\n\tvar damage_multiplier_per_stack: float = 0.05 + 0.002 * level\n\tvar stack_count: int = buff.get_level()\n\tvar damage_multiplier: float = base_multiplier + damage_multiplier_per_stack * stack_count\n\n\ttower.do_attack_damage(creep, tower.get_current_attack_damage_with_bonus() * damage_multiplier, tower.calc_attack_multicrit_no_bonus())\n\n\nfunc apply_ignite(target: Unit):\n\tvar buff: Buff = target.get_buff_of_type(ignite_bt)\n\n\tvar active_stacks: int\n\tif buff != null:\n\t\tactive_stacks = buff.get_level()\n\telse:\n\t\tactive_stacks = 0\n\n\tvar new_stacks: int = active_stacks + 1\n\n\tbuff = ignite_bt.apply(tower, target, new_stacks)\n\tbuff.set_displayed_stacks(new_stacks)\n"
  },
  {
    "path": "src/towers/tower_behaviors/firestorm_cell.gd",
    "content": "extends TowerBehavior\n\n\nvar firestorm_bt: BuffType\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {firestorm_chance = 0.12, firestorm_chance_add = 0.004, firestorm_damage = 100, firestorm_damage_add = 3},\n\t\t2: {firestorm_chance = 0.16, firestorm_chance_add = 0.005, firestorm_damage = 300, firestorm_damage_add = 10},\n\t\t3: {firestorm_chance = 0.20, firestorm_chance_add = 0.006, firestorm_damage = 800, firestorm_damage_add = 35},\n\t\t4: {firestorm_chance = 0.24, firestorm_chance_add = 0.007, firestorm_damage = 1400, firestorm_damage_add = 65},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc ashbringer_firestorm_damage(creep: Unit):\n\tvar effect: int = Effect.create_scaled(\"res://src/effects/doom_death.tscn\", Vector3(creep.get_x(), creep.get_y(), 0), 0, 0.4)\n\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\ttower.do_spell_damage_aoe_unit(creep, 300, _stats.firestorm_damage + (_stats.firestorm_damage_add * tower.get_level()), tower.calc_spell_crit_no_bonus(), 0.0)\n\n\nfunc ashbringer_firestorm_periodic(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar target: Unit = b.get_buffed_unit()\n\tb.user_int = b.user_int - 1\n\tif b.user_int <= 0:\n#\t\tneed to do it in this order, because the damage can\n#\t\tkill the buff carrier, and removing buff after the\n#\t\tcarrier is dead causes double free\n\t\tb.remove_buff()\n\tashbringer_firestorm_damage(target)\n\n\nfunc firestorm(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit() \n\tvar damage_per_stack: float = _stats.firestorm_damage + _stats.firestorm_damage_add * tower.get_level()\n\tvar stack_count: int = buff.user_int\n\tvar damage: float = damage_per_stack * stack_count\n\n\tvar effect: int = Effect.create_scaled(\"res://src/effects/doom_death.tscn\", Vector3(creep.get_x(), creep.get_y(), 0), 0, 0.8)\n\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\n\ttower.do_spell_damage_aoe_unit(creep, 300, damage, tower.calc_spell_crit_no_bonus(), 0.0)\n\n\nfunc tower_init():\n\tfirestorm_bt = BuffType.new(\"firestorm_bt\", 1000, 0, false, self)\n\tfirestorm_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tfirestorm_bt.set_buff_tooltip(tr(\"WVLM\"))\n\tfirestorm_bt.add_periodic_event(ashbringer_firestorm_periodic, 1)\n\tfirestorm_bt.add_event_on_death(firestorm)\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(_stats.firestorm_chance + _stats.firestorm_chance_add * tower.get_level()):\n\t\treturn\n\n\tvar creep: Unit = event.get_target()\n\tvar buff: Buff = creep.get_buff_of_type(firestorm_bt)\n\n\tCombatLog.log_ability(tower, creep, \"Firestorm\")\n\n\tif buff != null:\n\t\tashbringer_firestorm_damage(creep)\n\n\tvar active_stack_count: int\n\tif buff != null:\n\t\tactive_stack_count = buff.user_int\n\telse:\n\t\tactive_stack_count = 0\n\n#\tNOTE: doing +2 here instead of +3 because one stack\n#\tis consumed instantly\n\tvar new_stack_count: int\n\tif buff != null:\n\t\tnew_stack_count = active_stack_count + 2\n\telse:\n\t\tnew_stack_count = 3\n\n\tbuff = firestorm_bt.apply(tower, creep, 1)\n\tbuff.user_int = new_stack_count\n\tbuff.set_displayed_stacks(new_stack_count)\n"
  },
  {
    "path": "src/towers/tower_behaviors/fisherman.gd",
    "content": "extends TowerBehavior\n\n\nvar dps_boost_bt: BuffType\nvar slow_bt: BuffType\nvar multiboard: MultiboardValues\n\nvar current_attack_target: int = -1\nvar current_attack_count: int = -1\nvar strangle_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tdps_boost_bt = BuffType.new(\"dps_boost_bt\", 0, 0, true, self)\n\tvar fisherman_dps_boost_mod: Modifier = Modifier.new()\n\tfisherman_dps_boost_mod.add_modification(ModificationType.enm.MOD_DPS_ADD, 0.0, 0.001)\n\tdps_boost_bt.set_buff_modifier(fisherman_dps_boost_mod)\n\tdps_boost_bt.set_buff_icon(\"res://resources/icons/generic_icons/meat.tres\")\n\tdps_boost_bt.set_buff_tooltip(tr(\"ZRPB\"))\n\n\tslow_bt = BuffType.new(\"slow_bt\", 3, 0, false, self)\n\tvar fisherman_slow_mod: Modifier = Modifier.new()\n\tfisherman_slow_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.25, -0.01)\n\tslow_bt.set_buff_modifier(fisherman_slow_mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.add_event_on_create(slow_bt_on_create)\n\tslow_bt.add_event_on_expire(slow_bt_on_expire)\n\tslow_bt.set_buff_tooltip(tr(\"AEHQ\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar strangled_count_label: String = tr(\"AFH7\")\n\tmultiboard.set_key(0, strangled_count_label)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif current_attack_target != target.get_instance_id():\n\t\tcurrent_attack_target = target.get_instance_id()\n\t\tcurrent_attack_count = 0\n\n\tcurrent_attack_count += 1\n\n\tvar impatient_procced: bool = current_attack_count > 4 && target.get_size() < CreepSize.enm.BOSS\n\n\tif !impatient_procced:\n\t\treturn\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), tower.get_range())\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next != target && next.get_buff_of_type(slow_bt) == null:\n\t\t\tCombatLog.log_ability(tower, next, \"Impatient\")\n\t\t\ttower.issue_target_order(next)\n\n\t\t\treturn\n\n\tcurrent_attack_count = 0\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tslow_bt.apply(tower, target, level)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar strangle_count_string: String = str(strangle_count)\n\tmultiboard.set_value(0, strangle_count_string)\n\n\treturn multiboard\n\n\nfunc slow_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar net_start_tick: int = Utils.get_current_tick()\n\tbuff.user_int2 = net_start_tick\n\n\nfunc slow_bt_on_expire(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar lvl: int = tower.get_level()\n\tvar movespeed_for_strangle: float = 120 + 2.4 * lvl\n\tvar net_start_tick: int = buff.user_int2\n\tvar current_tick: int = Utils.get_current_tick()\n\tvar net_duration_ticks: int = current_tick - net_start_tick\n\tvar net_duration: float = Utils.ticks_to_time(net_duration_ticks)\n\tvar target_can_be_strangled: bool = target.get_current_movespeed() <= movespeed_for_strangle || target.is_stunned()\n\tvar strangle_chance: float = (0.03 + 0.002 * lvl) * (net_duration / 3.0)\n\tvar damage_for_boss: float = tower.get_current_attack_damage_with_bonus() * (4 + 0.16 * lvl)\n\tvar strangle_procced: bool = target_can_be_strangled && tower.calc_chance(strangle_chance)\n\n\tif !strangle_procced:\n\t\treturn\n\n\tif target.get_size() >= CreepSize.enm.BOSS || target.is_immune():\n\t\tCombatLog.log_ability(tower, target, \"Strangle boss damage\")\n\t\ttower.do_attack_damage(target, damage_for_boss, tower.calc_attack_multicrit_no_bonus())\n\telse:\n\t\tCombatLog.log_ability(tower, target, \"Strangle non-boss instant kill\")\n\t\ttower.kill_instantly(target)\n\n\tfresh_fish()\n\tEffect.create_simple_at_unit(\"res://src/effects/blood_splatter.tscn\", target, Unit.BodyPart.ORIGIN)\n\tstrangle_count += 1\n\n\nfunc fresh_fish():\n\tvar buff_level: int = int(1000 * tower.get_current_attack_damage_with_bonus() / tower.get_current_attack_speed() * (0.15 + 0.004 * tower.get_level()))\n\tvar duration: float = 5.0 + 0.1 * tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tdps_boost_bt.apply_custom_timed(tower, next, buff_level, duration)\n"
  },
  {
    "path": "src/towers/tower_behaviors/forest_archer.gd",
    "content": "extends TowerBehavior\n\n\nvar roots_bt: BuffType\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {stun_chance = 0.05, slow_chance = 0.10, slow_duration = 7.5},\n\t\t2: {stun_chance = 0.06, slow_chance = 0.15, slow_duration = 8.5},\n\t\t3: {stun_chance = 0.07, slow_chance = 0.20, slow_duration = 9.5},\n\t}\n\n\nconst STUN_CHANCE_ADD: float = 0.001\nconst STUN_DURATION: float = 1.75\nconst STUN_DURATION_ADD: float = 0.05\nconst SLOW_AMOUNT: float = 0.15\nconst SLOW_CHANCE_ADD: float = 0.001\nconst SLOW_DURATION_ADD: float = 0.2\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_level_changed(on_level_changed)\n\n\nfunc tower_init():\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -SLOW_AMOUNT, 0.0)\n\troots_bt = BuffType.new(\"roots_bt\", 0, 0, false, self)\n\troots_bt.set_buff_icon(\"res://resources/icons/generic_icons/root_tip.tres\")\n\troots_bt.set_buff_modifier(mod)\n\troots_bt.set_buff_tooltip(tr(\"FDSR\"))\n\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar creep: Unit = event.get_target()\n\tvar slow_duration: float = _stats.slow_duration + SLOW_DURATION_ADD * level\n\tvar slow_level: int = int(slow_duration * 1000)\n\n\tif tower.calc_chance(_stats.stun_chance + STUN_CHANCE_ADD * level):\n\t\tCombatLog.log_ability(tower, creep, \"Gift of the Forest Stun\")\n\n\t\tstun_bt.apply_only_timed(tower, creep, STUN_DURATION + STUN_DURATION_ADD * level)\n\telif tower.calc_chance(_stats.slow_chance + SLOW_CHANCE_ADD * level):\n\t\tCombatLog.log_ability(tower, creep, \"Gift of the Forest Slow\")\n\n\t\troots_bt.apply_custom_timed(tower, creep, slow_level, slow_duration)\n\n\nfunc on_level_changed(_event: Event):\n\tif tower.get_level() == 15:\n\t\ttower.set_target_count(4)\n\n\nfunc on_create(_preceding: Tower):\n\tif tower.get_level() >= 15:\n\t\ttower.set_target_count(4)\n"
  },
  {
    "path": "src/towers/tower_behaviors/forest_protectress.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed a bug where slow debuff\n# was applied to the main target instead of all damaged\n# units.\n\n\nvar slow_bt: BuffType\nvar aura_bt: BuffType\nvar seconds_since_last_attack: int = 0\nvar dmg_bonus_from_meld: float = 0.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", 1.5, 0.04, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.50, 0.0)\n\tslow_bt.set_buff_modifier(mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"X9P5\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\taura_bt.add_event_on_attack(aura_bt_on_attack)\n\taura_bt.add_event_on_cleanup(aura_bt_on_cleanup)\n\taura_bt.set_buff_tooltip(tr(\"OPHZ\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar wrath_damage: float = (0.5 + 0.02 * tower.get_level()) * tower.get_current_attack_damage_with_bonus()\n\tvar wrath_chance: float = 0.05 * seconds_since_last_attack\n\n\tif !tower.calc_chance(wrath_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Protectress's Wrath\")\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 250)\n\tEffect.create_simple_at_unit(\"res://src/effects/ne_cancel_death.tscn\", target)\n\ttower.do_attack_damage_aoe_unit(target, 250, wrath_damage, tower.calc_attack_multicrit_no_bonus(), 0.0)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tslow_bt.apply(tower, next, tower.get_level())\n\n\ttower.set_sprite_color(Color.WHITE)\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -dmg_bonus_from_meld)\n\tdmg_bonus_from_meld = 0.0\n\tseconds_since_last_attack = 0\n\n\nfunc periodic(event: Event):\n\tvar bonus_add: float = 0.18 + 0.01 * tower.get_level()\n\tvar updated_period: float = tower.get_current_attack_speed() / 2.2\n\n\tif seconds_since_last_attack < 12:\n\t\tseconds_since_last_attack += 1\n\n#\t\tNOTE: original script uses alpha of (255 - 15 * seconds_since_last_attack).\n#\t\tChanged it to 7 because tower sprite was getting too\n#\t\ttransparent.\n\t\ttower.set_sprite_color(Color8(255, 255, 255, 255 - 7 * seconds_since_last_attack))\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, bonus_add)\n\t\tdmg_bonus_from_meld += bonus_add\n\n\tevent.enable_advanced(updated_period, false)\n\n\nfunc aura_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\tvar creep: Unit = event.get_target()\n\tvar caster: Unit = buff.get_caster()\n\tvar prev_bonus: float = buff.user_real\n\tvar new_bonus: float = creep.get_health_ratio() * (0.25 + 0.01 * caster.get_level())\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, -prev_bonus)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, new_bonus)\n\n\tbuff.user_real = new_bonus\n\n\nfunc aura_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\tvar applied_bonus: float = buff.user_real\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATK_CRIT_CHANCE, -applied_bonus)\n"
  },
  {
    "path": "src/towers/tower_behaviors/forest_troll.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Furbolg\"=>\"Forest Troll\"\n\n\nvar rage_0_bt: BuffType\nvar rage_15_bt: BuffType\nvar rage_25_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {trigger_chance = 0.14, buff_level = 0, buff_level_add = 2, duration = 4.0, duration_add = 0.08},\n\t\t2: {trigger_chance = 0.15, buff_level = 50, buff_level_add = 3, duration = 5.0, duration_add = 0.10},\n\t\t3: {trigger_chance = 0.16, buff_level = 100, buff_level_add = 4, duration = 6.0, duration_add = 0.12},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 1.5, 0.01)\n\tm.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.25, 0.0)\n\tm.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.75, 0.0)\n\trage_0_bt = BuffType.new(\"rage_0_bt\", 0, 0, true, self)\n\trage_0_bt.set_buff_modifier(m)\n\trage_0_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\trage_0_bt.set_buff_tooltip(tr(\"L091\"))\n\n\tvar m_15: Modifier = Modifier.new()\n\tm_15.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 1.5, 0.0)\n\tm_15.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.25, 0.0)\n\tm_15.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.75, 0.0)\n\tm_15.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 1.0, 0.0)\n\trage_15_bt = BuffType.new(\"rage_15_bt\", 0, 0, true, self)\n\trage_15_bt.set_buff_modifier(m_15)\n\trage_15_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\trage_15_bt.set_buff_tooltip(tr(\"Y0KF\"))\n\n\tvar m_25: Modifier = Modifier.new()\n\tm_25.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 1.5, 0.0)\n\tm_25.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.25, 0.0)\n\tm_25.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.75, 0.0)\n\tm_25.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 2.0, 0.0)\n\trage_25_bt = BuffType.new(\"rage_25_bt\", 0, 0, true, self)\n\trage_25_bt.set_buff_modifier(m_25)\n\trage_25_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\trage_25_bt.set_buff_tooltip(tr(\"EMWR\"))\n\n\nfunc on_attack(_event: Event):\n\tif !tower.calc_chance(_stats.trigger_chance):\n\t\treturn\n\n\tvar lvl: int = tower.get_level()\n\n#\tDo not allow retriggering while the tower is enraged\n\tvar is_enraged: bool = tower.get_buff_of_type(rage_0_bt) != null || tower.get_buff_of_type(rage_15_bt) != null || tower.get_buff_of_type(rage_25_bt) != null \n\n\tif !is_enraged:\n\t\tCombatLog.log_ability(tower, null, \"Rampage\")\n\n\t\tvar buff_type: BuffType\n\t\tif lvl < 15:\n\t\t\tbuff_type = rage_0_bt\n\t\telif lvl < 25:\n\t\t\tbuff_type = rage_15_bt\n\t\telse:\n\t\t\tbuff_type = rage_25_bt\n\t\t\n\t\tbuff_type.apply_custom_timed(tower, tower, _stats.buff_level + lvl * _stats.buff_level_add, _stats.duration + _stats.duration_add * lvl)\n"
  },
  {
    "path": "src/towers/tower_behaviors/frost_root.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 25, damage_add = 1},\n\t\t2: {damage = 125, damage_add = 5},\n\t\t3: {damage = 375, damage_add = 15},\n\t\t4: {damage = 750, damage_add = 30},\n\t\t5: {damage = 1500, damage_add = 60},\n\t\t6: {damage = 2500, damage_add = 100},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tif event.is_main_target() && tower.calc_chance(0.15) && !event.get_target().is_immune():\n\t\tCombatLog.log_ability(tower, event.get_target(), \"Frozen Thorn\")\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_armor_damage.tscn\", event.get_target())\n\t\ttower.do_spell_damage(event.get_target(), _stats.damage + _stats.damage_add * tower.get_level(), tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/frosty_rock.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Removed floating text for\n# ability chance because it popped up on every attack and\n# was annoying. Added display of this chance in tower\n# details instead.\n\n\nvar slow_bt: BuffType\nvar stun_bt: BuffType\nvar multiboard : MultiboardValues\n\n\nconst SLOW_DURATION: float = 3.0\n\n\nvar accumulated_chance: float = 0.0\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_movespeed = 0.070, mod_movespeed_add = 0.0035, wrath_damage = 100, wrath_damage_add = 2, damage_and_stun_chance = 0.02, stun_duration = 0.8},\n\t\t2: {mod_movespeed = 0.100, mod_movespeed_add = 0.0050, wrath_damage = 520, wrath_damage_add = 10.4, damage_and_stun_chance = 0.03, stun_duration = 0.9},\n\t\t3: {mod_movespeed = 0.130, mod_movespeed_add = 0.0065, wrath_damage = 1300, wrath_damage_add = 26, damage_and_stun_chance = 0.04, stun_duration = 1.0},\n\t\t4: {mod_movespeed = 0.160, mod_movespeed_add = 0.0080, wrath_damage = 2150, wrath_damage_add = 43, damage_and_stun_chance = 0.05, stun_duration = 1.1},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", SLOW_DURATION, 0, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"US8A\"))\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.mod_movespeed, -_stats.mod_movespeed_add)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\n\tstun_bt = CbStun.new(\"stun_bt\", _stats.stun_duration, 0, false, self)\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar stun_chance_label: String = tr(\"KP18\")\n\tmultiboard.set_key(0, stun_chance_label)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tslow_bt.apply(tower, target, level)\n\n\tif tower.calc_chance(accumulated_chance) == true && !event.get_target().is_immune():\n\t\tCombatLog.log_ability(tower, target, \"Glacial Wrath Bonus\")\n\n\t\tstun_bt.apply(tower, target, level)\n\t\tvar wrath_damage: float = _stats.wrath_damage + _stats.wrath_damage_add * level\n\t\ttower.do_spell_damage(target, wrath_damage, tower.calc_spell_crit_no_bonus())\n\t\taccumulated_chance = _stats.damage_and_stun_chance\n\telse:\n\t\taccumulated_chance += _stats.damage_and_stun_chance\n\n\nfunc on_create(_preceding_tower: Tower):\n\taccumulated_chance = _stats.damage_and_stun_chance\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar accumulated_chance_text: String = Utils.format_percent(accumulated_chance, 2)\n\tmultiboard.set_value(0, accumulated_chance_text)\n\t\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/frozen_well.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar mist_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar boekie_frozen_well_aura_mod: Modifier = Modifier.new()\n\tboekie_frozen_well_aura_mod.add_modification(ModificationType.enm.MOD_BUFF_DURATION, 0.25, 0.004)\n\taura_bt.set_buff_modifier(boekie_frozen_well_aura_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/star_swirl.tres\")\n\taura_bt.set_buff_tooltip(tr(\"X6EY\"))\n\n\tmist_bt = BuffType.new(\"mist_bt\", 10, 0, false, self)\n\tvar boekie_freezing_mist_mod: Modifier = Modifier.new()\n\tboekie_freezing_mist_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.15, -0.004)\n\tmist_bt.set_buff_modifier(boekie_freezing_mist_mod)\n\tmist_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\tmist_bt.set_buff_tooltip(tr(\"R38D\"))\n\n\nfunc on_damage(event: Event):\n\tmist_bt.apply(tower, event.get_target(), tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/garden_of_eden.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\nvar current_spawn_level: int = 0\nvar lifeforce_stored: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar lifeforce_stored_label: String = tr(\"LZQX\")\n\tmultiboard.set_key(0, lifeforce_stored_label)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tcurrent_spawn_level = target.get_spawn_level()\n\tvar damage: float = lifeforce_stored * 2 * current_spawn_level\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc on_kill(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar category: CreepCategory.enm = target.get_category()\n\tvar category_match: bool = [CreepCategory.enm.NATURE, CreepCategory.enm.ORC, CreepCategory.enm.HUMANOID].has(category)\n\tvar can_store_lifeforce: bool = lifeforce_stored < 5 + tower.get_level() && category_match\n\n\tif !can_store_lifeforce:\n\t\treturn\n\n\tlifeforce_stored += 1\n\tEffect.create_simple_at_unit(\"res://src/effects/ne_death.tscn\", tower)\n\n\nfunc on_autocast(_event: Event):\n\tvar x: float = tower.get_x()\n\tvar y: float = tower.get_y()\n\tvar z: float = tower.get_z()\n\n\tif lifeforce_stored == 0:\n\t\treturn\n\n\tvar boom: int\n\tvar effect_pos: Vector3 = Vector3(x, y, z + Constants.TILE_SIZE_WC3 / 2)\n\tvar effect_color: Color = Color(Color.CYAN, 0.3)\n\tboom = Effect.create_animated_scaled(\"res://src/effects/wisp_explode.tscn\", effect_pos, 0, 2.0)\n\tEffect.set_animation_speed(boom, 0.6)\n\tEffect.set_lifetime(boom, 2.0)\n\tEffect.set_color(boom, effect_color)\n\tboom = Effect.create_animated_scaled(\"res://src/effects/wisp_explode.tscn\", effect_pos, 0, 2.0)\n\tEffect.set_animation_speed(boom, 0.7)\n\tEffect.set_lifetime(boom, 2.0)\n\tEffect.set_color(boom, effect_color)\n\tboom = Effect.create_animated_scaled(\"res://src/effects/wisp_explode.tscn\", effect_pos, 0, 2.0)\n\tEffect.set_animation_speed(boom, 0.8)\n\tEffect.set_lifetime(boom, 2.0)\n\tEffect.set_color(boom, effect_color)\n\tboom = Effect.create_animated_scaled(\"res://src/effects/wisp_explode.tscn\", effect_pos, 0, 2.0)\n\tEffect.set_animation_speed(boom, 0.9)\n\tEffect.set_lifetime(boom, 2.0)\n\tEffect.set_color(boom, effect_color)\n\n\tawait Utils.create_manual_timer(0.5, self).timeout\n\n\tif Utils.unit_is_valid(tower):\n\t\tvar aoe_damage: float = 15 * lifeforce_stored * current_spawn_level\n\t\ttower.do_spell_damage_pb_aoe(1600, aoe_damage, tower.calc_spell_crit_no_bonus(), 0.0)\n\t\tlifeforce_stored = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, str(lifeforce_stored))\n\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/gatling_gun.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: changed how gatling fire is enabled. Using a bool\n# flag instead of enabling/disabling periodic event.\n\n\n\nvar ball_pt: ProjectileType\nvar sentry_bt: BuffType\n\nvar gatling_fire_enabled: bool = false\nvar gatling_fire_target: Unit = null\nvar gatling_fire_count: int = 0\nvar gatling_fire_dmg_ratio: float = 0.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_periodic_event(periodic, 0.1)\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 800, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\tball_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 1000, self)\n\tball_pt.enable_homing(ball_pt_on_hit, 0)\n\n\tsentry_bt = BuffType.new(\"sentry_bt\", 0, 0, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.005)\n\tsentry_bt.set_buff_modifier(mod)\n\tsentry_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\tsentry_bt.set_buff_tooltip(tr(\"WX48\"))\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar projectile_count_max: int = int(tower.get_current_attack_speed() / 0.1)\n\tvar dmg_ratio: float = 1.0\n\n\tvar rapid_gun_fire_chance: float = 0.65 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(rapid_gun_fire_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Rapid Gun Fire\")\n\n#\tIncrement amount of extra attacks until the chance isn't\n#\tmet or max is reached.\n\tvar projectile_count: int = 1\n\twhile true:\n\t\tvar extra_projectile_chance: float = 0.65 + 0.004 * tower.get_level() - 0.06 * projectile_count\n\t\tvar chance_success: bool = tower.calc_chance(extra_projectile_chance)\n\n\t\tif !chance_success || projectile_count > 10:\n\t\t\tbreak\n\n\t\tprojectile_count += 1\n\n#\tIf tower cannot release as many projectiles as required,\n#\tscale the dmg instead!\n\tif projectile_count > projectile_count_max:\n\t\tdmg_ratio = float(projectile_count) / float(projectile_count_max)\n\t\tprojectile_count = projectile_count_max\n\n#\tSets the target to shoot balls at and makes the periodic\n#\tperiod smaller to get the rapid attack\n\tgatling_fire_enabled = true\n\tgatling_fire_target = target\n\tgatling_fire_count = projectile_count\n\tgatling_fire_dmg_ratio = dmg_ratio\n\n\nfunc on_unit_in_range(_event: Event):\n\tvar tower_level: int = tower.get_level()\n\tvar buff_level: int = 1\n\tvar buff: Buff = tower.get_buff_of_type(sentry_bt)\n\n\tif buff != null:\n\t\tbuff_level = min(buff.user_int + 1, 20)\n\n\tvar buff_duration: float = 3.0 + 0.05 * tower_level\n\n\tbuff = sentry_bt.apply_custom_timed(tower, tower, buff_level * (30 + tower_level), buff_duration)\n\tbuff.user_int = buff_level\n\n\tbuff.set_displayed_stacks(buff.user_int)\n\n\nfunc periodic(_event: Event):\n\tif !gatling_fire_enabled:\n\t\treturn\n\n\tif !Utils.unit_is_valid(gatling_fire_target):\n\t\tgatling_fire_enabled = false\n\n\t\treturn\n\n\tif gatling_fire_count == 0:\n\t\tgatling_fire_enabled = false\n\t\t\n\t\treturn\n\n\tvar gatling_shot: Projectile = Projectile.create_from_unit_to_unit(ball_pt, tower, 1.0, 0.0, tower, gatling_fire_target, true, false, false)\n\tgatling_shot.user_real = gatling_fire_dmg_ratio\n\n\tgatling_fire_count -= 1\n\n\nfunc ball_pt_on_hit(projectile: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar explode_chance: float = 0.10 + 0.003 * tower.get_level()\n\tvar exploded: bool = tower.calc_chance(explode_chance)\n\tvar damage: float = projectile.user_real * tower.get_current_attack_damage_with_bonus()\n\n\tif exploded:\n\t\tEffect.create_scaled(\"res://src/effects/firelord_death_explode.tscn\", Vector3(projectile.get_x(), projectile.get_y(), 30.0), 0, 2)\n\n\t\ttower.do_attack_damage_aoe_unit(creep, 200, damage, tower.calc_attack_multicrit_no_bonus(), 0.0)\n\telse:\n\t\ttower.do_attack_damage(creep, damage, tower.calc_attack_multicrit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/genis_sage.gd",
    "content": "extends TowerBehavior\n\n\nvar swarm_st: SpellType\nvar speedcast_bt: BuffType\nvar spread_bt: BuffType\nvar magic_boost_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 7.0)\n\n\nfunc tower_init():\n\tspeedcast_bt = BuffType.new(\"speedcast_bt\", 3.5, 0.1, true, self)\n\tvar mock_genis_speedcast_mod: Modifier = Modifier.new()\n\tmock_genis_speedcast_mod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.25, 0.01)\n\tmock_genis_speedcast_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.25, 0.01)\n\tspeedcast_bt.set_buff_modifier(mock_genis_speedcast_mod)\n\tspeedcast_bt.set_buff_icon(\"res://resources/icons/generic_icons/holy_grail.tres\")\n\tspeedcast_bt.set_buff_tooltip(tr(\"FY84\"))\n\n\tspread_bt = CbStun.new(\"spread_bt\", 0.8, 0, false, self)\n\tspread_bt.add_event_on_create(spread_bt_on_create)\n\tspread_bt.add_event_on_cleanup(spread_bt_on_cleanup)\n\tspread_bt.set_buff_tooltip(tr(\"EG93\"))\n\n\tmagic_boost_bt = BuffType.new(\"magic_boost_bt\", 3, 0, true, self)\n\tvar mock_genis_magic_boost_mod: Modifier = Modifier.new()\n\tmock_genis_magic_boost_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.2, 0.01)\n\tmagic_boost_bt.set_buff_modifier(mock_genis_magic_boost_mod)\n\tmagic_boost_bt.set_buff_icon(\"res://resources/icons/generic_icons/gold_bar.tres\")\n\tmagic_boost_bt.set_buff_tooltip(tr(\"MF10\"))\n\n\tswarm_st = SpellType.new(SpellType.Name.CARRION_SWARM, 1, self)\n\tswarm_st.data.swarm.damage = 1.0\n\tswarm_st.data.swarm.start_radius = 30\n\tswarm_st.data.swarm.end_radius = 50\n\tswarm_st.data.swarm.travel_distance = 1200\n\tswarm_st.data.swarm.effect_path = \"res://src/effects/moonwell_target.tscn\"\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar aqua_edge_chance: float = 0.20 + 0.006 * level\n\tvar x2: float = target.get_x()\n\tvar y2: float = target.get_y()\n\tvar x: float = tower.get_x()\n\tvar y: float = tower.get_y()\n\tvar facing: float = rad_to_deg(atan2(y2 - y, x2 - x))\n\tvar angle: float = -20\n\tvar edge_damage: float = 1500 + 150 * level\n\n\tif !tower.calc_chance(aqua_edge_chance):\n\t\treturn\n\n\tif tower.get_mana() < 15:\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Aqua Edge\")\n\n\ttower.subtract_mana(15, false)\n\n\twhile true:\n\t\tif angle > 20:\n\t\t\tbreak\n\n\t\tvar edge_angle: float = deg_to_rad(facing + angle)\n\n\t\tswarm_st.point_cast_from_caster_on_point(tower, Vector2(x + 25 * cos(edge_angle), y + 25 * sin(edge_angle)), edge_damage, tower.calc_spell_crit_no_bonus())\n\n\t\tangle += 20\n\n\tspeedcast()\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar spread_chance: float = 0.10 + 0.002 * level\n\n\tif !tower.calc_chance(spread_chance):\n\t\treturn\n\n\tif tower.get_mana() < 40:\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Spread\")\n\n\ttower.subtract_mana(40, false)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/naga_death.tscn\", creep)\n\n#\tNOTE: call calc_spell_crit_no_bonus() one time so that\n#\tall AoE has same crit value\n\tvar spread_damage: float = 3000 + 200 * level\n\tvar crit_ratio: float = tower.calc_spell_crit_no_bonus()\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), creep, 250)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\ttower.do_spell_damage(next, spread_damage, crit_ratio)\n\t\tspread_bt.apply(tower, next, 0)\n\n\tspeedcast()\n\n\nfunc periodic(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar magic_boost_chance: float = 0.3\n\n\tif !tower.calc_chance(magic_boost_chance):\n\t\treturn\n\n\tif tower.get_mana() < 40:\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Magic Boost\")\n\n\ttower.subtract_mana(40, false)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 350)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tmagic_boost_bt.apply(tower, next, level)\n\n\tspeedcast()\n\n\nfunc speedcast():\n\tvar speedcast_chance: float = 0.15\n\n\tif !tower.calc_chance(speedcast_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Speedcast\")\n\n\tspeedcast_bt.apply(tower, tower, tower.get_level())\n\n\nfunc spread_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar adjust_speed: float = 300 / (0.4 * caster.get_prop_buff_duration()) * creep.get_prop_debuff_duration()\n\tcreep.adjust_height(300, adjust_speed)\n\n\nfunc spread_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar adjust_speed: float = 300 / (0.4 * caster.get_prop_buff_duration()) * creep.get_prop_debuff_duration()\n\tcreep.adjust_height(-300, adjust_speed)\n"
  },
  {
    "path": "src/towers/tower_behaviors/geothermal_extractor.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage_increase = 0.180, damage_increase_add = 0.005},\n\t\t2: {damage_increase = 0.300, damage_increase_add = 0.008},\n\t}\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tm.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, _stats.damage_increase, _stats.damage_increase_add)\n\taura_bt.set_buff_modifier(m)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_outfit.tres\")\n\taura_bt.set_buff_tooltip(tr(\"LQM2\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/glaive_master.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: for some reason, youtd website shows the \"Glaivesaw\"\n# ability as \"on_spell_cast\" handler. It should be an\n# autocast. Guessed the parameters for the autocast and\n# implemented it.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where movement speed does not affect damage dealt by\n# dot even though the ability description says that movement\n# speed does affect damage. Preserved this bug.\n\n# NOTE: every time this tower deals damage, it will show up\n# as 0 damage in combat log and then non-zero damage from\n# Lacerate. It looks weird but works as intended.\n\n\nclass Glaivesaw:\n\tvar position: Vector2\n\tvar effect_id: int\n\n\nconst GLAIVESAW_MAX: int = 3\nvar lacerate_bt: BuffType\nvar storm_pt: ProjectileType\nvar bounder_pt: ProjectileType\nvar glaivesaw_list: Array[Glaivesaw] = []\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\tlacerate_bt = BuffType.new(\"lacerate_bt\", 5, 0, false, self)\n\tlacerate_bt.set_buff_icon(\"res://resources/icons/generic_icons/triple_scratches.tres\")\n\tlacerate_bt.add_periodic_event(lacerate_bt_periodic, 1.0)\n\tlacerate_bt.set_buff_tooltip(tr(\"WIM8\"))\n\n\tstorm_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\tstorm_pt.set_event_on_interpolation_finished(storm_pt_on_finished)\n\n\tbounder_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 2000, self)\n\tbounder_pt.enable_collision(bounder_pt_on_collision, 100, TargetType.new(TargetType.CREEPS), false)\n\tbounder_pt.set_event_on_interpolation_finished(bounder_pt_on_finished)\n\n\nfunc on_attack(_event: Event):\n\tvar bounder_chance: float = 0.15 + 0.006 * tower.get_level()\n\n\tif !tower.calc_chance(bounder_chance):\n\t\treturn\n\n\tashbringer_bounder_throw()\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar storm_chance: float = 0.05 + 0.002 * tower.get_level()\n\n\tashbringer_lacerate_damage(target, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit_no_bonus())\n\tevent.damage = 0\n\n\tif !tower.calc_chance(storm_chance):\n\t\treturn\n\n\tashbringer_storm_throw(target)\n\n\nfunc periodic(_event: Event):\n\tvar damage: float = (0.5 + 0.01 * tower.get_level()) * tower.get_current_attack_damage_with_bonus()\n\n\tfor glaivesaw in glaivesaw_list:\n\t\tvar pos: Vector2 = glaivesaw.position\n\n\t\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), pos, 150)\n\n\t\twhile true:\n\t\t\tvar next: Unit = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/stampede_missile_death.tscn\", next, Unit.BodyPart.ORIGIN)\n\t\t\tashbringer_lacerate_damage(next, damage, tower.calc_attack_multicrit_no_bonus())\n\t\t\tEffect.set_lifetime(effect, 2.0)\n\n\nfunc on_destruct():\n\tfor glaivesaw in glaivesaw_list:\n\t\tvar effect_id: int = glaivesaw.effect_id\n\t\tEffect.destroy_effect(effect_id)\n\n\nfunc on_autocast(event: Event):\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar target_pos: Vector2 = autocast.get_target_pos()\n\t\n\tvar new_glaive: Glaivesaw = Glaivesaw.new()\n\tvar new_effect: int = Effect.create_animated_scaled(\"res://src/effects/glaive.tscn\", Vector3(target_pos.x, target_pos.y, 40.0), 0.0, 1.45)\n\tEffect.set_auto_destroy_enabled(new_effect, false)\n\tEffect.set_animation_speed(new_effect, 2.0)\n\tnew_glaive.effect_id = new_effect\n\tnew_glaive.position = target_pos\n\n\tglaivesaw_list.append(new_glaive)\n\n#\tDelete oldest glaive to keep total glaive count at 3\n\twhile glaivesaw_list.size() > GLAIVESAW_MAX:\n\t\tvar old_glaive: Glaivesaw = glaivesaw_list.pop_front()\n\t\tvar effect: int = old_glaive.effect_id\n\t\tEffect.destroy_effect(effect)\n\n\nfunc ashbringer_lacerate_damage(target: Unit, damage: float, crit: float):\n\tvar dot_inc: float = 1.0 + 0.01 * tower.get_level()\n\tvar dot_damage: float = 0.5 * damage * dot_inc * crit\n\n\ttower.do_attack_damage(target, damage * 0.5, crit)\n\n\tvar buff: Buff = target.get_buff_of_type(lacerate_bt)\n\n\tif buff != null:\n\t\tvar damage_stack: float = buff.user_real + dot_damage\n\t\tbuff = lacerate_bt.apply(tower, target, 0)\n\t\tbuff.user_real = damage_stack\n\telse:\n\t\tbuff = lacerate_bt.apply(tower, target, 0)\n\t\tbuff.user_real = dot_damage\n\n\nfunc lacerate_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar remaining: float = buff.get_remaining_duration()\n\tvar damage: float = buff.user_real / remaining\n\tvar damage_tick: float = damage\n#\tNOTE: unused in original script, probably a bug\n\t# var movement_relative: float = target.get_current_movespeed() / 261\n\n\tif target.is_stunned():\n\t\tdamage_tick = 0\n\telse:\n\t\tif remaining < 1:\n\t\t\tdamage = buff.user_real\n\t\t\tdamage_tick = damage\n\n\tif damage_tick > 0:\n\t\tbuff.user_real -= damage\n\t\ttower.do_custom_attack_damage(target, damage_tick, 1.0, AttackType.enm.DECAY)\n\n\nfunc ashbringer_bounder_throw():\n\tif glaivesaw_list.is_empty():\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Bounder\")\n\n\tvar damage: float = (2.5 + 0.06 * tower.get_level()) * tower.get_current_attack_damage_with_bonus()\n\tvar random_glaivesaw_index: int = Globals.synced_rng.randi_range(0, glaivesaw_list.size() - 1)\n\tvar random_glaivesaw: Glaivesaw = glaivesaw_list[random_glaivesaw_index]\n\tvar bounces: int = 1\n\n\tvar p: Projectile = Projectile.create_linear_interpolation_from_point_to_point(bounder_pt, tower, 0, 0, Vector3(tower.get_x(), tower.get_y(), 110), Vector3(random_glaivesaw.position.x, random_glaivesaw.position.y, 0), 0)\n\tp.user_int = random_glaivesaw_index\n\tp.user_int2 = bounces\n\tp.user_real = damage\n\n\nfunc bounder_pt_on_collision(p: Projectile, target: Unit):\n\tvar damage: float = p.user_real\n\tashbringer_lacerate_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\n\nfunc bounder_pt_on_finished(p: Projectile, _target: Unit):\n\tvar bounces: int = p.user_int2\n\tvar bounce_is_over: bool = bounces == 0\n\n\tif bounce_is_over:\n\t\treturn\n\n# \tPick random glaivesaw to bounce to, which is not the\n# \tcurrent glaivesaw\n\tvar next_glaivesaw_list: Array = []\n\n\tfor glaivesaw in glaivesaw_list:\n\t\tvar glaivesaw_is_at_projectile: bool = glaivesaw.position == p.get_position_wc3_2d()\n\t\t\n\t\tif !glaivesaw_is_at_projectile:\n\t\t\tnext_glaivesaw_list.append(glaivesaw)\n\n\tif next_glaivesaw_list.is_empty():\n\t\treturn\n\n\tvar next_glaivesaw: Glaivesaw = Utils.pick_random(Globals.synced_rng, next_glaivesaw_list)\n\n\tp.avert_destruction()\n\tp.start_bezier_interpolation_to_point(Vector3(next_glaivesaw.position.x, next_glaivesaw.position.y, 0), 0, 0, 0)\n\tbounces = 0\n\tp.user_int2 = bounces\n\n\nfunc ashbringer_storm_throw(target: Unit):\n\tCombatLog.log_ability(tower, target, \"Glaive Storm\")\n\tvar p: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(storm_pt, tower, 1, 1, tower, target, 0, 0.3, 0.17, true)\n\t\n\tvar damage: float = (0.5 + 0.02 * tower.get_level()) * tower.get_current_attack_damage_with_bonus()\n\tvar hit_count: int = 20\n\tvar moving_to_target: int = 1\n\tp.user_int = moving_to_target\n\tp.user_int2 = hit_count\n\tp.user_real = damage\n\tp.user_real2 = tower.get_x()\n\tp.user_real3 = tower.get_y()\n\n\nfunc storm_pt_on_finished(p: Projectile, creep: Unit):\n\tvar moving_to_target: int = p.user_int\n\tvar bounce_count: int = p.user_int2\n\tvar tower_x: float = p.user_real2\n\tvar tower_y: float = p.user_real3\n\tvar return_pos: Vector3 = Vector3(tower_x, tower_y, 100)\n\n\tif moving_to_target == 1:\n\t\tp.avert_destruction()\n\t\tvar damage: float = p.user_real\n\t\tif creep != null:\n\t\t\tashbringer_lacerate_damage(creep, damage, tower.calc_attack_multicrit_no_bonus())\n\t\tp.start_bezier_interpolation_to_point(return_pos, 0, 0.3, 0.17)\n\t\tmoving_to_target = 0\n\t\tp.user_int = moving_to_target\n\telif bounce_count > 0:\n\t\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(tower_x, tower_y), 1000)\n\t\tvar next: Unit = it.next_random()\n\n\t\tif next != null:\n\t\t\tp.avert_destruction()\n\t\t\tp.start_bezier_interpolation_to_unit(next, 0, 0.3, 0.17, true)\n\n\t\t\tmoving_to_target = 1\n\t\t\tp.user_int = moving_to_target\n\n\t\t\tbounce_count -= 1\n\t\t\tp.user_int2 = bounce_count\n"
  },
  {
    "path": "src/towers/tower_behaviors/glowing_solar_orb.gd",
    "content": "extends TowerBehavior\n\n\nvar armor_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {armor_decrease = 2},\n\t\t2: {armor_decrease = 3},\n\t\t3: {armor_decrease = 5},\n\t\t4: {armor_decrease = 7},\n\t\t5: {armor_decrease = 10},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar armor: Modifier = Modifier.new()\n\tarmor.add_modification(ModificationType.enm.MOD_ARMOR, 0, -1)\n\tarmor_bt = BuffType.new(\"armor_bt\", 0, 0, false, self)\n\tarmor_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\tarmor_bt.set_buff_modifier(armor)\n\n\tarmor_bt.set_buff_tooltip(tr(\"Y0QD\"))\n\n\nfunc on_damage(event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar creep: Unit = event.get_target()\n\tvar size_factor: float = 1.0\n\n\tif creep.get_size() == CreepSize.enm.BOSS:\n\t\tsize_factor = 2.0\n\n\tif tower.calc_chance((0.05 + lvl * 0.006) * size_factor):\n\t\tCombatLog.log_ability(tower, creep, \"Afterglow\")\n\t\t\n\t\tarmor_bt.apply_custom_timed(tower, creep, _stats.armor_decrease, 5 + lvl * 0.25)\n"
  },
  {
    "path": "src/towers/tower_behaviors/gnoll_thunder_mage.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {base_damage = 1450, base_damage_add = 58, damage_per_tower = 435, damage_per_tower_add = 17.4},\n\t\t2: {base_damage = 2900, base_damage_add = 116, damage_per_tower = 870, damage_per_tower_add = 34.8},\n\t\t3: {base_damage = 4350, base_damage_add = 174, damage_per_tower = 1305, damage_per_tower_add = 52.2},\n\t}\n\nconst RECAST_CHANCE: float = 0.25\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar shock_dmg_label: String = tr(\"IXB0\")\n\tmultiboard.set_key(0, shock_dmg_label)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar lvl: int = tower.get_level()\n\n\tvar thunder_shock_damage: float = get_current_thunder_shock_damage()\n\n\ttower.do_spell_damage(target, thunder_shock_damage, tower.calc_spell_crit_no_bonus())\n\n\tvar recast_happened: bool = tower.calc_chance(RECAST_CHANCE)\n\tif !recast_happened:\n\t\treturn\n\n\ttower.get_player().display_small_floating_text(\"MULTICAST!\", tower, Color8(0, 255, 0), 0.0)\n\n\tvar cast_count: int\n\tif lvl == 25:\n\t\tcast_count = 3\n\telif lvl >= 15:\n\t\tcast_count = 2\n\telse:\n\t\tcast_count = 1\n\n\tvar creeps_in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\n\twhile true:\n\t\tvar creep: Unit = creeps_in_range.next_random()\n\n\t\tif creep == null:\n\t\t\tbreak\n\n\t\tCombatLog.log_ability(tower, creep, \"Thunder Shock recast!\")\n\t\t\n\t\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", creep)\n\t\t\n\t\ttower.do_spell_damage(creep, thunder_shock_damage, tower.calc_spell_crit_no_bonus())\n\n\t\tcast_count -= 1\n\n\t\tif cast_count == 0:\n\t\t\tbreak\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar thunder_shock_damage: float = get_current_thunder_shock_damage()\n\tvar thunder_shock_damage_string: String = Utils.format_float(thunder_shock_damage, 2)\n\tmultiboard.set_value(0, thunder_shock_damage_string)\n\n\treturn multiboard\n\n\nfunc get_current_thunder_shock_damage() -> float:\n\tvar base_damage: float = _stats.base_damage + _stats.base_damage_add * tower.get_level()\n\tvar damage_per_tower: float = _stats.damage_per_tower + _stats.damage_per_tower_add * tower.get_level()\n\tvar tower_count: int = tower.get_player().get_num_towers()\n\tvar thunder_shock_damage: float = base_damage + damage_per_tower * tower_count\n\n\treturn thunder_shock_damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/goblin_stronghold.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug which happened if\n# robot ability failed to find a target. It would do an\n# early return and stop emitter from happening. Note that\n# this bug is not critical because robot ability almost\n# always finds a target because there are many towers\n# nearby.\n\n# NOTE: original script used same ProjectileType for robot\n# and emitter. Created separate PT for emitter.\n\n\nvar sapper_pt: ProjectileType\nvar robot_pt: ProjectileType\nvar emitter_pt: ProjectileType\nvar sapper_bt: BuffType\nvar robot_bt: BuffType\nvar emitter_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tsapper_pt = ProjectileType.create(\"path_to_projectile_sprite\", 20, 700, self)\n\tsapper_pt.enable_homing(sapper_pt_on_hit, 0)\n\n\trobot_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 200, self)\n\trobot_pt.set_event_on_interpolation_finished(robot_pt_on_hit)\n\n\temitter_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 200, self)\n\temitter_pt.set_event_on_interpolation_finished(emitter_pt_on_hit)\n\n\tsapper_bt = BuffType.new(\"sapper_bt\", 3, 0, false, self)\n\tvar cedi_goblin_sapper_mod: Modifier = Modifier.new()\n\tcedi_goblin_sapper_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.001)\n\tsapper_bt.set_buff_modifier(cedi_goblin_sapper_mod)\n\tsapper_bt.set_buff_icon(\"res://resources/icons/generic_icons/barefoot.tres\")\n\tsapper_bt.set_buff_tooltip(tr(\"SBOV\"))\n\n\trobot_bt = BuffType.new(\"robot_bt\", 5, 0, true, self)\n\tvar cedi_goblin_robot_mod: Modifier = Modifier.new()\n\tcedi_goblin_robot_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.001)\n\tcedi_goblin_robot_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.001)\n\trobot_bt.set_buff_modifier(cedi_goblin_robot_mod)\n\trobot_bt.set_buff_icon(\"res://resources/icons/generic_icons/cog.tres\")\n\trobot_bt.set_special_effect(\"res://src/effects/holy_bolt.tscn\", 100, 1.0)\n\trobot_bt.set_buff_tooltip(tr(\"ZENW\"))\n\n\temitter_bt = BuffType.new(\"emitter_bt\", 5, 0, true, self)\n\tvar cedi_goblin_emitter_mod: Modifier = Modifier.new()\n\tcedi_goblin_emitter_mod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.0, 0.001)\n\temitter_bt.set_buff_modifier(cedi_goblin_emitter_mod)\n\temitter_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\temitter_bt.set_special_effect(\"res://src/effects/frost_bolt_missile.tscn\", 100, 1.0)\n\temitter_bt.set_buff_tooltip(tr(\"KB5O\"))\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n#\tNOTE: it's the same chance value for all 3 abilities\n\tvar chance: float = 0.20 + 0.004 * level\n\tvar do_sapper: bool = tower.calc_chance(chance)\n\tvar do_robot: bool = tower.calc_chance(chance)\n\tvar do_emitter: bool = tower.calc_chance(chance)\n\n\tif do_sapper:\n\t\tCombatLog.log_ability(tower, target, \"Goblin Sapper\")\n\t\tProjectile.create_from_unit_to_unit(sapper_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\n\tif do_robot:\n\t\tCombatLog.log_ability(tower, target, \"Clockwork Engineer\")\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\t\tvar next: Unit = it.next_random()\n\n#\t\tDon't target self\n\t\tif next == tower:\n\t\t\tnext = it.next_random()\n\n\t\tif next != null:\n\t\t\tProjectile.create_linear_interpolation_from_unit_to_unit(robot_pt, tower, 1.0, 1.0, tower, next, 0.35, true)\n\n\tif do_emitter:\n\t\tCombatLog.log_ability(tower, null, \"Probability Field Emitter\")\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\t\tvar next: Unit = it.next_random()\n\n#\t\tDon't target self\n\t\tif next == tower:\n\t\t\tnext = it.next_random()\n\n\t\tif next != null:\n\t\t\tvar projectile: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(emitter_pt, tower, 1.0, 1.0, tower, next, 0.33, true)\n\t\t\tvar emitter_buff_level: int = Globals.synced_rng.randi_range(300, 600) + 6 * level\n\t\t\tprojectile.user_int = emitter_buff_level\n\n\tvar used_ability: bool = do_sapper || do_robot || do_emitter\n\tif !used_ability:\n\t\tCombatLog.log_ability(tower, null, \"Reimbursement\")\n\t\ttower.get_player().give_gold(5, tower, true, true)\n\n\nfunc sapper_pt_on_hit(projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar sapper_damage: float = Globals.synced_rng.randi_range(1350, 7650) + 180 * level\n\tvar slow_buff_level: int = Globals.synced_rng.randi_range(250, 450) + 6 * level\n\n\tif tower == null:\n\t\treturn\n\n\tvar slow_text: String = tr(\"EMCY\") % (slow_buff_level / 10) \n\ttower.get_player().display_small_floating_text(slow_text, target, Color8(100, 100, 255), 40)\n\n\tEffect.add_special_effect(\"res://src/effects/frag_boom_spawn.tscn\", Vector2(projectile.get_x(), projectile.get_y()))\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 250)\n\t\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\ttower.do_spell_damage(next, sapper_damage, tower.calc_spell_crit_no_bonus())\n\t\tsapper_bt.apply(tower, next, slow_buff_level)\n\n\nfunc robot_pt_on_hit(_projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar buff_level: int = Globals.synced_rng.randi_range(100, 400) + 6 * level\n\n\tif tower == null:\n\t\treturn\n\n\trobot_bt.apply(tower, target, buff_level)\n\n\tvar attackspeed_and_dmg_text: String = tr(\"F7DM\") % (buff_level / 10) \n\ttower.get_player().display_small_floating_text(attackspeed_and_dmg_text, target, Color8(100, 255, 100), 40)\n\n\nfunc emitter_pt_on_hit(_projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar buff_level: int = Globals.synced_rng.randi_range(300, 600) + 6 * level\n\n\tif tower == null:\n\t\treturn\n\n\temitter_bt.apply(tower, target, buff_level)\n\n\tvar trigger_chances_text: String = tr(\"R735\") % (buff_level / 10) \n\ttower.get_player().display_small_floating_text(trigger_chances_text, target, Color8(100, 255, 100), 40)\n"
  },
  {
    "path": "src/towers/tower_behaviors/grab-o-bot.gd",
    "content": "extends TowerBehavior\n\n\nvar grapple_bt: BuffType\nvar shock_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tgrapple_bt = CbStun.new(\"grapple_bt\", 2.5, 0, false, self)\n\tgrapple_bt.set_buff_icon(\"res://resources/icons/generic_icons/pokecog.tres\")\n\tgrapple_bt.add_event_on_create(grapple_bt_on_create)\n\tgrapple_bt.add_event_on_cleanup(grapple_bt_on_cleanup)\n\n\tshock_bt = CbStun.new(\"shock_bt\", 2.5, 0, false, self)\n\tshock_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar grapple_chance: float = 0.08 + 0.0032 * tower.get_level()\n\n\tvar grapple_duration: float\n\tif target.get_size() >= CreepSize.enm.CHAMPION:\n\t\tgrapple_duration = 0.9\n\telse:\n\t\tgrapple_duration = 2.5\n\n\tif !tower.calc_chance(grapple_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Grapple\")\n\n\tgrapple_bt.apply_only_timed(tower, target, grapple_duration)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar shock_damage: float = 1250 + 185 * tower.get_level()\n\n\tEffect.create_simple_at_unit(\"res://src/effects/thunder_clap.tscn\", target)\n\n\ttower.do_spell_damage_aoe_unit(target, 250, shock_damage, tower.calc_spell_crit_no_bonus(), 0.5)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 250)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tshock_bt.apply_only_timed(tower, next, 2.0)\n\n\nfunc grapple_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar caster: Unit = buff.get_caster()\n\n\tvar lightning_start: Vector3 = Vector3(caster.get_x(), caster.get_y(), 100)\n\tvar lightning_end: Vector3 = Vector3(target.get_x(), target.get_y(), 0)\n\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_point(InterpolatedSprite.LIGHTNING, lightning_start, lightning_end)\n\tbuff.user_int = lightning.get_instance_id()\n\n\nfunc grapple_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar lightning_id: int = buff.user_int\n\n\tvar lightning_object: Object = instance_from_id(lightning_id)\n\n\tif lightning_object != null:\n\t\tvar lightning_node: Node = lightning_object as Node\n\t\tlightning_node.queue_free()\n"
  },
  {
    "path": "src/towers/tower_behaviors/green_dragon_roost.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\nconst AURA_RANGE: int = 200\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MULTICRIT_COUNT, 2, 0.0)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\taura_bt.set_buff_tooltip(tr(\"RGO6\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/green_lightning.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: changed missile speed in csv for this tower.\n# 5000->9001. This tower uses \"lightning\" projectile visual\n# so slow speed looks weird because it makes the damage\n# delayed compared to the lightning visual.\n\nvar surge_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {surge_bt_level_bonus = 0, spell_crit = 0.050, spell_crit_add = 0.0010, damage_from_mana_multiplier = 15},\n\t\t2: {surge_bt_level_bonus = 25, spell_crit = 0.075, spell_crit_add = 0.0015, damage_from_mana_multiplier = 25},\n\t\t3: {surge_bt_level_bonus = 50, spell_crit = 0.100, spell_crit_add = 0.0020, damage_from_mana_multiplier = 35},\n\t\t4: {surge_bt_level_bonus = 75, spell_crit = 0.125, spell_crit_add = 0.0025, damage_from_mana_multiplier = 45},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_autocast(_event: Event):\n\ttower.user_int = 5 + tower.get_level() / 5\n\tsurge_bt.apply(tower, tower, tower.get_level() + _stats.surge_bt_level_bonus)\n\n\n# NOTE: surge() in original script\nfunc surge_bt_on_attack(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar caster: Unit = b.get_caster()\n\n\tif caster.user_int < 1:\n\t\tb.remove_buff()\n\telse:\n\t\tcaster.user_int = caster.user_int - 1\n\n\nfunc tower_init():\n\tvar surge_bt_mod: Modifier = Modifier.new()\n\tsurge_bt = BuffType.new(\"surge_bt\", 8, 0, true, self)\n\tsurge_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 1.0, 0.02)\n\tsurge_bt.set_buff_modifier(surge_bt_mod)\n\tsurge_bt.set_buff_icon(\"res://resources/icons/generic_icons/over_infinity.tres\")\n\tsurge_bt.add_event_on_attack(surge_bt_on_attack)\n\tsurge_bt.set_buff_tooltip(tr(\"Q9D4\"))\n\n\nfunc on_attack(_event: Event):\n\tvar mana: float = tower.get_mana()\n\n\ttower.set_mana(mana + 4 * tower.get_base_mana_regen_bonus_percent())\n\n\ttower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, _stats.spell_crit + (tower.get_level() * _stats.spell_crit_add))\n\ttower.user_real = tower.user_real + _stats.spell_crit + tower.get_level() * _stats.spell_crit_add\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(0.125 + 0.005 * tower.get_level()):\n\t\treturn\n\n\tvar creep: Creep = event.get_target()\n\n\tif !creep.is_immune():\n\t\tCombatLog.log_ability(tower, creep, \"Lightning Burst\")\n\n\t\tEffect.create_animated(\"res://src/effects/holy_bolt_green.tscn\", Vector3(creep.get_x(), creep.get_y(), 50), 0)\n\t\ttower.do_spell_damage(creep, tower.get_mana() * _stats.damage_from_mana_multiplier, tower.calc_spell_crit_no_bonus())\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, - tower.user_real)\n\t\ttower.user_real = 0.0\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_real = 0.0\n\ttower.user_int = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/greyfang.gd",
    "content": "extends TowerBehavior\n\n\nvar shard_pt: ProjectileType\n\nconst BONE_SHATTER_DAMAGE_RATIO: float = 0.25\nconst SHARD_SPREAD_RADIUS: float = 300\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tshard_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 5000, self)\n\tshard_pt.enable_collision(shard_pt_on_collide, 40, TargetType.new(TargetType.CREEPS), false)\n\n\nfunc on_attack(_event: Event):\n#\tRemove normal critical ((also, sadly, this removes any\n#\tbonus crits which were added by other callbacks before\n#\tthis one))\n\ttower.reset_attack_crits()\n\n\tvar do_two_rolls: bool = tower.get_level() == 25\n\n\tvar remaining_count: int = tower.get_prop_multicrit_count()\n\tvar current_chance: float = tower.get_prop_atk_crit_chance()\n\n\tvar crit_count: int = 0\n\twhile true:\n\t\tif remaining_count <= 0:\n\t\t\tbreak\n\n\t\tremaining_count -= 1\n\n\t\tvar first_roll: bool = Utils.rand_chance(Globals.synced_rng, min(current_chance, Constants.ATK_CRIT_CHANCE_CAP))\n\n\t\tif first_roll:\n\t\t\tcrit_count += 1\n\t\t\tcurrent_chance *= Constants.ATK_MULTICRIT_DIMISHING\n\t\telif do_two_rolls:\n\t\t\tvar second_roll: bool = Utils.rand_chance(Globals.synced_rng, min(current_chance, Constants.ATK_CRIT_CHANCE_CAP))\n\n\t\t\tif second_roll:\n\t\t\t\tcrit_count += 1\n\t\t\t\tcurrent_chance *= Constants.ATK_MULTICRIT_DIMISHING\n\n\tvar crit_damage: float = tower._calc_attack_multicrit_from_crit_count(crit_count, 0)\n\ttower._current_crit_count = crit_count\n\ttower._current_crit_damage = crit_damage\n\n\nfunc on_kill(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar shard_count: int = tower.get_prop_multicrit_count()\n\tvar first_angle: float = deg_to_rad(Globals.synced_rng.randf_range(0, 180))\n\tvar angle_between: float = deg_to_rad(180 / shard_count * 2)\n\tvar shard_start_pos: Vector3 = Vector3(creep.get_x(), creep.get_y(), 0)\n\n\tfor i in range(0, shard_count):\n\t\tvar shard_angle: float = first_angle + angle_between * i\n\t\tvar offset: Vector2 = Vector2(SHARD_SPREAD_RADIUS, 0).rotated(shard_angle)\n\t\tvar shard_end_pos: Vector3 = shard_start_pos + Vector3(offset.x, offset.y, 0)\n\n\t\tvar p: Projectile = Projectile.create_linear_interpolation_from_point_to_point(shard_pt, tower, 1, 1, shard_start_pos, shard_end_pos, 0)\n\t\tp.set_projectile_scale(0.25)\n\t\tp.set_color(Color.GRAY)\n\n\t\tp.user_real = BONE_SHATTER_DAMAGE_RATIO\n\n\nfunc shard_pt_on_collide(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar current_shard_damage_ratio: float = p.user_real\n\n\tvar shard_damage: float = current_shard_damage_ratio * tower.get_current_attack_damage_with_bonus()\n\ttower.do_attack_damage(target, shard_damage, tower.calc_attack_multicrit_no_bonus())\n\n\tvar new_shard_damage_ratio: float = current_shard_damage_ratio * 0.8\n\tp.user_real = new_shard_damage_ratio\n"
  },
  {
    "path": "src/towers/tower_behaviors/gryphon_rider.gd",
    "content": "extends TowerBehavior\n\n\n# TODO: look into \"Storm Bolt\" ability more. It creates a\n# line of AoE when projectile hits. The angle of the line is\n# equal to projectile's angle. Currently, that means the\n# angle of the projectile's movement right before it hit the\n# creep. This means that when projectile is turning fast at\n# the end the angle can be something unexpected. Check in\n# original youtd. Maybe this angle needs to be the angle\n# between tower and creep if projectile is interpolated?\n\n\nvar stun_bt: BuffType\nvar hammer_fall_bt: BuffType\nvar stormbolt_pt: ProjectileType\nvar hammer_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\n\tstun_bt = CbStun.new(\"gryphon_rider_stun\", 0, 0, false, self)\n\t\n\thammer_fall_bt = BuffType.new(\"hammer_fall_bt\", 6, 0, false, self)\n\tvar hammer_fall_bt_mod: Modifier = Modifier.new()\n\thammer_fall_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -0.1, 0.0)\n\thammer_fall_bt.set_buff_modifier(hammer_fall_bt_mod)\n\thammer_fall_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\thammer_fall_bt.set_buff_tooltip(tr(\"JNYZ\"))\n\n\tstormbolt_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1100, self)\n\tstormbolt_pt.set_event_on_interpolation_finished(stormbolt_pt_on_hit)\n\n\thammer_pt = ProjectileType.create(\"path_to_projectile_sprite\", 90, 0, self)\n\thammer_pt.enable_physics(hammer_pt_on_impact, -30)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tProjectile.create_linear_interpolation_from_unit_to_unit(stormbolt_pt, tower, 1.0, 1.0, tower, target, 0.15, true)\n\n\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tvar p: Projectile = Projectile.create_from_unit(hammer_pt, tower, target, 0, 1.0, 1.0)\n\tp.set_z(1000)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.PLAYER_TOWERS), 2500.0)\n\tvar damage_multiplier: float = 1.0\n\tvar damage_multiplier_per_tower: float = 0.05 + 0.002 * tower.get_level()\n\n\twhile true:\n\t\tvar next: Tower = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next.get_element() == Element.enm.STORM:\n\t\t\tdamage_multiplier += damage_multiplier_per_tower\n\t\t\thammer_fall_bt.apply(tower, next, 0)\n\n\t\tif damage_multiplier >= 2.0:\n\t\t\tbreak\n\n\tp.user_real *= damage_multiplier\n\n\nfunc stormbolt_pt_on_hit(p: Projectile, target: Unit):\n\tif target != null:\n\t\tvar stormbolt_damage: float = tower.get_current_attack_damage_with_bonus()\n\t\tdeal_damage(target, stormbolt_damage)\n\n\tline_damage(Vector2(p.get_x(), p.get_y()), p.get_direction())\n\n\n# NOTE: impact() in original script\nfunc hammer_pt_on_impact(p: Projectile):\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(p.get_x(), p.get_y()), 600.0)\n\tvar hammer_damage: float = p.user_real\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tdeal_damage(next, hammer_damage)\n\t\tstun_bt.apply_only_timed(tower, next, 1.0)\n\n\nfunc deal_damage(target: Unit, damage: float):\n\tvar spell: float = target.get_prop_spell_damage_received()\n\tvar phys: float = target.get_prop_atk_damage_received()\n\tvar r: float = 0.0\n\tvar crit: float = 0.0\n\n#\tcalc spell damage taken\n#\tImmune?\n\tif target.is_immune():\n#\t\t0% spell damage\n\t\tspell = 0\n\n#\tcalc physical damage taken\n#\tEthereal?\n\tif target.is_ethereal():\n#\t\t0% physical damage\n\t\tphys = 0\n\telse:\n#\t\tarmor\n\t\tphys *= target.get_current_armor_damage_reduction()\n\n#\twe don't want anything below zero!\n\tif spell < 0.0:\n\t\tspell = 0\n\n\tif phys < 0.0:\n\t\tphys = 0\n\n#\tResult are how much physical and spell damage the unit takes.\n#\tProbably adding these two wont result in 100% so we have to scale them\n\tr = spell + phys\n\tif r <= 0:\n#\t\tshit happened...\n\t\treturn\n\n\tif r != 1.0:\n\t\tspell /= r\n\t\tphys /= r\n\n#\tcrit bonus?\n\tif phys == 1.0 || spell == 1.0:\n\t\tcrit = 0.05 + 0.018 * tower.get_level()\n\n# \tNow we know what we need to know to deal damage\n\ttower.do_spell_damage(target, damage * spell, tower.calc_spell_crit(crit, 0.0))\n\ttower.do_attack_damage(target, damage * phys, tower.calc_attack_multicrit(crit, 0, 0))\n\n\nfunc line_damage(origin_pos: Vector2, direction: float):\n\tvar distance: float = 128.0\n\tvar damage: float = tower.get_current_attack_damage_with_bonus()\n\tvar i: int = 0\n\tvar dmg_multiplier: float = 0.6 + 0.012 * tower.get_level()\n\n\twhile true:\n\t\tif i >= 5 || !Utils.unit_is_valid(tower):\n\t\t\tbreak\n\n\t\tvar current_distance: float = distance * i\n\t\tvar offset: Vector2 = Vector2.from_angle(deg_to_rad(direction)) * current_distance\n\t\tvar current_pos: Vector2 = origin_pos + offset\n\n\t\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(current_pos.x, current_pos.y), 85)\n\n\t\twhile true:\n\t\t\tvar next: Unit = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tdeal_damage(next, damage)\n\n\t\tvar clap_effect: int = Effect.create_animated(\"res://src/effects/thunder_clap.tscn\", Vector3(current_pos.x, current_pos.y, 0.0), 0.0)\n\t\tEffect.set_scale(clap_effect, 0.5)\n\t\tvar bolt_effect: int = Effect.create_animated(\"res://src/effects/holy_bolt.tscn\", Vector3(current_pos.x, current_pos.y, 0.0), 0)\n\t\tEffect.set_color(bolt_effect, Color.SILVER)\n\n\t\tdamage *= dmg_multiplier\n\t\ti += 1\n\t\tawait Utils.create_manual_timer(0.15, self).timeout\n"
  },
  {
    "path": "src/towers/tower_behaviors/hall_of_souls.gd",
    "content": "extends TowerBehavior\n\n\n# Changed original script by adding apply_soul_bonus() to\n# get rid of the need to store the soul stats in\n# user_real's. Instead, tower will apply changes appropriate\n# for it's tier in apply_soul_bonus().\n\n# [ORIGINAL_GAME_DEVIATION] Added display of damage\n# accumulated from Revenge of Souls to tower details.\n\n\nvar aura_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {soul_damage = 6, soul_damage_add = 0.3, soul_experience = 1},\n\t\t2: {soul_damage = 12, soul_damage_add = 0.6, soul_experience = 2},\n\t\t3: {soul_damage = 18, soul_damage_add = 0.9, soul_experience = 3},\n\t}\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar revenge_damage_label: String = tr(\"UUFH\")\n\tmultiboard.set_key(0, revenge_damage_label)\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\taura_bt.add_event_on_create(aura_bt_on_create)\n\taura_bt.add_event_on_death(aura_bt_on_death)\n\taura_bt.set_hidden()\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar damage_bonus_text: String = TowerDetails.int_format(tower.user_real3)\n\tmultiboard.set_value(0, damage_bonus_text)\n\n\treturn multiboard\n\n\n# Carry over soul damage from previous tier\nfunc on_create(preceding: Tower):\n\ttower.user_int = _stats.soul_experience\n\ttower.user_real = _stats.soul_damage\n\ttower.user_real2 = _stats.soul_damage_add\n\n\tif preceding != null && preceding.get_family() == tower.get_family():\n\t\tvar soul_bonus: float = preceding.user_real3\n\t\ttower.user_real3 = soul_bonus\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD, soul_bonus)\n\telse:\n\t\ttower.user_real3 = 0.0\n\n\n# NOTE: setFamID() in original script\nfunc aura_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar family: int = caster.get_family()\n\tbuff.user_int = family\n\n\n# Iterate over all Hall of Souls towers in range of killed\n# creep and apply bonuses from \"Revenge of Souls\" ability\n# NOTE: increaseDamageAndExp() in original script\nfunc aura_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(target, TargetType.new(TargetType.TOWERS), 1000)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/spell_aiso.tscn\", target)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next.get_family() == buff.user_int:\n\t\t\tapply_soul_bonus(next)\n\n\nfunc apply_soul_bonus(target: Unit):\n\tvar stat_soul_experience: int = target.user_int\n\tvar stat_soul_damage: float = target.user_real\n\tvar stat_soul_damage_add: float = target.user_real2\n\n#\tNOTE: can't use \"_stats\" here because target may be\n#\tanother \"Hall of Souls\" tower with a different tier.\n\tvar soul_damage: float = stat_soul_damage + stat_soul_damage_add * target.get_level()\n\tvar soul_experience: float = stat_soul_experience\n\n\ttarget.modify_property(ModificationType.enm.MOD_DAMAGE_ADD, soul_damage)\n\ttarget.add_exp(soul_experience)\n\ttarget.user_real3 += soul_damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/harby.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar awaken_bt: BuffType\nvar missile_pt: ProjectileType\nvar is_awake: bool = false\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\ttriggers.add_event_on_spell_targeted(on_spell_targeted)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_tooltip(tr(\"WMXC\"))\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\taura_bt.add_event_on_create(aura_bt_on_create)\n\taura_bt.add_event_on_spell_casted(aura_bt_on_spell_casted)\n\n\tawaken_bt = BuffType.new(\"awaken_bt\", 5, 0, true, self)\n\tawaken_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\tawaken_bt.set_buff_tooltip(tr(\"KY4C\"))\n\tawaken_bt.add_event_on_create(awaken_bt_on_create)\n\tawaken_bt.add_event_on_cleanup(awaken_bt_on_cleanup)\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1500, self)\n\tmissile_pt.enable_homing(missile_pt_on_hit, 0.0)\n\n\nfunc on_attack(event: Event):\n\tvar damage: float = (6 + 0.1 * tower.get_level()) * tower.get_mana()\n\tvar creep: Creep = event.get_target()\n\n\tif !is_awake:\n\t\ttower.order_stop()\n\n\t\treturn\n\n\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, creep, true, false, false)\n\n\tvar arcane_aura_chance: float = 0.1 + 0.004 * tower.get_level()\n\n\tif tower.get_mana() >= 100:\n\t\ttower.subtract_mana(100, false)\n\n\t\tif tower.calc_chance(arcane_aura_chance):\n\t\t\tarcane_mana_replenish(tower)\n\n\t\tvar floating_text: String = \"+%s\" % Utils.format_float(damage, 0)\n\t\ttower.get_player().display_floating_text_x(floating_text, tower, Color8(255, 0, 255, 255), 0.05, 2, 3)\n\t\tp.user_real = damage\n\telse:\n\t\tp.user_real = 0\n\n\nfunc on_kill(_event: Event):\n\ttower.modify_property(ModificationType.enm.MOD_MANA, 1)\n\n\nfunc on_spell_targeted(_event: Event):\n\tawaken_bt.apply(tower, tower, 0)\n\n\nfunc on_create(preceding_tower: Tower):\n\tif preceding_tower == null:\n\t\treturn\n\n\tvar preceding_kills: int = preceding_tower.get_kills()\n\ttower.modify_property(ModificationType.enm.MOD_MANA, preceding_kills)\n\n\nfunc aura_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar last_proc_tick: int = 0\n\tbuff.user_int = last_proc_tick\n\n\nfunc aura_bt_on_spell_casted(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar last_proc_tick: int = buff.user_int\n\tvar autocast: Autocast = event.get_autocast_type()\n\n#\tNOTE: use tick-based calculation to avoid float precision\n#\tdrift in multiplayer.\n\tvar cooldown_ticks: int = Utils.time_to_ticks(5)\n\tvar current_tick: int = Utils.get_current_tick()\n\tvar can_proc: bool = last_proc_tick + cooldown_ticks < current_tick && autocast.get_mana_cost() > 0\n\n\tif !can_proc:\n\t\treturn\n\n\tvar proc_chance: bool = 0.10 + 0.004 * buffed_tower.get_level()\n\n\tif !buffed_tower.calc_chance(proc_chance):\n\t\treturn\n\n\tCombatLog.log_ability(buffed_tower, null, \"Arcane Aura proc\")\n\n\tarcane_mana_replenish(buffed_tower)\n\n\tlast_proc_tick = current_tick\n\tbuff.user_int = last_proc_tick\n\n\nfunc arcane_mana_replenish(target: Tower):\n\tEffect.create_colored(\"res://src/effects/replenish_mana.tscn\", Vector3(target.get_x(), target.get_y(), 80), 0.0, 5, Color8(100, 100, 255, 255))\n\tvar mana_gain: float = 0.1 + 0.002 * target.get_level()\n\ttarget.add_mana_perc(mana_gain)\n\n\nfunc awaken_bt_on_create(_event: Event):\n\t# AddUnitAnimationProperties(u, \"stand alternate\", true)\n\t# SetUnitFlyHeight(u, 100, 2000)\n\n\tCombatLog.log_ability(tower, null, \"Grotesque Awakening\")\n\n\tis_awake = true\n\n\nfunc awaken_bt_on_cleanup(_event: Event):\n\t# AddUnitAnimationProperties(u, \"stand alternate\", false)\n\t# SetUnitFlyHeight(u, 40, 2000)\n\n\tCombatLog.log_ability(tower, null, \"Grotesque Awakening End\")\n\n\tis_awake = false\n\n\nfunc missile_pt_on_hit(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = p.user_real\n\tp.do_spell_damage(target, damage)\n"
  },
  {
    "path": "src/towers/tower_behaviors/harpy_witch.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug in original script,\n# where twister debuff from Harpy Queen (tier 2) was not\n# causing creeps to suffer 18% extra dmg from storm towers,\n# as described in the tooltip. The bug was caused by\n# twister_level_base value being equal to 20 which caused\n# the mod value to be 12% instead of 18%. Fixed by changing\n# twister_level_base for tier 2 to 80.\n\n\nvar sparks_bt: BuffType\nvar twister_bt: BuffType\nvar missile_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {sparks_spell_damage = 0.15, sparks_spell_damage_add = 0.002, sparks_spell_crit_chance = 0.100, sparks_spell_crit_chance_add = 0.001, twister_chance = 0.08, twister_chance_add = 0.003, twister_tornado_count = 2, twister_mod_storm_dmg = 0.10, twister_mod_storm_dmg_add = 0.004, sparks_level_base = 0, sparks_level_multiply = 1, twister_level_base = 0, twister_level_multiply = 4},\n\t\t2: {sparks_spell_damage = 0.20, sparks_spell_damage_add = 0.004, sparks_spell_crit_chance = 0.125, sparks_spell_crit_chance_add = 0.002, twister_chance = 0.12, twister_chance_add = 0.005, twister_tornado_count = 3, twister_mod_storm_dmg = 0.18, twister_mod_storm_dmg_add = 0.007, sparks_level_base = 25, sparks_level_multiply = 2, twister_level_base = 80, twister_level_multiply = 7},\n\t}\n\nconst SPARKS_DURATION: float = 7.5\nconst SPARKS_DURATION_ADD: float = 0.3\nconst TWISTER_DURATION: float = 5.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tsparks_bt = BuffType.new(\"sparks_bt\", 0, 0, true, self)\n\tvar sparks_mod: Modifier = Modifier.new()\n\tsparks_mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, 0.10, 0.001)\n\tsparks_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.15, 0.002)\n\tsparks_bt.set_buff_modifier(sparks_mod)\n\tsparks_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\tsparks_bt.set_buff_tooltip(tr(\"Q903\"))\n\n\ttwister_bt = BuffType.new(\"twister_bt\", TWISTER_DURATION, 0, false, self)\n\tvar twister_mod: Modifier = Modifier.new()\n\ttwister_mod.add_modification(ModificationType.enm.MOD_DMG_FROM_STORM, 0.10, 0.001)\n\ttwister_bt.set_buff_modifier(twister_mod)\n\ttwister_bt.set_buff_icon(\"res://resources/icons/generic_icons/over_infinity.tres\")\n\ttwister_bt.set_buff_tooltip(tr(\"GEGK\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 1000, self)\n\tmissile_pt.enable_homing(harpy_missile_on_hit, 0)\n\n\nfunc on_attack(_event: Event):\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1000)\n\tvar twister_chance: float = _stats.twister_chance + _stats.twister_chance_add * tower.get_level()\n\tvar tornado_count: int = _stats.twister_tornado_count\n\n\tif !tower.calc_chance(twister_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Twister\")\n\n\twhile true:\n\t\tvar target: Unit = it.next_random()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tvar projectile: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1, 0, tower, target, true, false, false)\n\t\tprojectile.set_projectile_scale(0.7)\n\n\t\ttornado_count -= 1\n\t\tif tornado_count == 0:\n\t\t\tbreak\n\n\nfunc on_autocast(event: Event):\n\tvar target: Tower = event.get_target()\n\tvar buff_level: int = _stats.sparks_level_base + _stats.sparks_level_multiply * tower.get_level()\n\tvar buff_duration: float = SPARKS_DURATION + SPARKS_DURATION_ADD * tower.get_level()\n\tsparks_bt.apply_custom_timed(tower, target, buff_level, buff_duration)\n\n\nfunc harpy_missile_on_hit(_projectile: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar buff_level: int = _stats.twister_level_base + _stats.twister_level_multiply * tower.get_level()\n\ttower.do_attack_damage(creep, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit_no_bonus())\n\ttwister_bt.apply(tower, creep, buff_level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/haunted_rubble.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Changed value for tier 1 stats:\n# 15% + 0.15%/lvl -> 10% + 0.10%/lvl Changed because it\n# didn't make sense, the values went down when upgrading to\n# tier 2. Pretty sure this is a typo in original script.\n\n\nvar slow_bt: BuffType\n\n\nconst SLOW_DURATION: float = 5.0\nconst MULTIPLIER_FOR_BOSSES: float = 0.66\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t1: {slow_value = 0.15, chance = 0.10, chance_add = 0.0010},\n\t2: {slow_value = 0.18, chance = 0.12, chance_add = 0.0012},\n\t3: {slow_value = 0.21, chance = 0.15, chance_add = 0.0014},\n\t4: {slow_value = 0.24, chance = 0.16, chance_add = 0.0016},\n\t5: {slow_value = 0.27, chance = 0.18, chance_add = 0.0018},\n}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", SLOW_DURATION, 0, false, self)\n\tvar slow: Modifier = Modifier.new()\n\tslow.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.slow_value, 0.0)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\tslow_bt.set_buff_modifier(slow)\n\t\n\tslow_bt.set_buff_tooltip(tr(\"FCCP\"))\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tvar atrophy_chance: float = _stats.chance + _stats.chance_add * level\n\tvar target_size: int = target.get_size()\n\tif target_size == CreepSize.enm.BOSS:\n\t\tatrophy_chance *= MULTIPLIER_FOR_BOSSES\n\n\tif !tower.calc_chance(atrophy_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Atrophy\")\n\n\tslow_bt.apply(tower, target, level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/healing_obelisk.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {heal_ratio = 0.50, heal_ratio_add = 0.0040},\n\t\t2: {heal_ratio = 0.55, heal_ratio_add = 0.0052},\n\t\t3: {heal_ratio = 0.60, heal_ratio_add = 0.0068},\n\t\t4: {heal_ratio = 0.65, heal_ratio_add = 0.0080},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_level_changed(on_level_changed)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar loop_count: int = tower.user_int\n\tvar healing: int = int(event.damage * (_stats.heal_ratio - tower.get_level() * _stats.heal_ratio_add))\n\n\tif !target.is_immune():\n\t\thealing = int(healing / loop_count)\n\t\t\n\t\twhile true:\n\t\t\tif loop_count == 0:\n\t\t\t\tbreak\n\n\t\t\tawait Utils.create_manual_timer(1.0, self).timeout\n\n\t\t\tif Utils.unit_is_valid(tower) && Utils.unit_is_valid(target):\n\t\t\t\ttarget.set_health(target.get_health() + healing)\n\t\t\t\tEffect.create_simple_at_unit(\"res://src/effects/holy_bolt.tscn\", target)\n\t\t\t\tvar healing_text: String = \"+%d\" % healing\n\t\t\t\ttower.get_player().display_floating_text_x(healing_text, target, Color8(0, 255, 0, 255), 0.05, 0.0, 2.0)\n\t\t\telse:\n\t\t\t\treturn\n\n\t\t\tloop_count = loop_count - 1\n\n\nfunc on_level_changed(_event: Event):\n\tvar level: int = tower.get_level()\n\n\tif level < 15:\n\t\ttower.user_int = 3\n\telif level < 25:\n\t\ttower.user_int = 4\n\telse:\n\t\ttower.user_int = 5\n\n\nfunc on_create(_preceding_tower: Tower):\n\tvar level: int = tower.get_level()\n\n\tif level < 15:\n\t\ttower.user_int = 3\n\telif level < 25:\n\t\ttower.user_int = 4\n\telse:\n\t\ttower.user_int = 5\n"
  },
  {
    "path": "src/towers/tower_behaviors/helicopter_zone.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: Changes compared to original script:\n# - Removed usage of p.userInt\n# - Inverted order of looping through cones, start looping\n#   from closest and increase distance.\n# - Changed position used when checking if copter should\n#   turn to tower. Original script (incorrectly?) used the\n#   copter position before any abilities were performed.\n#   This means that if copter teleported, then it used\n#   completely innaccurate position. Changed to use position\n#   of copter after abilities.\n# - Changed center of tesla ability to be equal to position\n#   of picked main target instead of the position on the\n#   line in front of helicopter closest to main target. This\n#   is just because it works better in code like this. Not a\n#   big difference in final behavior.\n# - Didn't implement fading for teleport ability. Maybe will\n#   later.\n\n\nenum CopterAbility {\n\tNONE,\n\tNAPALM,\n\tTESLA,\n\tGHOST,\n}\n\nclass Copter:\n\tvar projectile: Projectile = null\n\tvar active_ability: CopterAbility = CopterAbility.NONE\n\tvar ghost_ability_timer: int = 0\n\n\nvar copter_slow_bt: BuffType\nvar copter_armor_bt: BuffType\nvar copter_napalm_bt: BuffType\nvar copter_pt: ProjectileType\n\nvar copter_map: Dictionary = {}\nvar projectile_to_copter_map: Dictionary = {}\n\nconst MISSILE_RADIUS: float = 140\nconst TESLA_RADIUS: float = 140 * 1.5\nconst MISSILE_SPACING: float = 250\nconst MISSILE_COUNT_MAX: int = 3\nconst THRESHOLD_TO_START_TURNING_TO_TOWER: float = 550\nconst THRESHOLD_TO_SPEED_UP: float = 480\n# NOTE: picked 300 so that copter goes straight for 1.2\n# seconds when it starts shooting:\n# -- (480 - 300) / 30 * 0.2 = 1.2\nconst COPTER_SPEED_WHEN_START_SHOOTING: float = 300\n\nconst TURN_TO_TARGET_SPEED: float = 6\nconst TURN_TO_TARGET_MARGIN: float = 4\nconst TURN_TO_TOWER_SPEED: float = 6\nconst TURN_TO_TOWER_MARGIN: float = 25\nconst GHOST_ABILITY_TIMER_MAX: int = 20\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_level_changed(on_level_changed)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\t\n\tcopter_slow_bt = BuffType.new(\"copter_slow_bt\", 0.8, 0, false, self)\n\tvar copter_slow_bt_mod: Modifier = Modifier.new()\n\tcopter_slow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.1, -0.01)\n\tcopter_slow_bt.set_buff_modifier(copter_slow_bt_mod)\n\tcopter_slow_bt.set_buff_icon(\"res://resources/icons/generic_icons/cog.tres\")\n\tcopter_slow_bt.set_buff_tooltip(tr(\"OXHW\"))\n\n\tcopter_armor_bt = BuffType.new(\"copter_armor_bt\", 0.8, 0, false, self)\n\tvar copter_armor_bt_mod: Modifier = Modifier.new()\n\tcopter_armor_bt_mod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, -0.3, -0.004)\n\tcopter_armor_bt.set_buff_modifier(copter_armor_bt_mod)\n\tcopter_armor_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\tcopter_armor_bt.set_buff_tooltip(tr(\"IH1N\"))\n\n\tcopter_napalm_bt = BuffType.new(\"copter_napalm_bt\", 5, 0, false, self)\n\tvar copter_napalm_bt_mod: Modifier = Modifier.new()\n\tcopter_napalm_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.2, 0.0)\n\tcopter_napalm_bt.set_buff_modifier(copter_napalm_bt_mod)\n\tcopter_napalm_bt.set_buff_icon(\"res://resources/icons/generic_icons/mine_explosion.tres\")\n\tcopter_napalm_bt.set_buff_tooltip(tr(\"BXNR\"))\n\tcopter_napalm_bt.add_periodic_event(copter_napalm_bt_periodic, 1.0)\n\tcopter_napalm_bt.add_event_on_create(copter_napalm_bt_on_create)\n\n\tcopter_pt = ProjectileType.create(\"path_to_projectile_sprite\", 999999, 10, self)\n\tcopter_pt.enable_periodic(copter_pt_periodic, 0.25)\n\n\nfunc on_create(_preceding: Tower):\n\tvar tower_pos: Vector2 = tower.get_position_wc3_2d()\n\n\tfor i in range(0, 3):\n\t\tvar facing: float = 120 * i\n\t\tvar p: Projectile = Projectile.create_from_unit(copter_pt, tower, tower, facing, 0, 0)\n\t\tvar copter_offset: Vector2 = Vector2(\n\t\t\t(i - 1) * (-80),\n\t\t\t(i - 1) * (i - 1) * (-80) - 40\n\t\t\t)\n\t\tvar copter_pos: Vector3 = Vector3(\n\t\t\ttower_pos.x + copter_offset.x,\n\t\t\ttower_pos.y + copter_offset.y,\n\t\t\t225)\n\t\tp.set_position_wc3(copter_pos)\n\n\t\tp.user_int2 = 0\n\t\tp.user_int3 = 0\n\n\t\tvar copter: Copter = Copter.new()\n\t\tcopter.projectile = p\n\t\tcopter.active_ability = CopterAbility.NONE\n\t\tcopter_map[i] = copter\n\t\tprojectile_to_copter_map[p] = copter\n\n\tlevel_up_copters()\n\n\nfunc on_destruct():\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_copter_keys: Array = copter_map.keys()\n\tsorted_copter_keys.sort()\n\tfor key in sorted_copter_keys:\n\t\tvar copter: Copter = copter_map[key]\n\t\tvar projectile: Projectile = copter.projectile\n\t\tprojectile.remove_from_game()\n\n\nfunc on_level_changed(_event: Event):\n\tlevel_up_copters()\n\n\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\n# NOTE: onAutocast() + UPANDRUN() in original script\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tawait Utils.create_manual_timer(1.0, self).timeout\n\n\tif !Utils.unit_is_valid(tower) || !Utils.unit_is_valid(target):\n\t\treturn\n\n\tvar copter_1: Copter = copter_map[0]\n\tvar projectile: Projectile = copter_1.projectile\n\tprojectile.set_speed(COPTER_SPEED_WHEN_START_SHOOTING)\n\tmove_projectile_behind_unit(projectile, target, 0, 100)\n\n\n# NOTE: Periodic_CopterNapalm() in original script\nfunc copter_napalm_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar napalm_damage: float = buff.user_real\n\n\ttower.do_custom_attack_damage(buffed_unit, napalm_damage, tower.calc_attack_crit_no_bonus(), AttackType.enm.ELEMENTAL)\n\n\n# When applying Napalm, user_real is checked if new damage\n# is greater before setting it, so we need to initialize it\n# here.\n# NOTE: napalm_onCreate() in original script\nfunc copter_napalm_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar napalm_damage_initial: float = 0\n\tbuff.user_real = napalm_damage_initial\n\n\n# The main function which controls copters, adjusts\n# trajectory, and performs copter abilities.\n# NOTE: Copter_Periodic() in original script\nfunc copter_pt_periodic(p: Projectile):\n\tvar copter: Copter = projectile_to_copter_map[p]\n\n\tif copter.active_ability == CopterAbility.GHOST:\n\t\tcopter_ability_ghost(copter)\n\n\tvar target: Unit = copter_find_target_in_front(copter)\n\t\n\tif target != null:\n\t\tcopter_turn(p, target, TURN_TO_TARGET_SPEED, TURN_TO_TARGET_MARGIN)\n\n\t\tif copter.active_ability == CopterAbility.TESLA:\n\t\t\tcopter_ability_tesla_coil(copter, target)\n\t\telse:\n\t\t\tcopter_ability_shoot_in_front(copter)\n\n\tvar copter_should_speed_up: bool = p.get_speed() < THRESHOLD_TO_SPEED_UP\n\t\n\tvar copter_pos: Vector2 = p.get_position_wc3_2d()\n\tvar tower_pos: Vector2 = tower.get_position_wc3_2d()\n\tvar distance_to_tower_squared: float = copter_pos.distance_squared_to(tower_pos)\n\tvar copter_should_turn_to_tower: bool = distance_to_tower_squared > THRESHOLD_TO_START_TURNING_TO_TOWER ** 2\n\n\tif copter_should_speed_up:\n\t\tvar new_speed: float = p.get_speed() + 30\n\t\tp.set_speed(new_speed)\n\telif copter_should_turn_to_tower:\n\t\tcopter_turn(p, tower, TURN_TO_TOWER_SPEED, TURN_TO_TOWER_MARGIN)\n\n\nfunc copter_ability_ghost(copter: Copter):\n\tvar projectile: Projectile = copter.projectile\n\tvar copter_pos: Vector2 = projectile.get_position_wc3_2d()\n\tvar can_use_ghost_ability: bool = copter.ghost_ability_timer == GHOST_ABILITY_TIMER_MAX\n\n\tif can_use_ghost_ability:\n\t\tvar max_shoot_range: float = MISSILE_SPACING * MISSILE_COUNT_MAX\n\t\tvar ghost_teleport_range: float = 3 * max_shoot_range\n\t\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), copter_pos, ghost_teleport_range)\n\n\t\tvar target: Unit = it.next()\n\n\t\tif target != null:\n\t\t\tcopter.ghost_ability_timer = 21\n\n\t\t\tvar random_direction_offset: float = Globals.synced_rng.randf_range(-15, 15)\n\t\t\tmove_projectile_behind_unit(projectile, target, random_direction_offset, 0)\n\telse:\n\t\tcopter.ghost_ability_timer += 1\n\n#\t\t0-15 fade out, 15 wait for target, 15-20 fade in\n\t\tvar new_color: Color\n\t\tif copter.ghost_ability_timer > 20:\n\t\t\tnew_color = Color8(80, 80, 80, 63 + (copter.ghost_ability_timer - 21) * 48)\n\t\telse:\n\t\t\tnew_color = Color8(80, 80, 80, roundi(255 - copter.ghost_ability_timer * 9.6))\n\t\tprojectile.set_color(new_color)\n\n#\t\tIf faded in, start fading out again\n\t\tif copter.ghost_ability_timer == 25:\n\t\t\tcopter.ghost_ability_timer = 0\n\n\n# Makes the copter deal AoE damage in a line in front of it\nfunc copter_ability_shoot_in_front(copter: Copter):\n\tvar p: Projectile = copter.projectile\n\tvar copter_pos: Vector2 = p.get_position_wc3_2d()\n\tp.set_speed(COPTER_SPEED_WHEN_START_SHOOTING)\n\t\n\tvar copter_direction: float = p.get_direction()\n\tvar vector_between_missiles: Vector2 = Vector2(MISSILE_SPACING, 0).rotated(deg_to_rad(copter_direction))\n\n\tvar missile_count: int = 0\n\n\twhile true:\n\t\tif missile_count >= MISSILE_COUNT_MAX:\n\t\t\tbreak\n\n\t\tvar target_pos: Vector2 = copter_pos + vector_between_missiles * missile_count\n\n\t\tcopter_ability_shoot_one_missile(copter, target_pos)\n\n\t\tmissile_count += 1\n\n\n# Makes the copter deal AoE damage at one position\n# NOTE: CopterShotHit() in original script\nfunc copter_ability_shoot_one_missile(copter: Copter, target_pos: Vector2):\n\tvar napalm_is_active: bool = copter.active_ability == CopterAbility.NAPALM\n\n\tvar missile_radius: float\n\tif napalm_is_active:\n\t\tmissile_radius = MISSILE_RADIUS * 1.25\n\telse:\n\t\tmissile_radius = MISSILE_RADIUS\n\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), target_pos, missile_radius)\n\n\tvar effect: int = Effect.add_special_effect(\"res://src/effects/warstomp_caster.tscn\", target_pos)\n\tEffect.set_scale(effect, 0.5)\n\n\tvar attack_damage: float = tower.get_current_attack_damage_with_bonus()\n\n\twhile true:\n\t\tvar target: Unit = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tvar health_before: float = target.get_health()\n\n\t\tif napalm_is_active:\n\t\t\ttower.do_custom_attack_damage(target, attack_damage, tower.calc_attack_multicrit_no_bonus(), AttackType.enm.ELEMENTAL)\n\n\t\t\tvar health_decreased: bool = target.get_health() < health_before\n\t\t\tif health_decreased:\n\t\t\t\tvar napalm_buff: Buff = copter_napalm_bt.apply(tower, target, 0)\n\n\t\t\t\tvar current_napalm_damage: float = napalm_buff.user_real\n\t\t\t\tvar new_napalm_damage: float = 0.5 * attack_damage\n\t\t\t\tvar new_napalm_damage_is_upgrade: bool = new_napalm_damage > current_napalm_damage\n\t\t\t\tif new_napalm_damage_is_upgrade:\n\t\t\t\t\tnapalm_buff.user_real = new_napalm_damage\n\n\t\t\t\tcopter_slow_bt.apply(tower, target, 40)\n\t\t\t\tcopter_armor_bt.apply(tower, target, tower.get_level())\n\t\telse:\n\t\t\ttower.do_custom_attack_damage(target, attack_damage, tower.calc_attack_multicrit_no_bonus(), AttackType.enm.PHYSICAL)\n\n\t\t\tvar health_decreased: bool = target.get_health() < health_before\n\t\t\tif health_decreased:\n\t\t\t\tcopter_slow_bt.apply(tower, target, 40)\n\t\t\t\tcopter_armor_bt.apply(tower, target, tower.get_level())\n\n\nfunc copter_ability_tesla_coil(copter: Copter, main_target: Unit):\n\tvar tesla_center: Vector2 = main_target.get_position_wc3_2d()\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), tesla_center, TESLA_RADIUS)\n\t\n\tvar damage: float = tower.get_current_attack_damage_with_bonus()\n\n\twhile true:\n\t\tvar target: Unit = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tvar projectile: Projectile = copter.projectile\n\t\tvar copter_pos: Vector3 = projectile.get_position_wc3()\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, copter_pos, target)\n\t\tlightning.set_lifetime(0.12)\n\n\t\tvar health_before: float = target.get_health()\n\n\t\ttower.do_custom_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus(), AttackType.enm.ENERGY)\n\n\t\tvar health_decreased: bool = target.get_health() < health_before\n\n\t\tif health_decreased:\n\t\t\tcopter_armor_bt.apply(tower, target, tower.get_level() + 50)\n\t\t\tcopter_slow_bt.apply(tower, target, 0)\n\n\n# Find the nearest target in front of the copter\nfunc copter_find_target_in_front(copter: Copter) -> Unit:\n\tvar projectile: Projectile = copter.projectile\n\tvar missile_count_max: int = MISSILE_COUNT_MAX\n\tvar missile_radius: float = MISSILE_RADIUS\n\tif copter.active_ability == CopterAbility.TESLA:\n\t\tmissile_count_max = 8\n\t\tmissile_radius *= 1.5\n\tvar copter_pos: Vector2 = projectile.get_position_wc3_2d()\n\tvar copter_direction: float = projectile.get_direction()\n\tvar spacing_vector: Vector2 = Vector2(MISSILE_SPACING, 0).rotated(deg_to_rad(copter_direction))\n\tvar missile_count: int = 0\n\t\n\twhile true:\n\t\tif missile_count >= missile_count_max:\n\t\t\tbreak\n\n\t\tvar missile_pos: Vector2 = copter_pos + spacing_vector * missile_count\n\t\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), missile_pos, missile_radius)\n\n\t\tvar target: Unit = it.next()\n\n\t\tif target != null:\n\t\t\treturn target\n\t\t\n\t\tmissile_count += 1\n\t\t\n\treturn null\n\n\n# Moves copter behind unit and also aligns the direction of\n# the copter with the unit so that copter follows the\n# target.\n# NOTE: deem_fade() in original script. Also a portion of\n# Copter_Periodic()\nfunc move_projectile_behind_unit(projectile: Projectile, target: Unit, direction_offset: float, distance_offset: float):\n\tvar new_direction: float = target.get_unit_facing()\n\tnew_direction += direction_offset\n\tprojectile.set_direction(new_direction)\n\n\tvar max_shoot_range: float = MISSILE_SPACING * MISSILE_COUNT_MAX + distance_offset\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\tvar pos_behind_target: Vector2 = target_pos + Vector2(max_shoot_range, 0).rotated(deg_to_rad(new_direction + 180))\n\tprojectile.set_position_wc3_2d(pos_behind_target)\n\n\n# NOTE: deem_anglestuff() in original script\nfunc copter_turn(p: Projectile, target: Unit, turn: float, angle_margin: float):\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\tvar diff_vector: Vector2 = target_pos - p.get_position_wc3_2d()\n\tvar angle: float = rad_to_deg(diff_vector.angle())\n\tvar angle_diff: float = angle - p.get_direction()\n\n#\tNormalize angle\n\tif angle_diff > 180:\n\t\tangle_diff -= 360\n\telif angle_diff < -180:\n\t\tangle_diff += 360\n\n\tvar new_direction: float\n\tif angle_diff > angle_margin:\n\t\tnew_direction = p.get_direction() + turn\n\telif angle_diff < -angle_margin:\n\t\tnew_direction = p.get_direction() - turn\n\telse:\n\t\tnew_direction = p.get_direction()\n\n\tp.set_direction(new_direction)\n\n\n# NOTE: LevelUpCopters() in original script\nfunc level_up_copters():\n\tvar level: int = tower.get_level()\n\tvar copter_1: Copter = copter_map[0]\n\tvar copter_2: Copter = copter_map[1]\n\tvar copter_3: Copter = copter_map[2]\n\n\tif level >= 7:\n\t\tcopter_1.active_ability = CopterAbility.NAPALM\n\t\tcopter_1.projectile.set_color(Color8(255, 120, 120))\n\telse:\n\t\tcopter_1.active_ability = CopterAbility.NONE\n\t\tcopter_1.projectile.set_color(Color8(255, 255, 255))\n\n\tif level >= 15:\n\t\tcopter_2.active_ability = CopterAbility.TESLA\n\t\tcopter_2.projectile.set_color(Color8(120, 120, 255))\n\telse:\n\t\tcopter_2.active_ability = CopterAbility.NONE\n\t\tcopter_2.projectile.set_color(Color8(255, 255, 255))\n\n\tif level >= 25:\n\t\tcopter_3.active_ability = CopterAbility.GHOST\n\t\tcopter_3.projectile.set_color(Color8(80, 80, 80))\n\t\tcopter_3.ghost_ability_timer = 0\n\telse:\n\t\tcopter_3.active_ability = CopterAbility.NONE\n\t\tcopter_3.projectile.set_color(Color8(255, 255, 255))\n\t\tcopter_3.ghost_ability_timer = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/hell_bat.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Day/night mechanic is not\n# implemented so this tower is disabled. Disabled by\n# removing lines from tower props csv.\n\n\nvar darkness_bt: BuffType\nvar swarm_st: SpellType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {swarm_damage_night = 600, swarm_damage_night_add = 15, swarm_damage_day = 200, swarm_damage_day_add = 5, attack_damage_night_add = 0.004, attack_damage_day_add = 0.002},\n\t\t2: {swarm_damage_night = 1650, swarm_damage_night_add = 45, swarm_damage_day = 550, swarm_damage_day_add = 15, attack_damage_night_add = 0.006, attack_damage_day_add = 0.003},\n\t\t3: {swarm_damage_night = 2700, swarm_damage_night_add = 90, swarm_damage_day = 900, swarm_damage_day_add = 30, attack_damage_night_add = 0.008, attack_damage_day_add = 0.004},\n\t}\n\nconst ON_ATTACK_CHANCE: float = 0.15\nconst ON_ATTACK_CHANCE_ADD: float = 0.002\nconst ENGULFING_DARKNESS_DURATION: float = 5.0\nconst ATTACK_DAMAGE_NIGHT: float = 1.5\nconst ATTACK_DAMAGE_DAY: float = 0.5\nconst SWARM_START_RADIUS: float = 100\nconst SWARM_END_RADIUS: float = 300\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tdarkness_bt = BuffType.new(\"darkness_bt\", 5, 0, true, self)\n\tdarkness_bt.set_buff_icon(\"res://resources/icons/generic_icons/fire_dash.tres\")\n\tdarkness_bt.set_buff_tooltip(tr(\"E2YG\"))\n\n#\tNOTE: settubg damage to \"1.0\" here because value for\n#\tactual damage is passed when spell is casted as\n#\t\"damage_ratio\"\n\tswarm_st = SpellType.new(SpellType.Name.CARRION_SWARM, 3.0, self)\n\tswarm_st.data.swarm.damage = 1.0\n\tswarm_st.data.swarm.start_radius = SWARM_START_RADIUS\n\tswarm_st.data.swarm.end_radius = SWARM_END_RADIUS\n\tswarm_st.data.swarm.travel_distance = 1200\n\tswarm_st.data.swarm.effect_path = \"res://src/effects/death_coil.tscn\"\n\n\nfunc on_attack(event: Event):\n\tvar level: int = tower.get_level()\n\tvar target: Unit = event.get_target()\n\tvar chance: float = ON_ATTACK_CHANCE + ON_ATTACK_CHANCE_ADD * level\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Bat Swarm\")\n\n\tvar damage_ratio: int\n\tif time_is_night():\n\t\tdamage_ratio = _stats.swarm_damage_night + _stats.swarm_damage_night_add * level\n\telse:\n\t\tdamage_ratio = _stats.swarm_damage_day + _stats.swarm_damage_day_add * level\n\n\tswarm_st.target_cast_from_caster(tower, target, damage_ratio, tower.calc_spell_crit_no_bonus())\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar damage_ratio: float\n\tif time_is_night():\n\t\tdamage_ratio = ATTACK_DAMAGE_NIGHT + _stats.attack_damage_night_add * level\n\telse:\n\t\tdamage_ratio = ATTACK_DAMAGE_DAY + _stats.attack_damage_day_add * level\n\n\tevent.damage *= damage_ratio\n\n\nfunc on_autocast(_event: Event):\n\tdarkness_bt.apply(tower, tower, tower.get_level())\n\n\nfunc time_is_night() -> bool:\n\tvar time: float = Utils.get_time_of_day()\n\tvar out: bool = time >= 18.00 || time < 6.00 || tower.get_buff_of_type(darkness_bt) != null\n\n\treturn out\n"
  },
  {
    "path": "src/towers/tower_behaviors/holy_energy.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug in original script\n# where glimmer aura's initial level was set to 1 which\n# caused the initial effect value to be 15% + 0.2%. Fixed so\n# it's 15%.\n\n\nvar glimmer_bt: BuffType\nvar sunlight_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {},\n\t}\n\n\nconst SUNLIGHT_RANGE: float = 1000\nconst SUNLIGHT_DURATION: float = 1.5\nconst SUNLIGHT_DURATION_ADD: float = 0.02\nconst GLIMMER_MOD_DEBUFF_DURATION: float = 0.15\nconst GLIMMER_MOD_DEBUFF_DURATION_ADD: float = 0.002\n\n\nfunc tower_init():\n\tglimmer_bt = BuffType.create_aura_effect_type(\"glimmer_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -GLIMMER_MOD_DEBUFF_DURATION, -GLIMMER_MOD_DEBUFF_DURATION_ADD)\n\tglimmer_bt.set_buff_modifier(mod)\n\tglimmer_bt.set_buff_icon(\"res://resources/icons/generic_icons/star_swirl.tres\")\n\tglimmer_bt.set_buff_tooltip(tr(\"IROC\"))\n\n\tsunlight_bt = CbStun.new(\"sunlight_bt\", SUNLIGHT_DURATION, SUNLIGHT_DURATION_ADD, false, self)\n\tsunlight_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\n\nfunc on_autocast(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar creeps: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), SUNLIGHT_RANGE)\n\tvar towers: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), SUNLIGHT_RANGE)\n\n\twhile true:\n\t\tvar target_creep: Unit = creeps.next()\n\n\t\tif target_creep == null:\n\t\t\tbreak\n\n\t\tsunlight_bt.apply(tower, target_creep, level)\n\n\twhile true:\n\t\tvar target_tower: Unit = towers.next()\n\n\t\tif target_tower == null:\n\t\t\tbreak\n\n\t\tsunlight_bt.apply(tower, target_tower, level)\n\t\t\n\n"
  },
  {
    "path": "src/towers/tower_behaviors/ice_battery.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: rewrote script a bit. Instead of enabling/disabling\n# periodic event I added a flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where it refunds the cost of autocast in\n# on_autocast(). It refunds the cost by calling set_mana()\n# but the problem is that at the time when on_autocast() is\n# called, the mana cost has not been spent yet. Therefore,\n# refund fails if tower is at max mana because set_mana()\n# can't go above max mana. Not critical - don't need to fix.\n\n\nvar frozen_bt: BuffType\nvar missile_pt: ProjectileType\n\nvar _battery_overload_is_active: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 300, projectile_damage_add = 12, slow_amount = 0.10, slow_amount_add = 0.003},\n\t\t2: {projectile_damage = 750, projectile_damage_add = 30, slow_amount = 0.15, slow_amount_add = 0.0045},\n\t\t3: {projectile_damage = 1800, projectile_damage_add = 72, slow_amount = 0.20, slow_amount_add = 0.006},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc on_autocast(_event: Event):\n\ttower.set_mana(tower.get_mana() + 100)\n\t_battery_overload_is_active = true\n\n\nfunc hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.projectile_damage + _stats.projectile_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tfrozen_bt.apply(tower, creep, level)\n\n\nfunc tower_init():\n\tvar slow: Modifier = Modifier.new()\n\tslow.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.slow_amount, -_stats.slow_amount_add)\n\n\tfrozen_bt = BuffType.new(\"frozen_bt\", 9, 0.3, false, self)\n\tfrozen_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\tfrozen_bt.set_buff_modifier(slow)\n\tfrozen_bt.set_buff_tooltip(tr(\"FBX1\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\tmissile_pt.enable_homing(hit, 0)\n\n\nfunc on_damage(event: Event):\n\tfrozen_bt.apply(tower, event.get_target(), tower.get_level())\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.set_mana(0)\n\n\nfunc periodic(_event: Event):\n\tif !_battery_overload_is_active:\n\t\treturn\n\n\tif tower.get_mana() > 10:\n\t\tvar in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar target: Unit = in_range.next_random()\n\n\t\tif target != null:\n# \t\t\tNOTE: original script used createFromPointToUnit and made projectiles from high above the tower\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\t\tp.set_projectile_scale(0.5)\n\n#\t\tSpend mana, note that mana is used for unsuccessful\n#\t\tattempts as well\n\t\ttower.set_mana(tower.get_mana() - 10)\n\telse:\n#\t\tTower is out of mana so stop shooting\n\t\t_battery_overload_is_active = false\n"
  },
  {
    "path": "src/towers/tower_behaviors/icy_core.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_movespeed = 0.15, mod_movespeed_add = 0.004},\n\t\t2: {mod_movespeed = 0.25, mod_movespeed_add = 0.006},\n\t}\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.mod_movespeed, -_stats.mod_movespeed_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/barefoot.tres\")\n\taura_bt.set_buff_tooltip(tr(\"BHFS\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/icy_skulls.gd",
    "content": "extends TowerBehavior\n\n\nvar slow_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {slow_base = 0.075, slow_add = 0.003, duration_base = 3, duration_add = 0.1},\n\t\t2: {slow_base = 0.100, slow_add = 0.004, duration_base = 4, duration_add = 0.2},\n\t\t3: {slow_base = 0.125, slow_add = 0.005, duration_base = 5, duration_add = 0.3},\n\t\t4: {slow_base = 0.150, slow_add = 0.006, duration_base = 6, duration_add = 0.4},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", _stats.duration_base, _stats.duration_add, false, self)\n\tvar slow_mod: Modifier = Modifier.new()\n\tslow_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.slow_base, -_stats.slow_add)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_modifier(slow_mod)\n\n\tslow_bt.set_buff_tooltip(tr(\"PTSP\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar lvl: int = tower.get_level()\n\n\tslow_bt.apply(tower, target, lvl)\n"
  },
  {
    "path": "src/towers/tower_behaviors/icy_spirit.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: changed the script a bit. Original script\n# implementes nova delay via periodic events. Changed to use\n# await instead.\n\n\nvar slow_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {nova_dmg = 350, nova_dmg_add = 17.5},\n\t\t2: {nova_dmg = 910, nova_dmg_add = 45.5},\n\t\t3: {nova_dmg = 2100, nova_dmg_add = 105},\n\t}\n\n\nconst NOVA_CHANCE: float = 0.25\nconst NOVA_CHANCE_ADD: float = 0.005\nconst NOVA_RANGE: float = 900\nconst NOVA_AOE_RADIUS: float = 200\nconst NOVA_MOD_MOVESPEED: float = 0.125\nconst NOVA_MOD_MOVESPEED_ADD: float = 0.005\nconst NOVA_SLOW_DURATION: float = 4.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -NOVA_MOD_MOVESPEED, -NOVA_MOD_MOVESPEED_ADD)\n\n\tslow_bt = BuffType.new(\"slow_bt\", NOVA_SLOW_DURATION, 0, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/amber_mosquito.tres\")\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_tooltip(tr(\"KHEG\"))\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\n\tvar nova_chance: float = NOVA_CHANCE + NOVA_CHANCE_ADD * level\n\n\tif !tower.calc_chance(nova_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Nova Storm\")\n\n\tvar nova_count: int\n\tif level < 15:\n\t\tnova_count = 3\n\telif level < 25:\n\t\tnova_count = 4\n\telse:\n\t\tnova_count = 5\n\n\tfor i in range(0, nova_count):\n#\t\tCheck that tower still exists, could have been sold\n#\t\tduring await.\n\t\tif !Utils.unit_is_valid(tower):\n\t\t\treturn\n\n\t\tvar creeps_near_tower: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), NOVA_RANGE)\n\t\tvar main_target: Unit = creeps_near_tower.next_random()\n\n\t\tif main_target != null:\n\t\t\ttower.do_spell_damage_aoe_unit(main_target, NOVA_AOE_RADIUS, _stats.nova_dmg + (level * _stats.nova_dmg_add), tower.calc_spell_crit_no_bonus(), 0.5)\n\t\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", main_target)\n\n\t\t\tvar creeps_near_target: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), main_target, NOVA_AOE_RADIUS)\n\n\t\t\twhile true:\n\t\t\t\tvar aoe_target = creeps_near_target.next()\n\n\t\t\t\tif aoe_target == null:\n\t\t\t\t\tbreak\n\n\t\t\t\tslow_bt.apply(tower, aoe_target, level)\n\n\t\tawait Utils.create_manual_timer(0.1, self).timeout\n"
  },
  {
    "path": "src/towers/tower_behaviors/igloo.gd",
    "content": "extends TowerBehavior\n\n\nvar extreme_cold_bt: BuffType\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {stun_duration = 0.4, cold_damage = 700, cold_damage_add = 35, cold_slow = 0.20},\n\t\t2: {stun_duration = 0.8, cold_damage = 1500, cold_damage_add = 75, cold_slow = 0.25},\n\t\t3: {stun_duration = 1.2, cold_damage = 2800, cold_damage_add = 140, cold_slow = 0.30},\n\t}\n\n\nconst COLD_SLOW_ADD: float = 0.004\nconst COLD_SLOW_DURATION: float = 4\nconst COLD_RANGE: float = 900\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, COLD_RANGE, TargetType.new(TargetType.CREEPS))\n\n\nfunc boekie_igloo_end(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tstun_bt.apply_only_timed(buff.get_caster(), buff.get_buffed_unit(), _stats.stun_duration)\n\n\nfunc tower_init():\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.cold_slow, -COLD_SLOW_ADD)\n\textreme_cold_bt = BuffType.new(\"extreme_cold_bt\", COLD_SLOW_DURATION, 0, false, self)\n\textreme_cold_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\textreme_cold_bt.set_buff_modifier(modifier)\n\textreme_cold_bt.add_event_on_expire(boekie_igloo_end)\n\textreme_cold_bt.set_buff_tooltip(tr(\"V5N2\"))\n\n\tstun_bt = CbStun.new(\"igloo_stun\", 0, 0, false, self)\n\n\nfunc on_unit_in_range(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.cold_damage + _stats.cold_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\textreme_cold_bt.apply(tower, creep, level)\n\n\tEffect.create_scaled(\"res://src/effects/frost_armor_damage.tscn\", Vector3(creep.get_x(), creep.get_y(), 30), 0, 3)\n"
  },
  {
    "path": "src/towers/tower_behaviors/inexperienced_huntress.gd",
    "content": "extends TowerBehavior\n\n\nvar glaive_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {shadow_glaive_crit_bonus = 0.25, shadow_glaive_crit_bonus_add = 0.01, star_glaive_dmg_ratio = 0.25},\n\t\t2: {shadow_glaive_crit_bonus = 0.50, shadow_glaive_crit_bonus_add = 0.02, star_glaive_dmg_ratio = 0.35},\n\t\t3: {shadow_glaive_crit_bonus = 0.75, shadow_glaive_crit_bonus_add = 0.03, star_glaive_dmg_ratio = 0.45},\n\t}\n\n\nconst SHADOW_GLAIVE_CHANCE: float = 0.20\nconst SHADOW_GLAIVE_CHANCE_ADD: float = 0.008\nconst SHADOW_GLAIVE_ATTACK_SPEED: float = 2.0\nconst SHADOW_GLAIVE_ATTACK_SPEED_ADD: float = 0.08\nconst STAR_GLAIVE_CHANCE: float = 0.25\nconst STAR_GLAIVE_CHANCE_ADD: float = 0.004\nconst STAR_GLAIVE_DMG_RATIO_ADD: float = 0.01\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tglaive_bt = BuffType.new(\"glaive_bt\", 99, 0, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, SHADOW_GLAIVE_ATTACK_SPEED, SHADOW_GLAIVE_ATTACK_SPEED_ADD)\n\tglaive_bt.set_buff_modifier(mod)\n\tglaive_bt.set_buff_icon(\"res://resources/icons/generic_icons/pisces.tres\")\n\tglaive_bt.set_buff_tooltip(tr(\"IWIB\"))\n\n\nfunc on_attack(_event: Event):\n\tvar buff: Buff = tower.get_buff_of_type(glaive_bt)\n\tvar crit_damage_multiply: float = 1.0 + _stats.shadow_glaive_crit_bonus + _stats.shadow_glaive_crit_bonus_add * tower.get_level()\n\tvar shadow_glaive_chance: float = SHADOW_GLAIVE_CHANCE + SHADOW_GLAIVE_CHANCE_ADD * tower.get_level()\n\n\tif buff != null:\n\t\ttower.add_modified_attack_crit(0.0, crit_damage_multiply)\n\t\tbuff.remove_buff()\n\n\tif !tower.calc_chance(shadow_glaive_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Shadow Glaive\")\n\n\tglaive_bt.apply(tower, tower, tower.get_level())\n\n\nfunc on_damage(event: Event):\n\tvar star_glaive_chance: float = STAR_GLAIVE_CHANCE + STAR_GLAIVE_CHANCE_ADD * tower.get_level()\n\tvar stair_glaive_damage: float = event.damage * (_stats.star_glaive_dmg_ratio + STAR_GLAIVE_DMG_RATIO_ADD * tower.get_level())\n\n\tif !tower.calc_chance(star_glaive_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Star Glaive\")\n\n\ttower.do_spell_damage(event.get_target(), stair_glaive_damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/starfall_target.tscn\", event.get_target())\n"
  },
  {
    "path": "src/towers/tower_behaviors/inflamed_stone.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed minor bug in original\n# script. The buffs which tower applied onto itself were\n# unfriendly. Fixed them to be friendly. This bug doesn't\n# matter that much because the buffs are permanent and\n# invisible.\n\n# NOTE: had to adjust how buff levels are calculated a bit\n# to account for differences in how stats start from 0.0 vs\n# 1.0 in original youtd vs youtd2.\n\n\nvar damage_bt: BuffType\nvar crit_damage_bt: BuffType\nvar crit_chance_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {spellfire_ratio = 0.84, spellfire_ratio_add = 0.0336, extra_crit_dmg_per_mana = 0.08, mana_threshold_add = 0.20},\n\t\t2: {spellfire_ratio = 0.90, spellfire_ratio_add = 0.0360, extra_crit_dmg_per_mana = 0.09, mana_threshold_add = 0.25},\n\t\t3: {spellfire_ratio = 1.00, spellfire_ratio_add = 0.0400, extra_crit_dmg_per_mana = 0.10, mana_threshold_add = 0.30},\n\t}\n\n\nconst MANA_THRESHOLD_BASE: float = 20\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tdamage_bt = BuffType.new(\"damage_bt\", -1, 0, true, self)\n\tvar spell_flame_damage_mod: Modifier = Modifier.new()\n\tspell_flame_damage_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.01)\n\tdamage_bt.set_buff_modifier(spell_flame_damage_mod)\n\tdamage_bt.set_hidden()\n\n\tcrit_chance_bt = BuffType.new(\"crit_chance_bt\", -1, 0, true, self)\n\tvar spell_flame_crit_chance_mod: Modifier = Modifier.new()\n\tspell_flame_crit_chance_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.0, 0.01)\n\tcrit_chance_bt.set_buff_modifier(spell_flame_crit_chance_mod)\n\tcrit_chance_bt.set_hidden()\n\n\tcrit_damage_bt = BuffType.new(\"spell_crit_damage_bt\", -1, 0, true, self)\n\tvar spell_crit_damage_mod: Modifier = Modifier.new()\n\tspell_crit_damage_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.0, 0.01)\n\tcrit_damage_bt.set_buff_modifier(spell_crit_damage_mod)\n\tcrit_damage_bt.set_hidden()\n\n\nfunc on_attack(_event: Event):\n#\tSpellfire\n\tvar lvl: int = tower.get_level()\n\tvar buff_level_multiplier: float = (_stats.spellfire_ratio + _stats.spellfire_ratio_add * lvl) * 100\n\tvar spell_damage_level: int = int((tower.get_prop_spell_damage_dealt() - 1.0) * buff_level_multiplier)\n\tvar spell_crit_damage_level: int = int((tower.get_spell_crit_damage() - 1.0) * buff_level_multiplier)\n\tvar spell_crit_chance_level: int = int(tower.get_spell_crit_chance() * buff_level_multiplier)\n\n\tdamage_bt.apply(tower, tower, spell_damage_level)\n\tcrit_damage_bt.apply(tower, tower, spell_crit_damage_level)\n\tcrit_chance_bt.apply(tower, tower, spell_crit_chance_level)\n\n#\tSpellfire Projectiles\n\tvar mana: float = tower.get_mana()\n\tvar mana_threshold: float = MANA_THRESHOLD_BASE - _stats.mana_threshold_add * tower.get_level()\n\tvar extra_crit: bool = mana > mana_threshold\n\tvar custom_crit_ratio: float = tower.get_prop_atk_crit_damage() + (mana - mana_threshold) * _stats.extra_crit_dmg_per_mana\n\n\tif extra_crit:\n\t\tCombatLog.log_ability(tower, null, \"Spellfire Projectiles\")\n\n\t\ttower.subtract_mana(mana, false)\n\t\ttower.add_custom_attack_crit(custom_crit_ratio)\n"
  },
  {
    "path": "src/towers/tower_behaviors/initiate_elementalist.gd",
    "content": "extends TowerBehavior\n\n# NOTE: too many differences between tiers. Had to make\n# separate code paths for each tier.\n\n# NOTE: [ORIGINAL_GAME_BUG] Original script has typos. Fixed\n# them.\n# \n# 1. 50 dmg for Frost Nova of 2nd tier. Fixed it to 250.\n# \n# 2. Used aoe damage for \"Aftershork\" tier 3. Fixed to\n#    single target damage.\n\n\nvar stun_bt: BuffType\nvar slow_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.001)\n\tslow_bt = BuffType.new(\"slow_bt\", 0, 0, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_tooltip(tr(\"SZF9\"))\n\n\nfunc on_attack(event: Event):\n\tmatch tower.get_tier():\n\t\t1: return on_attack_1(event)\n\t\t2: return on_attack_2(event)\n\t\t3: return on_attack_3(event)\n\t\t4: return on_attack_4(event)\n\n\treturn \"\"\n\n\nfunc on_attack_1(event: Event):\n\tvar random_spell_id = Globals.synced_rng.randi_range(1, 3)\n\tvar c: Creep = event.get_target()\n\tvar u: Unit\n\tvar it: Iterate\n\n\tif random_spell_id < 3:\n\t\tCombatLog.log_ability(tower, c, \"Fire Blast\")\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 200, 190 + tower.get_level() * 7.6, tower.calc_spell_crit_no_bonus(), 0)\n\telse:\n\t\tCombatLog.log_ability(tower, c, \"Frost Nova\")\n\t\t\n\t\tit = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), c, 250)\n\n\t\twhile true:\n\t\t\tu = it.next()\n\n\t\t\tif u == null:\n\t\t\t\tbreak\n\n\t\t\tslow_bt.apply_custom_timed(tower, u, 100, 3)\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 250, 125 + tower.get_level() * 5, tower.calc_spell_crit_no_bonus(), 0)\n\t\t\t\n\nfunc on_attack_2(event: Event):\n\tvar random_spell_id = Globals.synced_rng.randi_range(1, 5)\n\tvar c: Creep = event.get_target()\n\tvar u: Unit\n\tvar it: Iterate\n\n\tif random_spell_id < 3:\n\t\tCombatLog.log_ability(tower, c, \"Fire Blast\")\n\t\t\n\t\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 250, 500 + tower.get_level() * 10, tower.calc_spell_crit_no_bonus(), 0)\n\telif random_spell_id < 5:\n\t\tCombatLog.log_ability(tower, c, \"Aftershock\")\n\t\t\n\t\tEffect.create_simple_at_unit(\"res://src/effects/ancient_protector_missile.tscn\", c)\n\t\tstun_bt.apply_only_timed(tower, c, 0.5 + tower.get_level() * 0.01)\n\t\ttower.do_spell_damage(c, 750, tower.calc_spell_crit_no_bonus())\n\telse:\n\t\tCombatLog.log_ability(tower, c, \"Frost Nova\")\n\t\t\n\t\tit = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), c, 250)\n\n\t\twhile true:\n\t\t\tu = it.next()\n\n\t\t\tif u == null:\n\t\t\t\tbreak\n\n\t\t\tslow_bt.apply_custom_timed(tower, u, 120, 3)\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 250, 250 + tower.get_level() * 8, tower.calc_spell_crit_no_bonus(), 0)\n\nfunc on_attack_3(event: Event):\n\tvar random_spell_id = Globals.synced_rng.randi_range(1, 10)\n\tvar c: Creep = event.get_target()\n\tvar u: Unit\n\tvar it: Iterate\n\tvar count: int\n\n\tif random_spell_id < 4:\n\t\tCombatLog.log_ability(tower, c, \"Fire Blast\")\n\t\t\n\t\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 250, 1650 + tower.get_level() * 18, tower.calc_spell_crit_no_bonus(), 0)\n\telif random_spell_id < 7:\n\t\tCombatLog.log_ability(tower, c, \"Aftershock\")\n\t\t\n\t\tEffect.create_simple_at_unit(\"res://src/effects/ancient_protector_missile.tscn\", c)\n\t\tstun_bt.apply_only_timed(tower, c, 0.5 + tower.get_level() * 0.01)\n\t\ttower.do_spell_damage(c, 2000, tower.calc_spell_crit_no_bonus())\n\telif random_spell_id < 9:\n\t\tCombatLog.log_ability(tower, c, \"Frost Nova\")\n\t\t\n\t\tit = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), c, 250)\n\n\t\twhile true:\n\t\t\tu = it.next()\n\n\t\t\tif u == null:\n\t\t\t\tbreak\n\n\t\t\tslow_bt.apply_custom_timed(tower, u, 140, 4)\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 250, 800 + tower.get_level() * 10, tower.calc_spell_crit_no_bonus(), 0)\n\telse:\n\t\tCombatLog.log_ability(tower, c, \"Lightning Burst\")\n\t\t\n\t\tit = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), c, 900)\n\n\t\twhile true:\n\t\t\tu = it.next()\n\t\t\tcount = count + 1\n\n\t\t\tif count == 6 || u == null:\n\t\t\t\tbreak\n\n\t\t\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", u)\n\t\t\ttower.do_spell_damage(u, 1650 + (tower.get_level() * 30), tower.calc_spell_crit_no_bonus())\n\t\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, tower, u)\n\t\t\tlightning.modulate = Color.LIGHT_BLUE\n\t\t\tlightning.set_lifetime(0.15)\n\n\nfunc on_attack_4(event: Event):\n\tvar random_spell_id = Globals.synced_rng.randi_range(1, 10)\n\tvar c: Creep = event.get_target()\n\tvar u: Unit\n\tvar it: Iterate\n\tvar count: int\n\n\tif random_spell_id < 4:\n# \t\tFireBlast\n\t\tCombatLog.log_ability(tower, c, \"Fire Blast\")\n\t\t\n\t\tif tower.user_int2 == 1:\n\t\t\ttower.user_int = tower.user_int + 1\n\t\telse:\n\t\t\ttower.user_int = 1\n\t\t\ttower.user_int2 = 1\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 300, (3000 + tower.get_level() * 60) * (1 + ((0.5 + tower.get_level() * 0.01) * (tower.user_int - 1))), tower.calc_spell_crit_no_bonus(), 0)\n\telif random_spell_id < 7:\n#\t\tAftershock\n\t\tCombatLog.log_ability(tower, c, \"Aftershock\")\n\t\t\n\t\tif tower.user_int2 == 2:\n\t\t\ttower.user_int = tower.user_int + 1\n\t\telse:\n\t\t\ttower.user_int = 1\n\t\t\ttower.user_int2 = 2\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/ancient_protector_missile.tscn\", c)\n\t\tstun_bt.apply_only_timed(tower, c, 0.7 + tower.get_level() * 0.02)\n\t\ttower.do_spell_damage(c, 6000 * (1 + ((0.5 + tower.get_level() * 0.01) * (tower.user_int - 1))), tower.calc_spell_crit_no_bonus())\n\telif random_spell_id < 9:\n#\t\tFrostNova\n\t\tCombatLog.log_ability(tower, c, \"Frost Nova\")\n\t\t\n\t\tif tower.user_int2 == 3:\n\t\t\ttower.user_int = tower.user_int + 1\n\t\telse:\n\t\t\ttower.user_int = 1\n\t\t\ttower.user_int2 = 3\n\n\t\tit = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), c, 300)\n\n\t\twhile true:\n\t\t\tu = it.next()\n\n\t\t\tif u == null:\n\t\t\t\tbreak\n\n\t\t\tslow_bt.apply_custom_timed(tower, u, 150, 4)\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", c)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/freezing_breath.tscn\", c)\n\t\ttower.do_spell_damage_aoe_unit(c, 300, (2000 + tower.get_level() * 80) * (1 + ((0.5 + tower.get_level() * 0.01) * (tower.user_int - 1))), tower.calc_spell_crit_no_bonus(), 0)\n\telse:\n#\t\tLightning Burst\n\t\tCombatLog.log_ability(tower, c, \"Lightning Burst\")\n\t\t\n\t\tif tower.user_int2 == 4:\n\t\t\ttower.user_int = tower.user_int + 1\n\t\telse:\n\t\t\ttower.user_int = 1\n\t\t\ttower.user_int2 = 4\n\n\t\tit = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), c, 900)\n\n\t\twhile true:\n\t\t\tu = it.next()\n\t\t\tcount = count + 1\n\n\t\t\tif count == 7 || u == null:\n\t\t\t\tbreak\n\n\t\t\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", u)\n\t\t\ttower.do_spell_damage(u, (3000 + tower.get_level() * 60) * (1 + ((0.5 + tower.get_level() * 0.01) * (tower.user_int - 1))), tower.calc_spell_crit_no_bonus())\n\t\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, tower, u)\n\t\t\tlightning.modulate = Color.LIGHT_BLUE\n\t\t\tlightning.set_lifetime(0.15)\n\n\nfunc on_create(_preceding: Tower):\n#\tStores how many consecutive times last spell was cast\n\ttower.user_int = 0\n#\tStores which spell was last cast\n\ttower.user_int2 = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/it.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Original script did not\n# allow placing Corruption Field before placing Recreation\n# Field. Removed this restriction.\n\n\nclass Summoner:\n\tvar size: float = 3.0\n\tvar corruption_effect: int = 0\n\tvar recreation_effect: int = 0\n\tvar from_pos: Vector2 = Vector2.INF\n\tvar dest_pos: Vector2 = Vector2.INF\n\n\n# NOTE: SCALE_MIN should match the value in tower sprite\n# scene\nconst SCALE_MIN: float = 0.7\nconst SCALE_MAX: float = 1.0\nconst TRANSPORT_CD: float = 1.0\nconst FIELD_RADIUS: float = 250\nconst FIELD_DAMAGE: float = 3000\nconst FIELD_DAMAGE_ADD: float = 100\n\n\nvar multiboard: MultiboardValues\nvar sum: Summoner = Summoner.new()\n# NOTE: this map is never cleared which is a bit suspect but\n# considering that the amount of creeps in game is capped at\n# 1000's and this stores references - it's not a big deal.\nvar summoner_units: Dictionary = {}\nvar tick_when_last_transported: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar spelldamage_bonus_label: String = tr(\"KERS\")\n\tmultiboard.set_key(0, spelldamage_bonus_label)\n\n\nfunc on_destruct():\n\tvar recreation_effect: int = sum.recreation_effect\n\tEffect.destroy_effect(recreation_effect)\n\tvar corruption_effect: int = sum.corruption_effect\n\tEffect.destroy_effect(corruption_effect)\n\n\nfunc on_attack(_event: Event):\n\tvar both_fields_were_placed: bool = sum.dest_pos != Vector2.INF && sum.from_pos != Vector2.INF\n\n\tif !both_fields_were_placed:\n\t\treturn\n\n#\tNOTE: use tick-based calculation to avoid float precision\n#\tdrift in multiplayer.\n\tvar transport_cd_ticks: int = Utils.time_to_ticks(TRANSPORT_CD)\n\tvar current_tick: int = Utils.get_current_tick()\n\tvar ticks_since_last_transport: int = current_tick - tick_when_last_transported\n\tvar transport_is_on_cooldown: bool = ticks_since_last_transport < transport_cd_ticks\n\n\tif transport_is_on_cooldown:\n\t\treturn\n\n\ttick_when_last_transported = current_tick\n\n\tvar aoe_dmg: float = FIELD_DAMAGE + FIELD_DAMAGE_ADD * tower.get_level()\n\ttower.do_spell_damage_aoe(sum.from_pos, FIELD_RADIUS, aoe_dmg, tower.calc_spell_crit_no_bonus(), 0.0)\n\n\tvar effect_from: int = Effect.create_colored(\"res://src/effects/arcane_tower_attack_flat.tscn\", Vector3(sum.from_pos.x, sum.from_pos.y, 100.0), 270.0, 2, Color8(0, 0, 0, 255))\n\tEffect.set_z_index(effect_from, Effect.Z_INDEX_BELOW_CREEPS)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), sum.from_pos, FIELD_RADIUS)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar creep: Creep = next as Creep\n\n\t\tif creep.get_size() >= CreepSize.enm.BOSS:\n\t\t\tcontinue\n\n\t\tvar already_summoned: bool = summoner_units.has(creep)\n\n\t\tif already_summoned:\n\t\t\tcontinue\n\n\t\tsummoner_units[creep] = true\n\n\t\tit_hunger_ability()\n\n\t\tvar random_offset: Vector2 = Vector2(Globals.synced_rng.randf_range(-25, 25), Globals.synced_rng.randf_range(-25, 25))\n\t\tvar dest_pos: Vector2 = sum.dest_pos + random_offset\n\n\t\tcreep.move_to_point(dest_pos)\n\n\ttower.do_spell_damage_aoe(sum.dest_pos, FIELD_RADIUS, aoe_dmg, tower.calc_spell_crit_no_bonus(), 0.0)\n\tvar effect_dest: int = Effect.create_colored(\"res://src/effects/arcane_tower_attack_flat.tscn\", Vector3(sum.dest_pos.x, sum.dest_pos.y, 100.0), 270.0, 2, Color8(0, 0, 0, 255))\n\tEffect.set_z_index(effect_dest, Effect.Z_INDEX_BELOW_CREEPS)\n\n\nfunc on_kill(_event: Event):\n\tit_hunger_ability()\n\n\n# NOTE: need to check that position of Recreation Field is\n# on creep path because creeps will get transported to that\n# position.\nfunc on_autocast_recreation(event: Event):\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar target_pos: Vector2 = autocast.get_target_pos()\n\t\n\tvar target_pos_is_on_path: bool = Utils.is_point_on_creep_path(target_pos, tower.get_player())\n\n\tif !target_pos_is_on_path:\n\t\tvar invalid_location_text: String = tr(\"FFW7\")\n\t\ttower.get_player().display_small_floating_text(invalid_location_text, tower, Color8(255, 150, 0), 30)\n\n\t\treturn\n\n\tsum.dest_pos = target_pos\n\n\tvar recreation_field_exists: bool = sum.recreation_effect != 0\n\n\tif !recreation_field_exists:\n\t\tsum.recreation_effect = Effect.create_animated(\"res://src/effects/vampiric_aura.tscn\", Vector3(target_pos.x, target_pos.y, 0), 270.0)\n\t\tEffect.set_z_index(sum.recreation_effect, Effect.Z_INDEX_BELOW_CREEPS)\n\t\tEffect.set_auto_destroy_enabled(sum.recreation_effect, false)\n\t\tEffect.set_color(sum.recreation_effect, Color8(255, 0, 0, 150))\n\telse:\n\t\tEffect.set_position(sum.recreation_effect, target_pos)\n\n\nfunc on_autocast_corruption(event: Event):\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar target_pos: Vector2 = autocast.get_target_pos()\n\n\tsum.from_pos = target_pos\n\n\tvar corruption_field_exists: bool = sum.corruption_effect != 0\n\n\tif !corruption_field_exists:\n\t\tsum.corruption_effect = Effect.create_animated(\"res://src/effects/vampiric_aura.tscn\", Vector3(target_pos.x, target_pos.y, 0), 270.0)\n\t\tEffect.set_z_index(sum.corruption_effect, Effect.Z_INDEX_BELOW_CREEPS)\n\t\tEffect.set_auto_destroy_enabled(sum.corruption_effect, false)\n\t\tEffect.set_color(sum.corruption_effect, Color8(0, 0, 255, 150))\n\telse:\n\t\tEffect.set_position(sum.corruption_effect, target_pos)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar spelldmg_bonus: float = sum.size - 3.0\n\tvar spelldmg_bonus_string: String = Utils.format_percent(spelldmg_bonus, 1)\n\tmultiboard.set_value(0, spelldmg_bonus_string)\n\n\treturn multiboard\n\n\n# NOTE: \"It_kill()\" in original script\nfunc it_hunger_ability():\n\tvar mod: float = 0.001 + 0.0001 * tower.get_level()\n\n\tif sum.size < 10.0:\n#\t\t700% cap\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, mod)\n\t\tsum.size += mod\n\n\tif sum.size < 3.7:\n\t\tvar tower_scale: float = Utils.get_scale_from_grows(SCALE_MIN, SCALE_MAX, sum.size - 3.0, 0.7)\n\t\ttower.set_unit_scale(tower_scale)\n"
  },
  {
    "path": "src/towers/tower_behaviors/jungle_stalker.gd",
    "content": "extends TowerBehavior\n\n\nvar rage_bt: BuffType\nvar feral_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {feral_dmg_gain = 0.002, feral_dmg_max = 2.00, bloodthirst_attack_speed = 1.00, bloodthirst_duration = 3, rage_buff_level_base = 0},\n\t\t2: {feral_dmg_gain = 0.003, feral_dmg_max = 2.25, bloodthirst_attack_speed = 1.25, bloodthirst_duration = 4, rage_buff_level_base = 25},\n\t\t3: {feral_dmg_gain = 0.004, feral_dmg_max = 2.50, bloodthirst_attack_speed = 1.50, bloodthirst_duration = 5, rage_buff_level_base = 50},\n\t}\n\n\nconst BLOODTHIRST_ATTACKSPEED_ADD: float = 0.01\nconst BLOODTHIRST_DURATION_ADD: float = 0.05\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\trage_bt = BuffType.new(\"rage_bt\", 0, 0, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 1.0, BLOODTHIRST_ATTACKSPEED_ADD)\n\trage_bt.set_buff_modifier(mod)\n\trage_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\trage_bt.set_buff_tooltip(tr(\"BLU0\"))\n\n\tferal_bt = BuffType.new(\"feral_bt\", -1, 0, true, self)\n\tferal_bt.set_buff_icon(\"res://resources/icons/generic_icons/orc_head.tres\")\n\tferal_bt.set_buff_tooltip(tr(\"XZ11\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar damage_bonus_label: String = tr(\"DS1C\")\n\tmultiboard.set_key(0, damage_bonus_label)\n\n\nfunc on_damage(event: Event):\n\tif event.is_attack_damage_critical() && tower.user_real <= _stats.feral_dmg_max:\n\t\ttower.user_real += _stats.feral_dmg_gain\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, _stats.feral_dmg_gain)\n\n\t\tvar feral_buff: Buff = tower.get_buff_of_type(feral_bt)\n\t\tvar feral_stack_count: int = floori(tower.user_real * 100)\n\t\tferal_buff.set_displayed_stacks(feral_stack_count)\n\n\nfunc on_kill(_event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar buff_level: int = lvl + _stats.rage_buff_level_base\n\tvar buff_duration: float = _stats.bloodthirst_duration + BLOODTHIRST_DURATION_ADD * lvl\n\n\tif tower.get_buff_of_type(rage_bt) == null:\n\t\tCombatLog.log_ability(tower, null, \"Bloodthirst\")\n\n\t\trage_bt.apply_custom_timed(tower, tower, buff_level, buff_duration)\n\n\nfunc on_create(preceding: Tower):\n\tif preceding != null && preceding.get_family() == tower.get_family():\n\t\tvar damage_bonus: float = preceding.user_real\n\t\ttower.user_real = damage_bonus\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, damage_bonus)\n\telse:\n\t\ttower.user_real = 0.0\n\n\tvar feral_buff: Buff = feral_bt.apply_to_unit_permanent(tower, tower, 0)\n\tvar feral_stack_count: int = floori(tower.user_real * 100)\n\tferal_buff.set_displayed_stacks(feral_stack_count)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar damage_bonus: String = Utils.format_percent(tower.user_real, 1)\n\n\tmultiboard.set_value(0, damage_bonus)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/kraken.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where Kraken\n# would crash the game. Not sure what caused the crash in\n# original game, it got fixed naturally in youtd2.\n\n# NOTE: changed how cooldown for tentacles is implemented.\n# Original script keeps a reference to periodic timer and\n# modifies it. Changed it to get rid of the need for\n# reference to timer. Instead, periodic callback shortens\n# it's own period when needed.\n\n\nvar stun_bt: BuffType\nvar acid_goo_bt: BuffType\nvar last_tick_when_used_tentacles: int = 0\nvar TARGET_TYPE_GROUND_ONLY: TargetType = TargetType.new(TargetType.CREEPS + TargetType.SIZE_MASS + TargetType.SIZE_NORMAL + TargetType.SIZE_CHAMPION + TargetType.SIZE_BOSS)\n\n\nconst ACID_GOO_CHANCE: float = 0.30\nconst ACID_GOO_CHANCE_ADD: float = 0.01\nconst ACID_GOO_ARMOR: float = 15.0\nconst ACID_GOO_ARMOR_ADD: float = 0.6\nconst ACID_GOO_DURATION: float = 5.0\nconst ACID_GOO_DURATION_ADD: float = 0.2\n\nconst EAT_THE_DEAD_VALUES: Dictionary = {\n\tCreepSize.enm.MASS: 0.005,\n\tCreepSize.enm.NORMAL: 0.01,\n\tCreepSize.enm.AIR: 0.02,\n\tCreepSize.enm.CHAMPION: 0.02,\n\tCreepSize.enm.BOSS: 0.10,\n}\n\nconst TENTACLE_ATTACK_RADIUS: float = 1200\nconst TENTACLE_ATTACK_CD: float = 4.0\nconst TENTACLE_ATTACK_CD_ADD: float = -0.04\nconst TENTACLE_ATTACK_TENTACLE_COUNT: int = 6\nconst TENTACLE_ATTACK_DAMAGE_RATIO: float = 0.15\nconst TENTACLE_ATTACK_STUN_DURATION: float = 0.4\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_kill(on_kill)\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\ttriggers_buff_type.add_periodic_event(periodic, 4.0)\n\ttriggers_buff_type.add_event_on_unit_comes_in_range(on_unit_in_range, TENTACLE_ATTACK_RADIUS, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tacid_goo_bt = BuffType.new(\"acid_goo_bt\", ACID_GOO_DURATION, ACID_GOO_DURATION_ADD, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR, -ACID_GOO_ARMOR, -ACID_GOO_ARMOR_ADD)\n\tacid_goo_bt.set_buff_modifier(mod)\n\tacid_goo_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tacid_goo_bt.set_buff_tooltip(tr(\"L7ND\"))\n\n\nfunc on_kill(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar target_size: CreepSize.enm = target.get_size()\n\n\tvar mod_value: float = EAT_THE_DEAD_VALUES.get(target_size, 0)\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, mod_value)\n\n\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/blood_splatter.tscn\", target)\n\tEffect.set_scale(effect, 2)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tvar chance: float = ACID_GOO_CHANCE + ACID_GOO_CHANCE_ADD * level\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Acid Goo\")\n\n\tacid_goo_bt.apply(tower, target, level)\n\n\n# NOTE: need to adjust periodic timer because tentacles can\n# be also fired inside on_unit_in_range().\nfunc periodic(event: Event):\n\tvar tentacles_are_on_cd: bool = get_tentacles_are_on_cd()\n\n\tif tentacles_are_on_cd:\n\t\tvar tentacles_cd: float = get_tentacles_cd()\n\t\tvar tentacles_cd_ticks: int = Utils.time_to_ticks(tentacles_cd)\n\t\tvar current_tick: int = Utils.get_current_tick()\n\t\tvar tick_for_next_tentacles: int = last_tick_when_used_tentacles + tentacles_cd_ticks\n\t\tvar remaining_cd_ticks: int = tick_for_next_tentacles - current_tick\n\t\tvar remaining_cd: float = Utils.ticks_to_time(remaining_cd_ticks)\n\n\t\tevent.enable_advanced(remaining_cd, false)\n\telse:\n\t\tfire_tentacles()\n\n\t\tvar tentacles_cd: float = get_tentacles_cd()\n\t\tevent.enable_advanced(tentacles_cd, false)\n\n\nfunc on_unit_in_range(_event: Event):\n\tvar tentacles_are_on_cd: bool = get_tentacles_are_on_cd()\n\n\tif !tentacles_are_on_cd:\n\t\tfire_tentacles()\n\n\nfunc fire_tentacles():\n\tvar level: int = tower.get_level()\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TARGET_TYPE_GROUND_ONLY, TENTACLE_ATTACK_RADIUS)\n\n\tvar tentacle_count_max: int = TENTACLE_ATTACK_TENTACLE_COUNT\n\tif level == 25:\n\t\ttentacle_count_max += 2\n\telif level >= 15:\n\t\ttentacle_count_max += 1\n\n\tvar tentacle_count: int = 0\n\n\tvar tentacle_damage: float = TENTACLE_ATTACK_DAMAGE_RATIO * tower.get_current_attack_damage_with_bonus()\n\n\tif it.count() > 0:\n\t\tCombatLog.log_ability(tower, null, \"Tentacle Attack\")\n\n\twhile true:\n\t\tif tentacle_count >= tentacle_count_max:\n\t\t\tbreak\n\n\t\tvar target: Unit = it.next_random()\n\t\t\n\t\tif target == null:\n\t\t\tbreak\n\t\t\n\t\tvar random_offset: Vector2 = Vector2(Globals.synced_rng.randf_range(-35, 35), Globals.synced_rng.randf_range(-35, 35))\n\t\tvar effect_pos: Vector2 = target.get_position_wc3_2d() + random_offset\n\t\tEffect.add_special_effect(\"res://src/effects/impale_hit_target.tscn\", effect_pos)\n\n\t\tstun_bt.apply_only_timed(tower, target, TENTACLE_ATTACK_STUN_DURATION)\n\n\t\ttower.do_custom_attack_damage(target, tentacle_damage, tower.calc_attack_multicrit_no_bonus(), AttackType.enm.PHYSICAL)\n\n\t\ttentacle_count += 1\n\n\tvar created_any_tentacles: bool = tentacle_count > 0\n\tif created_any_tentacles:\n\t\tlast_tick_when_used_tentacles = Utils.get_current_tick()\n\n\nfunc get_tentacles_cd() -> float:\n\tvar level: int = tower.get_level()\n\tvar cd: float = TENTACLE_ATTACK_CD + TENTACLE_ATTACK_CD_ADD * level\n\n\treturn cd\n\n\nfunc get_tentacles_are_on_cd() -> bool:\n\tvar tentacles_cd: float = get_tentacles_cd()\n\tvar tentacles_cd_ticks: int = Utils.time_to_ticks(tentacles_cd)\n\tvar current_tick: int = Utils.get_current_tick()\n\tvar ticks_since_last_tentacles: int = current_tick - last_tick_when_used_tentacles\n\tvar tentacles_are_on_cd: bool = ticks_since_last_tentacles < tentacles_cd_ticks\n\n\treturn tentacles_are_on_cd\n"
  },
  {
    "path": "src/towers/tower_behaviors/lesser_elemental_ghost.gd",
    "content": "extends TowerBehavior\n\n\nvar wrath_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {wrath_mod_trigger_chances_add = 0.005, elemental_wrath_chance = 0.150},\n\t\t2: {wrath_mod_trigger_chances_add = 0.006, elemental_wrath_chance = 0.175},\n\t\t3: {wrath_mod_trigger_chances_add = 0.007, elemental_wrath_chance = 0.200},\n\t\t4: {wrath_mod_trigger_chances_add = 0.008, elemental_wrath_chance = 0.225},\n\t\t5: {wrath_mod_trigger_chances_add = 0.009, elemental_wrath_chance = 0.250},\n\t}\n\n\nvar BUFF_DURATION: float = 5.0\nvar BUFF_DURATION_ADD: float = 0.1\nvar WRATH_MOD_TRIGGER_CHANCES: float = 0.15\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, WRATH_MOD_TRIGGER_CHANCES, _stats.wrath_mod_trigger_chances_add)\n\twrath_bt = BuffType.new(\"wrath_bt\", BUFF_DURATION, BUFF_DURATION_ADD, true, self)\n\twrath_bt.set_buff_icon(\"res://resources/icons/generic_icons/holy_grail.tres\")\n\twrath_bt.set_buff_modifier(modifier)\n\twrath_bt.set_buff_tooltip(tr(\"ANUA\"))\n\n\nfunc on_attack(_event: Event):\n\tif !tower.calc_chance(_stats.elemental_wrath_chance):\n\t\treturn\n\n\tif tower.get_buff_of_type(wrath_bt) == null:\n\t\tCombatLog.log_ability(tower, null, \"Elemental Wrath\")\n\n\t\tvar level: int = tower.get_level()\n\n\t\twrath_bt.apply(tower, tower, level)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar immune: bool = target.is_immune()\n\tvar sif: bool = target.get_armor_type() == ArmorType.enm.SIF\n\tvar zod: bool = target.get_armor_type() == ArmorType.enm.ZOD\n\tvar damage_add: float\n\tvar pos_damage_types: float = 3.0\n\n\tif immune:\n\t\tpos_damage_types = 2.0\n\n\tif Utils.rand_chance(Globals.synced_rng, 0.5):\n\t\tif sif || zod:\n\t\t\tdamage_add = 1.0\n\t\telif tower.calc_chance(1.0 / pos_damage_types):\n\t\t\tdamage_add = 1.8\n\t\telif !immune && tower.calc_chance(1.0 / (pos_damage_types - 1)):\n\t\t\tdamage_add = 1.5\n\t\telse:\n\t\t\tdamage_add = 1.2\n\telse:\n\t\tif zod:\n\t\t\tdamage_add = 0.9\n\t\telif sif:\n\t\t\tif !immune || (immune && tower.calc_chance(0.5)):\n\t\t\t\tdamage_add = 0.4\n\t\t\telse:\n\t\t\t\tdamage_add = 0.0\n\t\telif tower.calc_chance(1.0 / (6.0 - pos_damage_types)):\n\t\t\tdamage_add = 1.0\n\t\telif tower.calc_chance(1.0 / (6.0 - (pos_damage_types + 1))):\n\t\t\tdamage_add = 0.9\n\t\telif !immune || (immune && tower.calc_chance(1.0 / (6.0 - (pos_damage_types + 2)))):\n\t\t\tdamage_add = 0.6\n\t\telse:\n\t\t\tdamage_add = 0.0\n\n\tevent.damage = event.damage * damage_add\n\n\tif damage_add > 1.0:\n\t\ttower.get_player().display_small_floating_text(Utils.format_float(damage_add, 2), tower, Color8(0, 255, 0), 40)\n\telif damage_add < 1.0:\n\t\ttower.get_player().display_small_floating_text(Utils.format_float(damage_add, 2), tower, Color8(255, 0, 0), 40)\n\telse:\n\t\ttower.get_player().display_small_floating_text(Utils.format_float(damage_add, 2), tower, Color8(255, 255, 255), 40)\n"
  },
  {
    "path": "src/towers/tower_behaviors/lesser_priest.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {smite_damage = 10, smite_damage_add = 18, armor_reduce = -0.6, armor_reduce_boss = -0.2},\n\t\t2: {smite_damage = 35, smite_damage_add = 63, armor_reduce = -0.9, armor_reduce_boss = -0.3},\n\t\t3: {smite_damage = 90, smite_damage_add = 162, armor_reduce = -1.2, armor_reduce_boss = -0.4},\n\t\t4: {smite_damage = 190, smite_damage_add = 342, armor_reduce = -1.5, armor_reduce_boss = -0.5},\n\t\t5: {smite_damage = 380, smite_damage_add = 648, armor_reduce = -1.8, armor_reduce_boss = -0.6},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(0.05 + tower.get_level() * 0.02):\n\t\treturn\n\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tCombatLog.log_ability(tower, creep, \"Smite\")\n\n\ttower.do_spell_damage(creep, _stats.smite_damage + (level * _stats.smite_damage_add), tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/holy_bolt.tscn\", creep)\n\n\tif level == 25:\n\t\tif creep.get_size() < CreepSize.enm.BOSS:\n\t\t\tcreep.modify_property(ModificationType.enm.MOD_ARMOR, _stats.armor_reduce)\n\t\telse:\n\t\t\tcreep.modify_property(ModificationType.enm.MOD_ARMOR, _stats.armor_reduce_boss)\n"
  },
  {
    "path": "src/towers/tower_behaviors/lesser_skeletal_mage.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug in original script\n# where buff duration level bonus was equal to 0.6s instead\n# of 0.1s. This happened becase apply() was called with \"6 *\n# lvl\".\n\n\nvar curse_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {vuln = 0.15},\n\t\t2: {vuln = 0.22},\n\t\t3: {vuln = 0.29},\n\t\t4: {vuln = 0.36},\n\t}\n\n\nconst VULN_ADD: float = 0.006\nconst CURSE_DURATION: float = 5\nconst CURSE_DURATION_ADD: float = 0.1\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar lvl: int = tower.get_level()\n\n\tcurse_bt.apply(tower, target, lvl)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, _stats.vuln, VULN_ADD)\n\tcurse_bt = BuffType.new(\"curse_bt\", CURSE_DURATION, CURSE_DURATION_ADD, false, self)\n\tcurse_bt.set_buff_modifier(m)\n\tcurse_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\tcurse_bt.set_buff_tooltip(tr(\"N9AS\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/lesser_wolves_den.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_attack_speed = 0.10, mod_attack_speed_add = 0.0050},\n\t\t2: {mod_attack_speed = 0.15, mod_attack_speed_add = 0.0075},\n\t\t3: {mod_attack_speed = 0.20, mod_attack_speed_add = 0.0100},\n\t}\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tm.add_modification(ModificationType.enm.MOD_ATTACKSPEED, _stats.mod_attack_speed, _stats.mod_attack_speed_add)\n\taura_bt.set_buff_modifier(m)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/aries.tres\")\n\taura_bt.set_buff_tooltip(tr(\"GGZN\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/library_of_alexandria.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar teachings_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 5.0)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar library_aura_mod: Modifier = Modifier.new()\n\tlibrary_aura_mod.add_modification(ModificationType.enm.MOD_EXP_GRANTED, 0.30, 0.01)\n\taura_bt.set_buff_modifier(library_aura_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\taura_bt.set_buff_tooltip(tr(\"OTAZ\"))\n\n\tteachings_bt = BuffType.new(\"teachings_bt\", 10, 0.2, true, self)\n\tvar library_divine_teachings_mod: Modifier = Modifier.new()\n\tlibrary_divine_teachings_mod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, 1.0, 0.02)\n\tteachings_bt.set_buff_modifier(library_divine_teachings_mod)\n\tteachings_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\tteachings_bt.set_buff_tooltip(tr(\"TL4V\"))\n\n\nfunc periodic(_event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar towers_in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\tvar random_tower: Tower = towers_in_range.next_random()\n\n\tif random_tower == null:\n\t\treturn\n\n\trandom_tower.add_exp(2 + lvl * 0.2)\n\tEffect.create_simple_at_unit(\"res://src/effects/spell_alim.tscn\", random_tower)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\ttower.add_exp(2)\n\tteachings_bt.apply(tower, target, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/lich_king.gd",
    "content": "extends TowerBehavior\n\n\nvar curse_bt: BuffType\nvar aura_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tcurse_bt = BuffType.new(\"curse_bt\", 5, 0, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, 0.30, 0.008)\n\tcurse_bt.set_buff_modifier(mod)\n\tcurse_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\tcurse_bt.set_buff_tooltip(tr(\"AFMY\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/omega.tres\")\n\taura_bt.add_event_on_create(aura_bt_on_create)\n\taura_bt.add_event_on_refresh(aura_bt_on_refresh)\n\taura_bt.add_event_on_cleanup(aura_bt_on_cleanup)\n\taura_bt.set_buff_tooltip(tr(\"FOMA\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar stored_damage_label: String = tr(\"HXEE\")\n\tmultiboard.set_key(0, stored_damage_label)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tcurse_bt.apply(tower, target, level)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar stored_damage_string: String = Utils.format_float(tower.user_real, 0)\n\tmultiboard.set_value(0, stored_damage_string)\n\n\treturn multiboard\n\n\nfunc aura_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\n\tvar buff_apply_tick: int = Utils.get_current_tick()\n\tvar max_dps: int = buff.get_level()\n\tvar buff_stored_damage: float = 0.0\n\tvar caster_id: int = caster.get_instance_id()\n\n\tbuff.user_int = buff_apply_tick\n\tbuff.user_int2 = max_dps\n\tbuff.user_int3 = caster_id\n\tbuff.user_real = buff_stored_damage\n\n\nfunc aura_bt_on_refresh(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar new_dps: int = buff.get_level()\n\tvar old_king_id: int = buff.user_int3\n\tvar old_king: Unit = instance_from_id(old_king_id)\n\tvar new_king: Unit = buff.get_caster()\n\tvar new_king_id: int = new_king.get_instance_id()\n\n\tif old_king == null:\n\t\treturn\n\n\tvar old_wrath_damage: float = old_king.user_real * (0.5 + 0.04 * old_king.get_level())\n\n\told_king.user_real = 0.0\n\tbuff.user_int3 = new_king_id\n\n\tif new_dps > buff.user_int2:\n\t\tbuff.user_int2 = new_dps\n\n\tif old_wrath_damage > 0.0:\n\t\tbuff.user_real = buff.user_real + old_wrath_damage\n\n\nfunc aura_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar caster: Unit = buff.get_caster()\n\n\tvar apply_tick: int = buff.user_int\n\tvar max_dps: int = buff.user_int2\n\tvar buff_stored_damage: float = buff.user_real\n\n#\tNOTE: use tick-based calculation to avoid float precision\n#\tdrift in multiplayer.\n\tvar current_tick: int = Utils.get_current_tick()\n\tvar elapsed_ticks: int = current_tick - apply_tick\n\tvar elapsed_time: float = Utils.ticks_to_time(elapsed_ticks)\n\tvar damage: float = elapsed_time * max_dps\n\tdamage += buff_stored_damage\n\n\tif target.get_health() > 0:\n\t\tif caster.user_real > 0:\n\t\t\tvar feel_the_wrath_text: String = tr(\"A8KA\")\n\t\t\tcaster.get_player().display_floating_text(feel_the_wrath_text, caster, Color8(15, 15, 200))\n\t\t\tvar stored_damage_ratio: float = 0.5 + 0.04 * caster.get_level()\n\t\t\tdamage += caster.user_real * stored_damage_ratio\n\t\t\tcaster.user_real = 0.0\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", target)\n\t\tcaster.do_spell_damage(target, damage, caster.calc_spell_crit_no_bonus())\n\t\tcaster.get_player().display_floating_text(Utils.format_float(damage, 0), caster, Color8(15, 15, 200))\n\telse:\n\t\tcaster.user_real += damage\n\t\tcaster.get_player().display_floating_text(\"+\" + Utils.format_float(damage, 0), caster, Color8(15, 15, 200))\n"
  },
  {
    "path": "src/towers/tower_behaviors/lightning_eye.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar forklight_st: SpellType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\taura_bt.add_event_on_damage(aura_bt_on_damage)\n\taura_bt.set_buff_tooltip(tr(\"AUDO\"))\n\n\tforklight_st = SpellType.new(SpellType.Name.FORKED_LIGHTNING, 1, self)\n\tforklight_st.data.forked_lightning.damage = 1.0\n\tforklight_st.data.forked_lightning.target_count = 3\n\n\nfunc on_attack(event: Event):\n\tvar creep: Creep = event.get_target()\n\tvar creep_health: float = creep.get_health()\n\tvar tower_mana: float = tower.get_mana()\n\tvar level: int = tower.get_level()\n\tvar glare_damage: float = 500 + 120 * level + 0.015 * creep_health\n\n\tif tower_mana < 40:\n\t\treturn\n\n\ttower.subtract_mana(40, false)\n\n\tforklight_st.target_cast_from_caster(tower, creep, glare_damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc aura_bt_on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar damage_multiplier: float = 1.2 + 0.01 * tower.get_level()\n\n\tif target.is_immune():\n\t\tevent.damage *= damage_multiplier\n"
  },
  {
    "path": "src/towers/tower_behaviors/lightning_generator.gd",
    "content": "extends TowerBehavior\n\n\nvar chainlight_st: SpellType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {chain_damage = 150, on_attack_damage = 70},\n\t\t2: {chain_damage = 560, on_attack_damage = 260},\n\t\t3: {chain_damage = 1680, on_attack_damage = 770},\n\t\t4: {chain_damage = 4000, on_attack_damage = 1840},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tchainlight_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 5.00, self)\n\tchainlight_st.data.chain_lightning.damage = _stats.chain_damage\n\tchainlight_st.data.chain_lightning.chain_count = 3\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(0.195 + tower.get_level() * 0.0025):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Chainlightning\")\n\n\tchainlight_st.target_cast_from_caster(tower, event.get_target(), 1.0 + tower.get_level() * 0.02, tower.calc_spell_crit_no_bonus())\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\ttower.do_spell_damage(creep, _stats.on_attack_damage * (1 + tower.get_level() * 0.02), tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/lightning_totem.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt : BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_spell_crit = 0.10},\n\t\t2: {mod_spell_crit = 0.15},\n\t\t3: {mod_spell_crit = 0.20},\n\t}\n\n\nconst MOD_SPELL_CRIT_ADD: float = 0.002\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, _stats.mod_spell_crit, MOD_SPELL_CRIT_ADD)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\taura_bt.set_buff_tooltip(tr(\"D49Z\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/little_phoenix.gd",
    "content": "extends TowerBehavior\n\n\nvar phoenix_pt: ProjectileType\nvar phoenix_fire_bt: BuffType\nvar buff_was_purged: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {target_count = 2, mod_armor = 0.50, mod_armor_add = 0.010, erupt_damage = 100, armor_regain = 0.70, armor_regain_add = 0.010, damage_per_buff_level = 1.0},\n\t\t2: {target_count = 3, mod_armor = 0.60, mod_armor_add = 0.015, erupt_damage = 260, armor_regain = 0.60, armor_regain_add = 0.015, damage_per_buff_level = 2.6},\n\t\t3: {target_count = 4, mod_armor = 0.70, mod_armor_add = 0.020, erupt_damage = 440, armor_regain = 0.50, armor_regain_add = 0.020, damage_per_buff_level = 4.4},\n\t}\n\n\nconst DEBUFF_DURATION: float = 5.0\nconst ERUPT_RANGE: float = 200\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\n# NOTE: tomy_PhoenixAttackHit() in original script \nfunc tomy_phoenix_attack_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\t_apply_phoenix_fire_buff(target)\n\n\ttower.do_attack_damage(target, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit(0, 0, 0))\n\n\n# NOTE: tomy_PhoenixFireBuffPurged() in original script \nfunc phoenix_fire_bt_on_purge(_event: Event):\n\tbuff_was_purged = true\n\n\n# NOTE: tomy_PhoenixFireBuffExpired() in original script \nfunc phoenix_fire_bt_on_cleanup(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar buff: Buff = event.get_buff()\n\tvar buff_level: int = buff.get_level()\n\tvar level: int = tower.get_level()\n\tvar damage_multiplier: float = tower.get_current_attack_damage_with_bonus() / tower.get_base_damage()\n\tvar eruption_damage: float = buff_level * _stats.damage_per_buff_level * damage_multiplier\n\tvar armor_regain_factor: float = _stats.armor_regain + _stats.armor_regain_add * level\n\tvar armor_regain: float = -buff_level / 100.0 * (1 - armor_regain_factor)\n\n\tif !buff_was_purged:\n\t\ttower.do_attack_damage_aoe_unit(target, ERUPT_RANGE, eruption_damage, tower.calc_attack_multicrit(0, 0, 0), 0.5)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", target)\n\n\ttarget.modify_property(ModificationType.enm.MOD_ARMOR, armor_regain)\n\n\tbuff_was_purged = false\n\n\nfunc tower_init():\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR, 0.0, -0.01)\n\n\tphoenix_fire_bt = BuffType.new(\"phoenix_fire_bt\", 5, 0, false, self)\n\tphoenix_fire_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tphoenix_fire_bt.set_buff_modifier(mod)\n\tphoenix_fire_bt.add_event_on_cleanup(phoenix_fire_bt_on_cleanup)\n\tphoenix_fire_bt.add_event_on_purge(phoenix_fire_bt_on_purge)\n\tphoenix_fire_bt.set_buff_tooltip(tr(\"C1QL\"))\n\n\tphoenix_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 800, self)\n\tphoenix_pt.set_event_on_interpolation_finished(tomy_phoenix_attack_hit)\n\n\nfunc on_attack(event: Event):\n\tvar main_target: Unit = event.get_target()\n#\tNOTE: subtract 1 from target_count because the normal\n#\tattack performed by tower is part of that count\n\tvar current_target_count: int = _stats.target_count - 1\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), main_target, 450)\n\tvar sidearc: float = 0.2\n\n\tif tower.get_level() >= 15:\n\t\tcurrent_target_count += 1\n\n\twhile current_target_count > 0:\n\t\tvar target: Unit\n\n\t\tif it.count() > 0:\n\t\t\ttarget = it.next()\n\t\telse:\n\t\t\ttarget = main_target\n\n\t\tvar projectile: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(phoenix_pt, tower, 0, 0, tower, target, 0, sidearc, 0, true)\n\t\tprojectile.set_projectile_scale(0.4)\n\n\t\tcurrent_target_count -= 1\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\t_apply_phoenix_fire_buff(target)\n\n\nfunc on_autocast(_event: Event):\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 3000)\n\n\twhile it.count() > 0:\n\t\tvar creep: Unit = it.next()\n\n\t\tvar buff: Buff = creep.get_buff_of_type(phoenix_fire_bt)\n\n\t\tif buff != null:\n\t\t\tbuff.remove_buff()\n\n\nfunc _apply_phoenix_fire_buff(target: Unit):\n\tvar level: int = tower.get_level()\n\tvar armor_loss: float = _stats.mod_armor + _stats.mod_armor_add * level\n\tvar buff: Buff = target.get_buff_of_type(phoenix_fire_bt)\n\n\tif buff != null:\n\t\tphoenix_fire_bt.apply(tower, target, buff.get_level() + int(armor_loss * 100))\n\telse:\n\t\tphoenix_fire_bt.apply(tower, target, int(armor_loss * 100))\n\n\tbuff = target.get_buff_of_type(phoenix_fire_bt)\n\tif buff != null:\n\t\tvar stack_count: int = roundi(Utils.divide_safe(buff.get_level(), armor_loss * 100))\n\t\tbuff.set_displayed_stacks(stack_count)\n"
  },
  {
    "path": "src/towers/tower_behaviors/living_volcano.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar lava_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\taura_bt.set_buff_tooltip(tr(\"WMGO\"))\n\taura_bt.add_periodic_event(aura_bt_periodic, 1.0)\n\taura_bt.add_event_on_death(aura_bt_on_death)\n\n\tlava_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 650, self)\n\tlava_pt.set_event_on_cleanup(lava_pt_on_cleanup)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar lvl: int = tower.get_level()\n\tvar aoe_radius: float = 300 + 5 * lvl\n\tvar aoe_damage: float = 3500 + 100 * lvl\n\tvar lava_attack_chance: float = 0.25\n\n\tif !tower.calc_chance(lava_attack_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Lava Attack\")\n\n\tvar p: Projectile = Projectile.create_linear_interpolation_from_unit_to_point(lava_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, Vector3(target.get_x(), target.get_y(), 0), 0.45)\n\tp.user_real = aoe_radius\n\tp.user_real2 = aoe_damage\n\n\nfunc lava_pt_on_cleanup(p: Projectile):\n\tvar aoe_radius: float = p.user_real\n\tvar aoe_damage: float = p.user_real2\n\tEffect.add_special_effect(\"res://src/effects/incinerate.tscn\", Vector2(p.get_x(), p.get_y()))\n\ttower.do_spell_damage_aoe(Vector2(p.get_x(), p.get_y()), aoe_radius, aoe_damage, tower.calc_spell_crit_no_bonus(), 0.25)\n\n\nfunc aura_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar life: float = creep.get_health()\n\tvar dmg: float = life * 0.03 * tower.get_damage_to_category(creep.get_category())\n\n#\tGex meant it is okay so...\n\tif life < 2.0:\n\t\tCombatLog.log_ability(tower, creep, \"Heat Aura instant kill\")\n\t\t\n\t\ttower.kill_instantly(creep)\n\telse:\n\t\tcreep.set_health(life - dmg)\n\n\nfunc aura_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Creep = buff.get_buffed_unit()\n\tvar heat_stroke_chance: float = 0.40\n\tvar aoe_radius: float = 300\n\tvar aoe_damage: float = 4500 + 100 * tower.get_level()\n\n\tif !tower.calc_chance(heat_stroke_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Heat Stroke\")\n\n\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", creep)\n\ttower.do_spell_damage_aoe_unit(creep, aoe_radius, aoe_damage, tower.calc_spell_crit_no_bonus(), 0.33)\n"
  },
  {
    "path": "src/towers/tower_behaviors/lunar_emitter.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {aura_range = 800, mod_spell_resist = 0.150, mod_spell_resist_add = 0.0045, vuln = 0.10, vuln_add = 0.003},\n\t\t2: {aura_range = 1100, mod_spell_resist = 0.225, mod_spell_resist_add = 0.0075, vuln = 0.15, vuln_add = 0.005},\n\t}\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, _stats.mod_spell_resist, _stats.mod_spell_resist_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_ASTRAL, _stats.vuln, _stats.vuln_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_DARKNESS, _stats.vuln, _stats.vuln_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_ICE, _stats.vuln, _stats.vuln_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_STORM, _stats.vuln, _stats.vuln_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/over_infinity.tres\")\n\taura_bt.set_buff_tooltip(tr(\"Y6TX\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/lunar_sentinel.gd",
    "content": "extends TowerBehavior\n\n\nvar lunar_energy_bt: BuffType\nvar stun_bt: BuffType\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug for tier 4 tower. In\n# original game, the \"lunar_energy_dmg_add\" value for tier 4\n# was 1000 even though ability description says it's should\n# be 100.\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {spell_damage = 50, spell_damage_15 = 70, spell_damage_add = 2, lunar_energy_dmg_add = 2, buff_level = 120, buff_level_15 = 150},\n\t\t2: {spell_damage = 500, spell_damage_15 = 700, spell_damage_add = 20, lunar_energy_dmg_add = 20, buff_level = 160, buff_level_15 = 200},\n\t\t3: {spell_damage = 1500, spell_damage_15 = 2100, spell_damage_add = 60, lunar_energy_dmg_add = 60, buff_level = 200, buff_level_15 = 250},\n\t\t4: {spell_damage = 2500, spell_damage_15 = 3500, spell_damage_add = 100, lunar_energy_dmg_add = 100, buff_level = 240, buff_level_15 = 300},\n\t}\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\tvar m: Modifier = Modifier.new()\n\tlunar_energy_bt = BuffType.new(\"lunar_energy_bt\", 0, 0, false, self)\n\tm.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0, 0.001)\n\tlunar_energy_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\n\tlunar_energy_bt.set_buff_tooltip(tr(\"LSE1\"))\n\n\nfunc on_autocast(event: Event):\n\tvar level: int = tower.get_level()\n\tvar target: Unit = event.get_target()\n\n\tif level < 15:\n\t\ttower.do_spell_damage(target, _stats.spell_damage + level * _stats.spell_damage_add, tower.calc_spell_crit_no_bonus())\n\telse:\n\t\ttower.do_spell_damage(target, _stats.spell_damage_15 + level * _stats.spell_damage_add, tower.calc_spell_crit_no_bonus())\n\n\tif tower.calc_chance(0.125 + level * 0.005) == true:\n\t\tCombatLog.log_ability(tower, target, \"Lunar Grace Bonus\")\n\n\t\ttower.do_spell_damage(target, _stats.spell_damage + level * _stats.lunar_energy_dmg_add, tower.calc_spell_crit_no_bonus())\n\n\t\tif level < 25:\n\t\t\tstun_bt.apply_only_timed(tower, target, 0.3)\n\t\telse:\n\t\t\tstun_bt.apply_only_timed(tower, target, 0.4)\n\n\t\tif level < 15:\n\t\t\tlunar_energy_bt.apply_custom_timed(tower, target, _stats.buff_level, 2.5)\n\t\telse:\n\t\t\tlunar_energy_bt.apply_custom_timed(tower, target, _stats.buff_level_15, 2.5)\n"
  },
  {
    "path": "src/towers/tower_behaviors/magic_battery.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: rewrote script a bit. Instead of enabling/disabling\n# periodic event I added a flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where it refunds the cost of autocast in\n# on_autocast(). It refunds the cost by calling set_mana()\n# but the problem is that at the time when on_autocast() is\n# called, the mana cost has not been spent yet. Therefore,\n# refund fails if tower is at max mana because set_mana()\n# can't go above max mana. Not critical - don't need to fix.\n\n\nvar faerie_bt: BuffType\nvar missile_pt: ProjectileType\n\nvar _battery_overload_is_active: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 300, projectile_damage_add = 12, mod_spell_damage = 0.10, mod_spell_damage_add = 0.004, mod_debuff_duration = 0.20, mod_debuff_duration_add = 0.006},\n\t\t2: {projectile_damage = 750, projectile_damage_add = 30, mod_spell_damage = 0.15, mod_spell_damage_add = 0.006, mod_debuff_duration = 0.25, mod_debuff_duration_add = 0.008},\n\t\t3: {projectile_damage = 1800, projectile_damage_add = 72, mod_spell_damage = 0.20, mod_spell_damage_add = 0.008, mod_debuff_duration = 0.30, mod_debuff_duration_add = 0.010},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc on_autocast(_event: Event):\n\ttower.set_mana(tower.get_mana() + 100)\n\t_battery_overload_is_active = true\n\n\n# NOTE: hit() in original script\nfunc missile_pt_on_hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.projectile_damage + _stats.projectile_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tfaerie_bt.apply(tower, creep, level)\n\n\nfunc tower_init():\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, _stats.mod_spell_damage, _stats.mod_spell_damage_add)\n\tmodifier.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, _stats.mod_debuff_duration, _stats.mod_debuff_duration_add)\n\n\tfaerie_bt = BuffType.new(\"faerie_bt\", 9, 0.3, false, self)\n\tfaerie_bt.set_buff_icon(\"res://resources/icons/generic_icons/pisces.tres\")\n\tfaerie_bt.set_buff_modifier(modifier)\n\tfaerie_bt.set_buff_tooltip(tr(\"VHUM\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\tmissile_pt.enable_homing(missile_pt_on_hit, 0)\n\n\nfunc on_damage(event: Event):\n\tfaerie_bt.apply(tower, event.get_target(), tower.get_level())\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.set_mana(0)\n\n\nfunc periodic(_event: Event):\n\tif !_battery_overload_is_active:\n\t\treturn\n\n\tif tower.get_mana() > 10:\n\t\tvar in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar target: Unit = in_range.next_random()\n\n\t\tif target != null:\n# \t\t\tNOTE: original script used createFromPointToUnit and made projectiles from high above the tower\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\t\tp.set_projectile_scale(0.5)\n\n#\t\tSpend mana, note that mana is used for unsuccessful\n#\t\tattempts as well\n\t\ttower.set_mana(tower.get_mana() - 10)\n\telse:\n#\t\tTower is out of mana so stop shooting\n\t\t_battery_overload_is_active = false\n"
  },
  {
    "path": "src/towers/tower_behaviors/magic_mushroom.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: added storage of stacks in for Fungus Strike buff.\n# This is to display stacks. Won't affect behavior because\n# Fungus Strike buff is cosmetic only.\n\n\n# NOTE: SCALE_MIN should match the value in tower sprite\n# scene\nconst SCALE_MIN: float = 0.5\nconst SCALE_MAX: float = 1.2\n\n\nvar trance_bt: BuffType\nvar fungus_bt: BuffType\nvar grow_bt: BuffType\nvar multiboard: MultiboardValues\nvar growth_count: int = 0\nvar spell_damage_from_growth: float = 0.0\nvar fungus_strike_activated: bool = false\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 20.0)\n\n\nfunc tower_init():\n\tfungus_bt = BuffType.new(\"fungus_bt\", 3600, 0, false, self)\n\tfungus_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_dot.tres\")\n\tfungus_bt.set_buff_tooltip(tr(\"TFNM\"))\n\n\ttrance_bt = BuffType.new(\"trance_bt\", 5, 0.2, true, self)\n\tvar drol_mushroom_trance_mod: Modifier = Modifier.new()\n\tdrol_mushroom_trance_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.25, 0.01)\n\tdrol_mushroom_trance_mod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.25, 0.01)\n\ttrance_bt.set_buff_modifier(drol_mushroom_trance_mod)\n\ttrance_bt.set_buff_icon(\"res://resources/icons/generic_icons/beard.tres\")\n\ttrance_bt.set_buff_tooltip(tr(\"PFRX\"))\n\n\tgrow_bt = BuffType.new(\"grow_bt\", -1, 0, true, self)\n\tgrow_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tgrow_bt.set_buff_tooltip(tr(\"BK1C\"))\n\n\tmultiboard = MultiboardValues.new(2)\n\tvar growth_count_label: String = tr(\"E1OK\")\n\tvar spell_damage_label: String = tr(\"ANUM\")\n\tmultiboard.set_key(0, growth_count_label)\n\tmultiboard.set_key(1, spell_damage_label)\n\n\nfunc on_create(_preceding: Tower):\n\tvar grow_buff: Buff = grow_bt.apply_to_unit_permanent(tower, tower, 0)\n\tgrow_buff.set_displayed_stacks(growth_count)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif !fungus_strike_activated || !event.is_main_target():\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Fungus Strike\")\n\n\tfungus_strike_activated = false\n\n\tvar fungus_buff: Buff = target.get_buff_of_type(fungus_bt)\n\n\tvar active_stack_count: int\n\tif fungus_buff != null:\n\t\tactive_stack_count = fungus_buff.user_int\n\telse:\n\t\tactive_stack_count = 0\n\n\tvar new_stack_count: int = active_stack_count + 1\n\n\tfungus_buff = fungus_bt.apply(tower, target, 1)\n\tfungus_buff.user_int = new_stack_count\n\tfungus_buff.set_displayed_stacks(new_stack_count)\n\n\ttarget.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.10)\n\tvar fungus_strike_damage: float = event.damage * (1.0 + 0.01 * tower.get_level())\n\ttower.do_spell_damage(target, fungus_strike_damage, tower.calc_spell_crit(0.20 + 0.008 * tower.get_level(), 0))\n\tevent.damage = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar growth_count_string: String = str(growth_count)\n\tvar spell_damage_string: String = Utils.format_percent(spell_damage_from_growth, 0)\n\n\tmultiboard.set_value(0, growth_count_string)\n\tmultiboard.set_value(1, spell_damage_string)\n\n\treturn multiboard\n\n\nfunc periodic(event: Event):\n\tvar lvl: int = tower.get_level()\n\n\tif !tower.calc_chance(0.4):\n\t\tCombatLog.log_ability(tower, null, \"Growth Fail\")\n\n\t\treturn\n\n\tvar reached_max_growth: bool = growth_count >= 40\n\tif reached_max_growth:\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Growth\")\n\n\tvar spell_damage_bonus: float = 0.03 + 0.0012 * lvl\n\n\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, spell_damage_bonus)\n\tspell_damage_from_growth += spell_damage_bonus\n\n\tvar target_effect: int = Effect.create_scaled(\"res://src/effects/starfall_target.tscn\", tower.get_position_wc3(), 0, 1)\n\tEffect.set_lifetime(target_effect, 1.0)\n\n\tgrowth_count += 1\n\n\tvar grow_buff: Buff = tower.get_buff_of_type(grow_bt)\n\tgrow_buff.set_displayed_stacks(growth_count)\n\n\tvar tower_scale: float = Utils.get_scale_from_grows(SCALE_MIN, SCALE_MAX, growth_count, 40)\n\ttower.set_unit_scale(tower_scale)\n\n\tvar periodic_time: float = 20 - 0.4 * lvl\n\tevent.enable_advanced(periodic_time, false)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tfungus_strike_activated = true\n\n\ttrance_bt.apply(tower, target, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/magna_warrior.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Magnataur Warrior\"=>\"Magna Warrior\"\n\n\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {on_damage_chance = 0.10, damage_add = 0.01},\n\t\t2: {on_damage_chance = 0.11, damage_add = 0.02},\n\t\t3: {on_damage_chance = 0.12, damage_add = 0.03},\n\t\t4: {on_damage_chance = 0.13, damage_add = 0.04},\n\t\t5: {on_damage_chance = 0.14, damage_add = 0.05},\n}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 1.0, 0, false, self)\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(_stats.on_damage_chance):\n\t\treturn\n\n\tvar creep: Unit = event.get_target()\n\tvar level: float = tower.get_level()\n\n\tCombatLog.log_ability(tower, creep, \"Frozen Spears\")\n\n\tif event.is_main_target():\n\t\tevent.damage = event.damage * (1.5 + (_stats.damage_add * level))\n\t\tEffect.create_simple_at_unit(\"res://src/effects/blood_splatter.tscn\", creep)\n\t\tstun_bt.apply_only_timed(tower, creep, 0.5 + tower.get_level() * 0.01)\n\t\tvar damage_text: String = Utils.format_float(event.damage, 0)\n\t\ttower.get_player().display_small_floating_text(damage_text, tower, Color8(255, 150, 150), 0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/mana-touched_drake.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\nconst UNSTABLE_MANA_RATIO: float = 0.75\nconst UNSTABLE_MANA_RATIO_ADD: float = 0.01\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mana_burn_amount = 2, damage_per_mana_burned = 50, damage_per_mana_burned_add = 4, aura_mana_cost = 7, damage_mana_multiplier = 8.0},\n\t\t2: {mana_burn_amount = 3, damage_per_mana_burned = 75, damage_per_mana_burned_add = 6, aura_mana_cost = 14, damage_mana_multiplier = 9.5},\n\t\t3: {mana_burn_amount = 4, damage_per_mana_burned = 100, damage_per_mana_burned_add = 8, aura_mana_cost = 24, damage_mana_multiplier = 11.0},\n\t\t4: {mana_burn_amount = 5, damage_per_mana_burned = 125, damage_per_mana_burned_add = 10, aura_mana_cost = 35, damage_mana_multiplier = 12.5},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc drake_aura_manaburn(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar buffed_tower: Unit = b.get_buffed_unit()\n\tvar target: Unit = event.get_target()\n\tvar caster: Unit = b.get_caster()\n\tvar speed_and_range_adjust: float = buffed_tower.get_base_attack_speed() * 800 / buffed_tower.get_base_range()\n\tvar mana_cost_for_drake: float = _stats.aura_mana_cost * speed_and_range_adjust\n\tvar mana_burned_intended: float = _stats.mana_burn_amount * speed_and_range_adjust\n\tvar level: int = caster.get_level()\n\n\tif target.get_mana() > 0 && caster.subtract_mana(mana_cost_for_drake, false) > 0:\n\t\tvar mana_burned_actual: float = target.subtract_mana(mana_burned_intended, true)\n\n\t\tvar damage_per_mana_burned: float = _stats.damage_per_mana_burned + _stats.damage_per_mana_burned_add * level\n\t\tvar damage: float = mana_burned_actual * damage_per_mana_burned\n\t\t\n\t\tbuffed_tower.do_spell_damage(target, damage, buffed_tower.calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/spell_aima.tscn\", target)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/moebius_trefoil.tres\")\n\taura_bt.add_event_on_attack(drake_aura_manaburn)\n\taura_bt.set_buff_tooltip(tr(\"Z3II\"))\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(0.28 + 0.0048 * tower.get_level()):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Unstable Energies\")\n\n\tvar target: Unit = event.get_target()\n\tvar tower_mana: float = tower.get_mana()\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.damage_mana_multiplier * tower_mana\n\tvar mana_spent: float = tower_mana * (UNSTABLE_MANA_RATIO - UNSTABLE_MANA_RATIO_ADD * level)\n\n\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\ttower.subtract_mana(mana_spent, true)\n\tEffect.create_simple_at_unit(\"res://src/effects/death_and_decay.tscn\", target)\n"
  },
  {
    "path": "src/towers/tower_behaviors/marine.gd",
    "content": "extends TowerBehavior\n\n\nvar stim_bt: BuffType\nvar fragged_bt: BuffType\nvar shard_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {grenade_chance = 0.20, grenade_chance_add = 0.003, grenade_count = 6, grenade_damage = 1200, grenade_damage_add = 100},\n\t\t2: {grenade_chance = 0.25, grenade_chance_add = 0.004, grenade_count = 8, grenade_damage = 1800, grenade_damage_add = 150},\n\t}\n\nconst STIM_ATTACKSPEED: float = 1.5\nconst STIM_ATTACK_DMG: float = 0.5\nconst STIM_DURATION: float = 5\nconst STIM_DURATION_ADD: float = 0.08\nconst GRENADE_MOD_DMG_RECEIVED: float = 0.02\nconst GRENADE_MOD_DMG_RECEIVED_ADD: float = 0.001\nconst GRENADE_MOD_DMG_RECEIVED_MAX: float = 0.50\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tstim_bt = BuffType.new(\"stim_bt\", STIM_DURATION, STIM_DURATION_ADD, true, self)\n\tvar boekie_stim_mod: Modifier = Modifier.new()\n\tboekie_stim_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, STIM_ATTACKSPEED, 0.0)\n\tboekie_stim_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -STIM_ATTACK_DMG, 0.0)\n\tstim_bt.set_buff_modifier(boekie_stim_mod)\n\tstim_bt.set_buff_icon(\"res://resources/icons/generic_icons/meat.tres\")\n\tstim_bt.set_buff_tooltip(tr(\"SY0C\"))\n\n\tfragged_bt = BuffType.new(\"fragged_bt\", -1, 0, true, self)\n\tvar boekie_grenade_mod: Modifier = Modifier.new()\n\tboekie_grenade_mod.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, GRENADE_MOD_DMG_RECEIVED, GRENADE_MOD_DMG_RECEIVED_ADD)\n\tfragged_bt.set_buff_modifier(boekie_grenade_mod)\n\tfragged_bt.set_buff_icon(\"res://resources/icons/generic_icons/ankh.tres\")\n\tfragged_bt.set_buff_tooltip(tr(\"SMHW\"))\n\n\tshard_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 400, 500, self)\n\tshard_pt.set_event_on_expiration(boekie_shard_on_expiration)\n\tshard_pt.enable_collision(boekie_shard_on_collide, 75, TargetType.new(TargetType.CREEPS), true)\n\n\nfunc on_damage(event: Event):\n\tvar grenade_chance: float = _stats.grenade_chance + _stats.grenade_chance_add * tower.get_level()\n\n\tif !tower.calc_chance(grenade_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Frag Grenade\")\n\n\tvar projectile: Projectile = Projectile.create_from_unit_to_unit(shard_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, event.get_target(), false, true, false)\n#\tSet user_int to 1 to mark this grenade as \"main grenade\"\n\tprojectile.user_int = 1\n\n\nfunc on_autocast(_event: Event):\n\tvar level: int = tower.get_level()\n\tstim_bt.apply(tower, tower, level)\n\n\nfunc boekie_shard_on_collide(projectile: Projectile, target: Unit):\n\tvar level: int = tower.get_level()\n\tvar buff: Buff = target.get_buff_of_type(fragged_bt)\n\n\tvar grenade_damage: float = _stats.grenade_damage + _stats.grenade_damage_add * level\n\tprojectile.do_spell_damage(target, grenade_damage)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/frag_boom_spawn.tscn\", target)\n\n\tif buff != null:\n\t\tvar buff_level: int = int(min(480, buff.get_level() + 20 + level))\n\t\tfragged_bt.apply(tower, target, buff_level)\n\telse:\n\t\tfragged_bt.apply(tower, target, level)\n\n#\tNOTE: need to add 2 to displayed stacks because fragged\n#\tbuff applies 2% at buff level 0\n\tbuff = target.get_buff_of_type(fragged_bt)\n\tif buff != null:\n\t\tvar stack_count: int = buff.get_level() / 10 + 2\n\t\tbuff.set_displayed_stacks(stack_count)\n\n\nfunc boekie_shard_on_expiration(projectile: Projectile):\n\tvar CONE_WIDTH: float = 120\n\tvar num_projectiles: float = _stats.grenade_count\n\tvar angle: float = projectile.get_direction() - CONE_WIDTH / 2\n\tvar dmg_ratio: float = projectile.get_dmg_ratio()\n\tvar is_main_grenade: bool = projectile.user_int == 1\n\n\tif !is_main_grenade:\n\t\treturn\n\n\tfor i in range(0, num_projectiles):\n\t\tvar small_grenade: Projectile = Projectile.create(shard_pt, tower, dmg_ratio, tower.calc_spell_crit_no_bonus(), projectile.get_position_wc3(), angle + Globals.synced_rng.randf_range(-8, 8))\n#\t\tSet user_int to 0 to mark this grenade as \"not main\"\n#\t\tand stop recursion\n\t\tsmall_grenade.user_int = 0\n\t\tangle += CONE_WIDTH / (num_projectiles - 1)\n"
  },
  {
    "path": "src/towers/tower_behaviors/meteor_totem.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] The autocast target_self in original script is set\n# to true BUT the autocast callback does a check \"if target\n# != tower:\", so the final behavior is Meteor Totem does NOT\n# apply the Attraction buff to itself.\n# \n# I set autocast target_self to false to make it less\n# confusing.\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Changed autocast type\n# AC_TYPE_ALWAYS_BUFF->AC_TYPE_ALWAYS_IMMEDIATE because it\n# buffs multiple towers.\n\n\nvar attraction_bt: BuffType\nvar torture_bt: BuffType\nvar missile_pt: ProjectileType\n\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tattraction_bt = BuffType.new(\"attraction_bt\", 2.5, 0.05, true, self)\n\tattraction_bt.add_event_on_attack(attraction_bt_on_attack)\n\tattraction_bt.add_event_on_spell_casted(attraction_bt_on_spell_casted)\n\tattraction_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_meteor.tres\")\n\tattraction_bt.set_buff_tooltip(tr(\"TNB5\"))\n\n\ttorture_bt = BuffType.new(\"torture_bt\", 2.5, 0.05, false, self)\n\ttorture_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\ttorture_bt.add_event_on_damaged(torture_bt_on_damaged)\n\ttorture_bt.set_buff_tooltip(tr(\"SUFS\"))\n\n\tmissile_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 950, self)\n\tmissile_pt.set_event_on_interpolation_finished(missile_pt_on_hit)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\ttorture_bt.apply(tower, target, tower.get_level())\n\n\nfunc on_autocast(_event: Event):\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\tvar number: int = 4 + int(tower.get_level() / 5)\n\n\twhile true:\n\t\tvar target: Unit = it.next_random()\n\n\t\tif target == null || number == 0:\n\t\t\tbreak\n\n\t\tif target != tower:\n\t\t\tvar buff: Buff = attraction_bt.apply(tower, target, tower.get_level())\n\t\t\tbuff.user_int = 0\n\t\t\tnumber -= 1\n\n\nfunc missile_pt_on_hit(projectile: Projectile, target: Unit):\n\tvar buffed_tower: Tower = projectile.get_caster()\n\tbuffed_tower.do_spell_damage_aoe(Vector2(projectile.get_x(), projectile.get_y()), 220, projectile.user_int, buffed_tower.calc_spell_crit_no_bonus(), 0)\n\t\n\tif target != null:\n\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/doom_death.tscn\", target, Unit.BodyPart.ORIGIN)\n\t\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\n\nfunc attraction_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed: Tower = buff.get_buffed_unit()\n\n\tif buffed.calc_chance(buffed.get_base_attack_speed() * 0.35):\n\t\tvar triggered_by_attack: bool = true\n\t\trelease_meteor(buff, triggered_by_attack)\n\n\nfunc attraction_bt_on_spell_casted(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar triggered_by_attack: bool = false\n\trelease_meteor(buff, triggered_by_attack)\n\n\nfunc release_meteor(buff: Buff, triggered_by_attack: bool):\n\tvar buffed: Tower = buff.get_buffed_unit()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(buffed, TargetType.new(TargetType.CREEPS), 1000)\n\tvar result: Unit = it.next_random()\n\tvar level: int = tower.get_level()\n\n\tif result != null:\n\t\tvar projectile: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(missile_pt, buffed, 1.0, 1.0, buffed, result, 0.0, 0, 0.0, true)\n\t\t\n\t\tvar projectile_damage: int\n\t\tif triggered_by_attack:\n\t\t\tprojectile_damage = 200 + 8 * level\n\t\telse:\n\t\t\tprojectile_damage = 500 + 20 * level\n\n\t\tprojectile.user_int = projectile_damage\n\n\tbuff.remove_buff()\n\n\nfunc torture_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar damage: float = event.damage * (0.08 + 0.001 * caster.get_level())\n\tvar target: Creep = buff.get_buffed_unit()\n\n\tif event.damage >= 500 && !event.is_spell_damage():\n\t\tcaster.do_spell_damage(target, damage, 1.0)\n\t\tvar floating_text: String = Utils.format_float(damage * caster.get_prop_spell_damage_dealt(), 0)\n\t\tcaster.get_player().display_small_floating_text(floating_text, target, Color8(255, 150, 150), 20)\n"
  },
  {
    "path": "src/towers/tower_behaviors/militia_watchtower.gd",
    "content": "extends TowerBehavior\n\n\nvar axe_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {miss_chance_add = 0.01},\n\t\t2: {miss_chance_add = 0.011},\n\t\t3: {miss_chance_add = 0.011},\n\t\t4: {miss_chance_add = 0.012},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc axe_pt_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tif tower.calc_bad_chance(0.33 - _stats.miss_chance_add * tower.get_level()):\n\t\ttower.get_player().display_floating_text_x(tr(\"FLOATING_TEXT_MISS\"), tower, Color8(255, 0, 0, 255), 0.05, 0.0, 2.0)\n\telse:\n\t\ttower.do_attack_damage(target, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit_no_bonus())\n\n\nfunc tower_init():\n\taxe_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 800, self)\n\taxe_pt.set_event_on_interpolation_finished(axe_pt_hit)\n\n\nfunc on_attack(event: Event):\n\tvar attacks: int = 2\n\tvar add: bool = false\n\tvar maintarget: Unit = event.get_target()\n\tvar target: Unit\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), maintarget, 450)\n\tvar sidearc: float = 0.20\n\tvar it_destroyed: bool = false\n\n\tif tower.get_level() >= 15:\n\t\tattacks = attacks + 1\n\n\tif tower.get_level() >= 25:\n\t\tattacks = attacks + 1\n\n\twhile true:\n#\t\tExit when all attacks are fired\n\t\tif attacks == 0:\n\t\t\treturn\n\n#\t\tIf the Iterate is not destroyed, get the next target\n\t\tif !it_destroyed:\n\t\t\ttarget = it.next()\n\n#\t\t\tIf there are no more targets\n\t\t\tif target == null:\n#\t\t\t\tIterate is destroyed (auto destroy)\n\t\t\t\tit_destroyed = true\n#\t\t\t\ttarget is the maintarget now\n\t\t\t\ttarget = maintarget\n\n#\t\tIf there are no more units, shoot at the maintarget\n#\t\t(itDestroyed). If there are units then don't shoot\n#\t\tat the maintarget\n\t\tif it_destroyed || target != maintarget:\n\t\t\tProjectile.create_bezier_interpolation_from_unit_to_unit(axe_pt, tower, 0, 0, tower, target, 0, sidearc, 0, true).set_projectile_scale(0.40)\n\t\t\tattacks = attacks - 1\n\t\t\tsidearc = -sidearc\n\n\t\t\tif add:\n\t\t\t\tsidearc = sidearc + 0.020\n\n\t\t\tadd = !add\n\n\nfunc on_damage(event: Event):\n\tif tower.calc_bad_chance(0.33 - _stats.miss_chance_add * tower.get_level()):\n\t\tevent.damage = 0\n\t\ttower.get_player().display_floating_text_x(tr(\"FLOATING_TEXT_MISS\"), tower, Color8(255, 0, 0, 255), 0.05, 0.0, 2.0)\n\n\nfunc on_create(_preceding_tower: Tower):\n# \tSave the family member (1 = first member)\n\ttower.user_int = tower.get_tier()\n# \tUsed to save the buff (double linked list)\n\ttower.user_int2 = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/miner.gd",
    "content": "extends TowerBehavior\n\n\n# [ORIGINAL_GAME_BUG] Fixed Goldrush duration for tier\n# 3 tower. +1sec/lvl => +0.1sec/lvl - how it is in ability\n# description.\n\n\nvar goldrush_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {attack_speed_base = 0, attack_speed_divisor = 5, goldrush_gold = 1.0, goldrush_gold_add = 0.04, excavation_gold = 7.5, excavation_gold_add = 0.3},\n\t\t2: {attack_speed_base = 20, attack_speed_divisor = 3, goldrush_gold = 2.8, goldrush_gold_add = 0.1, excavation_gold = 21, excavation_gold_add = 0.8},\n\t\t3: {attack_speed_base = 40, attack_speed_divisor = 2, goldrush_gold = 5.4, goldrush_gold_add = 0.22, excavation_gold = 40, excavation_gold_add = 1.6},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 20)\n\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tgoldrush_bt = BuffType.new(\"goldrush_bt\", 5, 0.1, true, self)\n\tm.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.2, 0.01)\n\tgoldrush_bt.set_buff_icon(\"res://resources/icons/generic_icons/gold_bar.tres\")\n\tgoldrush_bt.set_buff_modifier(m)\n\tgoldrush_bt.set_buff_tooltip(tr(\"AXB0\"))\n\n\tmultiboard = MultiboardValues.new(2)\n\tvar gold_gained_label: String = tr(\"EX70\")\n\tvar goldrush_bonus_label: String = tr(\"RZJV\")\n\tmultiboard.set_key(0, gold_gained_label)\n\tmultiboard.set_key(1, goldrush_bonus_label)\n\n\nfunc on_attack(_event: Event):\n\tif !tower.calc_chance(0.2):\n\t\treturn\n\n\tif tower.get_buff_of_type(goldrush_bt) == null:\n\t\tCombatLog.log_ability(tower, null, \"Goldrush\")\n\n\t\tvar gold_amount: float = tower.get_player().get_gold()\n\t\tgoldrush_bt.apply_custom_timed(tower, tower, int(_stats.attack_speed_base + pow(gold_amount,0.5) / _stats.attack_speed_divisor), 5 + tower.get_level() * 0.1)\n\n\nfunc on_damage(event: Event):\n\tvar gold_bonus = _stats.goldrush_gold + tower.get_level() * _stats.goldrush_gold_add\n\n\tif event.is_main_target() && tower.get_buff_of_type(goldrush_bt) != null:\n\t\ttower.user_real = tower.user_real + gold_bonus\n\t\ttower.get_player().give_gold(gold_bonus, tower, false, true)\n\n\nfunc on_create(preceding: Tower):\n\tif preceding != null && preceding.get_family() == tower.get_family():\n\t\ttower.user_real = preceding.user_real\n\telse:\n\t\ttower.user_real = 0.0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar gold_amount: float = tower.get_player().get_gold()\n\tvar excavation_value: int = 20 + int(pow(gold_amount, 0.5) / 5)\n\tvar gold_gained_text: String = Utils.format_float(tower.user_real, 2)\n\tvar goldrush_bonus_text: String = \"%d%%\" % excavation_value\n\n\tmultiboard.set_value(0, gold_gained_text)\n\tmultiboard.set_value(1, goldrush_bonus_text)\n\n\treturn multiboard\n\n\nfunc periodic(_event: Event):\n\tvar gold_bonus: float = _stats.excavation_gold + tower.get_level() * _stats.excavation_gold_add\n\n\tEffect.create_scaled(\"res://src/effects/ancient_protector_missile.tscn\", tower.get_position_wc3(), 0, 2)\n\n\tif tower.calc_chance(0.25):\n\t\tCombatLog.log_ability(tower, null, \"Excavation\")\n\n\t\ttower.user_real = tower.user_real + gold_bonus\n\t\ttower.get_player().give_gold(gold_bonus, tower, false, true)\n\telse:\n\t\tCombatLog.log_ability(tower, null, \"Excavation Fail\")\n"
  },
  {
    "path": "src/towers/tower_behaviors/minor_magic_ruin.gd",
    "content": "extends TowerBehavior\n\n\nvar illuminate_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {exp_bonus = 0.05, exp_bonus_add = 0.002},\n\t\t2: {exp_bonus = 0.10, exp_bonus_add = 0.004},\n\t\t3: {exp_bonus = 0.15, exp_bonus_add = 0.006},\n\t\t4: {exp_bonus = 0.20, exp_bonus_add = 0.008},\n\t\t5: {exp_bonus = 0.25, exp_bonus_add = 0.010},\n\t\t6: {exp_bonus = 0.30, exp_bonus_add = 0.012},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar astral_mod: Modifier = Modifier.new()\n\tilluminate_bt = BuffType.new(\"illuminate_bt\", 5, 0, false, self)\n\tastral_mod.add_modification(ModificationType.enm.MOD_EXP_GRANTED, _stats.exp_bonus, _stats.exp_bonus_add)\n\tilluminate_bt.set_buff_modifier(astral_mod)\n\tilluminate_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\t\n\tilluminate_bt.set_buff_tooltip(tr(\"ODJT\"))\n\n\nfunc on_damage(event: Event):\n\tilluminate_bt.apply_custom_timed(tower, event.get_target(), tower.get_level(), 5 + tower.get_level() * 0.2)\n"
  },
  {
    "path": "src/towers/tower_behaviors/mister_fireflies.gd",
    "content": "extends TowerBehavior\n\n# NOTE: changed script to hide attack projectile and deal 0\n# damage.\n\n# NOTE: removed update of moth element triggered by \"unit\n# comes in range\". Not necessary because can update this in\n# periodic callback.\n\n# NOTE: [ORIGINAL_GAME_BUG] Added moth periodic damage.\n# Original script is missing it.\n\n# NOTE: removed weird code for moth spell crit. Not needed\n# because moth damage is dealt via tower.\n\n\nvar TARGET_TYPE_FOR_RARE_BREED: TargetType = TargetType.new(TargetType.TOWERS + TargetType.ELEMENT_DARKNESS + TargetType.ELEMENT_FIRE + TargetType.ELEMENT_STORM)\n\n\n# var example_bt: BuffType\nvar moth_pt: ProjectileType\n# var multiboard: MultiboardValues\nvar moth_list: Array[Projectile] = []\nvar element_for_moths: Element.enm = Element.enm.DARKNESS\nvar timer_to_return_to_tower: float = 0\nvar moth_target: Unit = null\n\n\nconst RARE_BREED_RADIUS: float = 110\nconst MOTH_DAMAGE_RADIUS: float = 375\nconst MOTH_DAMAGE_PERIOD: float = 0.5\nconst MANA_BURN_ADD: float = 0.08\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {moth_damage = 50, moth_damage_if_darkness = 75, moth_count = 6, mana_burn = 2, mana_burn_bonus_if_fire = 2},\n\t\t2: {moth_damage = 80, moth_damage_if_darkness = 120, moth_count = 6, mana_burn = 3, mana_burn_bonus_if_fire = 3},\n\t\t3: {moth_damage = 110, moth_damage_if_darkness = 165, moth_count = 7, mana_burn = 4, mana_burn_bonus_if_fire = 4},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\n\tmoth_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 275, self)\n\tmoth_pt.set_event_on_interpolation_finished(moth_pt_on_interpolation_finished)\n\tmoth_pt.enable_periodic(moth_pt_periodic, MOTH_DAMAGE_PERIOD)\n\n\nfunc on_create(_preceding_tower: Tower):\n\tfor i in range(0, _stats.moth_count):\n\t\tvar moth_pos: Vector3 = Vector3(\n\t\t\ttower.get_x() + Globals.synced_rng.randf_range(-100, 100),\n\t\t\ttower.get_y() + Globals.synced_rng.randf_range(-100, 100),\n\t\t\t175,\n\t\t\t)\n\t\tvar p: Projectile = Projectile.create_bezier_interpolation_from_unit_to_point(moth_pt, tower, 1.0, 1.0, tower, moth_pos, 0.4, 0.4, 0.4)\n\n\t\tmoth_list.append(p)\n\n\tupdate_element_for_moths()\n\n\nfunc on_destruct():\n\tfor moth in moth_list:\n\t\tmoth.remove_from_game()\n\n\n# Send moths at current attack target\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tmoth_target = target\n\ttimer_to_return_to_tower = 3.5\n\n\n# NOTE: tower doesn't deal damage with normal attacks - only\n# with moths\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\nfunc periodic(_event: Event):\n#\tMoths start to attempt returning to tower after a delay\n\tif timer_to_return_to_tower > 0:\n\t\ttimer_to_return_to_tower -= 1\n\telse:\n\t\tmoth_target = tower\n\n\tupdate_element_for_moths()\n\n\nfunc moth_pt_on_interpolation_finished(p: Projectile, _hit_target: Unit):\n\tvar spread: float = 280\n\n#\tDivides the difference between p and target; higher =\n#\tslower approach, below 0 = jump to opposite side\n\tvar divider: float = 4\n\n\tvar move_target: Unit\n\tif Utils.unit_is_valid(moth_target):\n\t\tmove_target = moth_target\n\telse:\n\t\tmove_target = tower\n\n\tvar dx: float = move_target.get_x() - p.get_x()\n\tvar dy: float = move_target.get_y() - p.get_y()\n\n\tvar speed: float = 150\n\n\tif move_target is Creep:\n\t\tdivider = 2\n\n\t\tvar max_diff: float = max(dx, dy)\n\n\t\tif max_diff > 1200:\n\t\t\tspread = 150\n\t\t\tspeed = 300\n\t\telif max_diff > 400:\n\t\t\tspread = 175\n\t\t\tspeed = 350\n\t\telse:\n\t\t\tspread = 200\n\t\t\tspeed = 400\n\t\t\tdivider = 0.85\n\t\n\tif element_for_moths == Element.enm.STORM:\n\t\tspeed += 450\n\t\tspread = 150\n\t\tdivider = 1\n\n\tp.set_speed(speed)\n\n\tvar target_pos: Vector3 = Vector3(\n\t\tp.get_x() + Globals.synced_rng.randf_range(-spread, spread) + Utils.divide_safe(dx, divider),\n\t\tp.get_y() + Globals.synced_rng.randf_range(-spread, spread) + Utils.divide_safe(dy, divider),\n\t\tp.get_z() + Globals.synced_rng.randf_range(-min(35, p.get_z() - 35), 65) - Utils.divide_safe(p.get_z() / 10, divider)\n\t\t)\n\n\tvar angle: float = rad_to_deg(atan2(target_pos.y - p.get_y(), target_pos.x - p.get_x()))\n\tvar angle_diff: float = angle - p.get_direction()\n\n\tif angle_diff > 180:\n\t\tangle_diff -= 360\n\telif angle_diff < -180:\n\t\tangle_diff += 360\n\n\tvar steep: float = 0.2\n\tif angle_diff > 120 || angle_diff < -120:\n\t\tsteep = 1.0\n\n\tp.start_bezier_interpolation_to_point(target_pos, 0.1, Globals.synced_rng.randf_range(-1, 1), steep)\n\n\tp.avert_destruction()\n\n\n# NOTE: partially FireFly_Damage() in original script\nfunc moth_pt_periodic(projectile: Projectile):\n\tvar moth_pos: Vector2 = projectile.get_position_wc3_2d()\n\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), moth_pos, MOTH_DAMAGE_RADIUS)\n\n\tvar target: Unit = it.next_random()\n\n\tif target == null:\n\t\treturn\n\n\tvar mana_burn_amount: float = _stats.mana_burn + MANA_BURN_ADD * tower.get_level()\n\tif element_for_moths == Element.enm.FIRE:\n\t\tmana_burn_amount += _stats.mana_burn_bonus_if_fire\n\n\tvar moth_damage: float\n\tif element_for_moths == Element.enm.DARKNESS:\n\t\tmoth_damage = _stats.moth_damage_if_darkness\n\telse:\n\t\tmoth_damage = _stats.moth_damage\n\n\ttower.do_spell_damage(target, moth_damage, tower.calc_spell_crit_no_bonus())\n\ttarget.subtract_mana(mana_burn_amount, false)\n\n\nfunc update_element_for_moths():\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TARGET_TYPE_FOR_RARE_BREED, RARE_BREED_RADIUS)\n\n\tvar gold_cost_map: Dictionary = {}\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar element: Element.enm = next.get_element()\n\t\tvar this_gold_cost: int = next.get_gold_cost()\n\n\t\tif !gold_cost_map.has(element):\n\t\t\tgold_cost_map[element] = 0\n\n\t\tgold_cost_map[element] += this_gold_cost\n\n\tvar winning_element: Element.enm = Element.enm.DARKNESS\n\tvar winning_sum: int = gold_cost_map.get(Element.enm.DARKNESS, 0)\n\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_element_keys: Array = gold_cost_map.keys()\n\tsorted_element_keys.sort()\n\tfor element in sorted_element_keys:\n\t\tvar this_sum: int = gold_cost_map[element]\n\n\t\tif this_sum > winning_sum:\n\t\t\twinning_element = element\n\t\t\twinning_sum = this_sum\n\n\telement_for_moths = winning_element\n\n\tvar element_color: Color = Element.get_color(element_for_moths)\n\n\tfor moth in moth_list:\n\t\tmoth.set_color(element_color)\n"
  },
  {
    "path": "src/towers/tower_behaviors/monolith_of_chaos.gd",
    "content": "extends TowerBehavior\n\n\nvar chaos_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 750, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\tchaos_bt = BuffType.new(\"chaos_bt\", 3.0, 0.1, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, -1.0, 0.50)\n\tchaos_bt.set_buff_modifier(mod)\n\tchaos_bt.set_buff_icon(\"res://resources/icons/generic_icons/mine_explosion.tres\")\n\tchaos_bt.set_buff_tooltip(tr(\"HEC8\"))\n\n\nfunc on_unit_in_range(event: Event, ):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar chaos_chance: float = 0.45 + 0.004 * level\n\tvar buff_duration: float = 3.0 + 0.1 * level\n\n\tif !tower.calc_chance(chaos_chance):\n\t\treturn\n\n\tvar creep_size: CreepSize.enm = creep.get_size()\n\n\tvar buff_level: int\n\tif creep_size < CreepSize.enm.BOSS:\n\t\tbuff_level = 0\n\telse:\n\t\tbuff_level = 1\n\n\tchaos_bt.apply_custom_timed(tower, creep, buff_level, buff_duration)\n"
  },
  {
    "path": "src/towers/tower_behaviors/morphling.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: fixed description of \"Morphling Strike\". It now\n# explicitly states that projectiles will be launched only\n# if tower has at least 25 stacks of one of the Morph buffs.\n\n\nvar might_bt: BuffType\nvar swiftness_bt: BuffType\nvar adapt_bt: BuffType\nvar dot_bt: BuffType\nvar swift_strike_bt: BuffType\nvar damage_pt: ProjectileType\nvar speed_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar evolve_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tmight_bt = BuffType.new(\"might_bt\", -1, 0, true, self)\n\tvar might_bt_mod: Modifier = Modifier.new()\n\tmight_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.0, 0.02)\n\tmight_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, -0.02)\n\tmight_bt.set_buff_modifier(might_bt_mod)\n\tmight_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tmight_bt.set_buff_tooltip(tr(\"MUTT\"))\n\n\tswiftness_bt = BuffType.new(\"swiftness_bt\", -1, 0, true, self)\n\tvar swiftness_bt_mod: Modifier = Modifier.new()\n\tswiftness_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.0, -0.02)\n\tswiftness_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.02)\n\tswiftness_bt.set_buff_modifier(swiftness_bt_mod)\n\tswiftness_bt.set_buff_icon(\"res://resources/icons/generic_icons/sprint.tres\")\n\tswiftness_bt.set_buff_tooltip(tr(\"STJ0\"))\n\n\tadapt_bt = BuffType.new(\"adapt_bt\", -1, 0, true, self)\n\tadapt_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\tadapt_bt.set_buff_tooltip(tr(\"K488\"))\n\n\tdot_bt = BuffType.new(\"dot_bt\", 5, 0, false, self)\n\tdot_bt.set_buff_icon(\"res://resources/icons/generic_icons/triple_scratches.tres\")\n\tdot_bt.add_periodic_event(dot_bt_periodic, 1.0)\n\tdot_bt.set_buff_tooltip(tr(\"LWRJ\"))\n\n\tswift_strike_bt = BuffType.new(\"swift_strike_bt\", 8, 0.1, false, self)\n\tvar swift_strike_bt_mod: Modifier = Modifier.new()\n\tswift_strike_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.2, -0.004)\n\tswift_strike_bt_mod.add_modification(ModificationType.enm.MOD_DMG_FROM_NATURE, 0.15, 0.002)\n\tswift_strike_bt.set_buff_modifier(swift_strike_bt_mod)\n\tswift_strike_bt.set_buff_icon(\"res://resources/icons/generic_icons/amber_mosquito.tres\")\n\tswift_strike_bt.set_buff_tooltip(tr(\"AZW0\"))\n\n\tdamage_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 800, self)\n\tdamage_pt.enable_homing(damage_pt_on_hit, 0)\n\n\tspeed_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 800, self)\n\tspeed_pt.enable_homing(speed_pt_on_hit, 0)\n\n\tmultiboard = MultiboardValues.new(2)\n\tvar evolve_label: String = tr(\"R92N\")\n\tvar morph_level_label: String = tr(\"V3M2\")\n\tmultiboard.set_key(0, evolve_label)\n\tmultiboard.set_key(1, morph_level_label)\n\n\nfunc on_attack(_event: Event):\n\tvar damage_buff: Buff = tower.get_buff_of_type(might_bt)\n\tvar speed_buff: Buff = tower.get_buff_of_type(swiftness_bt)\n\tvar adapt_buff: Buff = tower.get_buff_of_type(adapt_bt)\n\n\tif adapt_buff == null:\n\t\tif damage_buff != null && damage_buff.get_level() < 50:\n\t\t\tvar might_buff: Buff = might_bt.apply(tower, tower, damage_buff.get_level() + 1)\n\t\t\tmight_buff.set_displayed_stacks(might_buff.get_level())\n\t\telif speed_buff != null && speed_buff.get_level() < 50:\n\t\t\tvar swiftness_buff: Buff = swiftness_bt.apply(tower, tower, speed_buff.get_level() + 1)\n\t\t\tswiftness_buff.set_displayed_stacks(swiftness_buff.get_level())\n\n\nfunc on_damage(event: Event):\n\tvar morphling_strike_chance: float = 0.2 + 0.006 * tower.get_level()\n\n\tif !tower.calc_chance(morphling_strike_chance):\n\t\treturn\n\n\tvar pt: ProjectileType = null\n\tvar projectile_scale: float = 1.0\n\n\tvar damage_buff: Buff = tower.get_buff_of_type(might_bt)\n\tvar speed_buff: Buff = tower.get_buff_of_type(swiftness_bt)\n\n\tif damage_buff != null && damage_buff.get_level() >= 25:\n\t\tpt = damage_pt\n\t\tprojectile_scale = 1.6\n\n\t\tif evolve_count < 500:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.002)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.001)\n\t\t\tevolve_count += 1\n\telif speed_buff != null && speed_buff.get_level() >= 25:\n\t\tpt = speed_pt\n\n\t\tif evolve_count < 500:\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.002)\n\t\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.001)\n\t\t\tevolve_count += 1\n\n\tif pt != null:\n\t\tCombatLog.log_ability(tower, event.get_target(), \"Morphling Strike\")\n\t\t\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 900)\n\n\t\tvar count: int = 0\n\n\t\twhile true:\n\t\t\tvar next: Unit = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tcount += 1\n\n\t\t\tif count == 4:\n\t\t\t\tbreak\n\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(pt, tower, 1, 1, tower, next, true, false, false)\n\t\t\tp.set_projectile_scale(projectile_scale)\n\n\nfunc on_autocast_might(_event: Event):\n\tvar speed_buff: Buff = tower.get_buff_of_type(swiftness_bt)\n\tvar damage_buff: Buff = tower.get_buff_of_type(might_bt)\n\n\tif damage_buff == null:\n\t\tif speed_buff != null:\n\t\t\tspeed_buff.remove_buff()\n\n\t\tmight_bt.apply(tower, tower, 0)\n\n\nfunc on_autocast_swiftness(_event: Event):\n\tvar speed_buff: Buff = tower.get_buff_of_type(swiftness_bt)\n\tvar damage_buff: Buff = tower.get_buff_of_type(might_bt)\n\n\tif speed_buff == null:\n\t\tif damage_buff != null:\n\t\t\tdamage_buff.remove_buff()\n\n\t\tswiftness_bt.apply(tower, tower, 0)\n\n\nfunc on_autocast_adapt(_event: Event):\n\tvar adapt_buff: Buff = tower.get_buff_of_type(adapt_bt)\n\n\tif adapt_buff == null:\n\t\tadapt_bt.apply(tower, tower, 0)\n\telif adapt_buff != null:\n\t\tadapt_buff.remove_buff()\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar damage_buff: Buff = tower.get_buff_of_type(might_bt)\n\tvar speed_buff: Buff = tower.get_buff_of_type(swiftness_bt)\n\n\tmultiboard.set_value(0, str(evolve_count))\n\t\n\tvar damage_buff_level: int = 0\n\tif damage_buff != null:\n\t\tdamage_buff_level = damage_buff.get_level()\n\t\tmultiboard.set_value(1, str(damage_buff_level))\n\n\tvar speed_buff_level: int = 0\n\tif speed_buff != null:\n\t\tspeed_buff_level = speed_buff.get_level()\n\t\tmultiboard.set_value(1, str(speed_buff_level))\n\n\treturn multiboard\n\n\n# NOTE: \"morphSpeedHit()\" in original script\nfunc speed_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = 2000 + 60 * level\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\tswift_strike_bt.apply(tower, target, level)\n\n\n# NOTE: \"morphDamageHit()\" in original script\nfunc damage_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = 2000 + 60 * level\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\tdot_bt.apply(tower, target, level)\n\n\n# NOTE: \"dot()\" in original script\nfunc dot_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar level: int = tower.get_level()\n\tvar damage: float = tower.get_current_attack_damage_with_bonus() * (0.25 + 0.008 * level)\n\ttower.do_spell_damage(buffed_unit, damage, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/mossy_acid_sprayer.gd",
    "content": "extends TowerBehavior\n\n\nvar acid_bt: BuffType\n\n# NOTE: values here are pre-multiplied by 1000, so 600 = 0.6\n# as final value. That's how it is in original script and we\n# stick to original to avoid introducting bugs.\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {armor_base = 0.6, armor_add = 0.024},\n\t\t2: {armor_base = 1.2, armor_add = 0.048},\n\t\t3: {armor_base = 2.4, armor_add = 0.096},\n\t\t4: {armor_base = 4.8, armor_add = 0.192},\n\t\t5: {armor_base = 9.6, armor_add = 0.384},\n\t}\n\n\nconst DEBUFF_DURATION: float = 3.0\nconst DEBUFF_DURATION_ADD: float = 0.12\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_ARMOR, -_stats.armor_base, -_stats.armor_add)\n\tacid_bt = BuffType.new(\"acid_bt\", DEBUFF_DURATION, DEBUFF_DURATION_ADD, false, self)\n\tacid_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tacid_bt.set_buff_modifier(m)\n\n\tacid_bt.set_buff_tooltip(tr(\"Y1IG\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tacid_bt.apply(tower, target, level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/mud_golem.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar slow_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", 0.5, 0.012, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.60, 0.0)\n\tslow_bt.set_buff_modifier(mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"INTD\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/cog.tres\")\n\taura_bt.add_event_on_attack(aura_bt_on_attack)\n\taura_bt.set_buff_tooltip(tr(\"GYWF\"))\n\n\nfunc on_damage(_event: Event):\n\tCombatLog.log_ability(tower, null, \"Ground Smash\")\n\n\tsmash()\n\n\nfunc aura_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar ground_smash_chance: float = (0.03 + 0.0004 * tower.get_level()) * buffed_tower.get_base_attack_speed()\n\n\tif !buffed_tower.calc_chance(ground_smash_chance):\n\t\treturn\n\n\tCombatLog.log_ability(buffed_tower, null, \"Ground Smash\")\n\n\tsmash()\n\n\nfunc smash():\n\tvar level: int = tower.get_level()\n\tvar smash_damage: float = (4300 + 230 * level) * tower.get_prop_spell_damage_dealt()\n\n\tvar smash_range: float\n\tif level == 25:\n\t\tsmash_range = 800\n\telse:\n\t\tsmash_range = 750\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), smash_range)\n\t\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next.get_size() == CreepSize.enm.AIR:\n\t\t\tcontinue\n\n#\t\tNOTE: using do_attack_damage() with args based on\n#\t\tspell damage is not a typo. Written this way in\n#\t\toriginal script on purpose.\n\t\tslow_bt.apply(tower, next, level)\n\t\ttower.do_attack_damage(next, smash_damage, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/nature_sprites.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] in original game there's a\n# discrepancy between value in description vs script. In\n# description, item chance level bonus = 0.14%. In script it\n# is 0.16%.\n\n\nconst SECONDARY_EFFECT_CHANCE: float = 0.25\nconst AUTOCAST_RANGE: float = 500\nconst GIFT_DURATION: float = 5\n\nconst EXP_RECEIVED: float = 0.28\nconst EXP_RECEIVED_ADD: float = 0.008\nconst SPELL_DAMAGE_DEALT: float = 0.16\nconst SPELL_DAMAGE_DEALT_ADD: float = 0.004\nconst ATK_CRIT_CHANCE: float = 0.04\nconst ATK_CRIT_CHANCE_ADD: float = 0.001\nconst DAMAGE_ADD_PERC: float = 0.16\nconst DAMAGE_ADD_PERC_ADD: float = 0.004\nconst BUFF_DURATION: float = 0.2\nconst BUFF_DURATION_ADD: float = 0.006\nconst ATTACKSPEED: float = 0.08\nconst ATTACKSPEED_ADD: float = 0.002\nconst ITEM_CHANCE: float = 0.06\nconst ITEM_CHANCE_ADD: float = 0.0014\n\n\nconst ELEMENT_TO_MOD_MAP: Dictionary = {\n\tElement.enm.ASTRAL: ModificationType.enm.MOD_EXP_RECEIVED,\n\tElement.enm.DARKNESS: ModificationType.enm.MOD_SPELL_DAMAGE_DEALT,\n\tElement.enm.NATURE: ModificationType.enm.MOD_ATK_CRIT_CHANCE,\n\tElement.enm.FIRE: ModificationType.enm.MOD_DAMAGE_ADD_PERC,\n\tElement.enm.ICE: ModificationType.enm.MOD_BUFF_DURATION,\n\tElement.enm.STORM: ModificationType.enm.MOD_ATTACKSPEED,\n\tElement.enm.IRON: ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL,\n}\n\n\nvar gift_bt: BuffType\nvar sprite_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {buff_strength = 1.0, projectile_scale = 0.75},\n\t\t2: {buff_strength = 1.5, projectile_scale = 1.5},\n\t\t3: {buff_strength = 2.0, projectile_scale = 1.5},\n\t}\n\n\nfunc gift_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Tower = buff.get_buffed_unit()\n\tvar tower_element: Element.enm = target.get_element()\n\n#\tEnsure caster is still alive.\n\tif tower == null:\n\t\treturn\n\n\tvar main_mod_type: ModificationType.enm = ELEMENT_TO_MOD_MAP[tower_element]\n\tvar main_mod_value: float = get_mod_value_for_stat(main_mod_type)\n\n\ttarget.modify_property(main_mod_type, main_mod_value)\n\n#\tSave values in buff, to be used later when undoing\n\tbuff.user_int = main_mod_type\n\tbuff.user_real = main_mod_value\n\n\tvar secondary_effect_happened: bool = true\n\n\tif secondary_effect_happened:\n#\t\tNOTE: for secondary effect, do not include IRON in\n#\t\tthe random list so that IRON effect can be used as a\n#\t\tfallback in case random element is same as tower\n#\t\telement.\n\t\tvar element_list: Array[Element.enm] = Element.get_list()\n\t\telement_list.erase(Element.enm.IRON)\n\n\t\tvar random_element: Element.enm = Utils.pick_random(Globals.synced_rng, element_list)\n\t\tif random_element == tower_element:\n\t\t\trandom_element = Element.enm.IRON\n\n\t\tvar secondary_mod_type: ModificationType.enm = ELEMENT_TO_MOD_MAP[random_element]\n\t\tvar secondary_mod_value: float = get_mod_value_for_stat(secondary_mod_type)\n\n\t\ttarget.modify_property(secondary_mod_type, secondary_mod_value)\n\n#\t\tSave values in buff, to be used later when undoing\n\t\tbuff.user_int2 = secondary_mod_type\n\t\tbuff.user_real2 = secondary_mod_value\n\telse:\n\t\tbuff.user_int2 = 0\n\t\tbuff.user_real2 = 0\n\n\tvar effect_id: int = Effect.create_simple_at_unit(\"res://src/effects/keeper_grove_missile.tscn\", target, Unit.BodyPart.OVERHEAD)\n\tEffect.set_auto_destroy_enabled(effect_id, false)\n\tif secondary_effect_happened:\n\t\tEffect.set_color(effect_id, Color8(255, 180, 180))\n\t\tEffect.set_scale(effect_id, 1.5)\n\tbuff.user_int3 = effect_id\n\n\nfunc gift_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Tower = buff.get_buffed_unit()\n\n\tvar main_mod_type: ModificationType.enm = buff.user_int as ModificationType.enm\n\tvar main_mod_value: float = buff.user_real\n\tvar secondary_mod_type: ModificationType.enm = buff.user_int2 as ModificationType.enm\n\tvar secondary_mod_value: float = buff.user_real2\n\n\ttarget.modify_property(main_mod_type, -main_mod_value)\n\n\tif secondary_mod_type != 0:\n\t\ttarget.modify_property(secondary_mod_type, -secondary_mod_value)\n\n\tvar effect_id: int = buff.user_int3\n\tif effect_id != 0:\n\t\tEffect.destroy_effect(effect_id)\n\n\nfunc sprite_hit(_projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tgift_bt.apply(tower, target, tower.get_level())\n\n\nfunc tower_init():\n\tgift_bt = BuffType.new(\"gift_bt\", GIFT_DURATION, 0, true, self)\n\tgift_bt.set_buff_icon(\"res://resources/icons/generic_icons/holy_grail.tres\")\n\tgift_bt.add_event_on_create(gift_bt_on_create)\n\tgift_bt.add_event_on_cleanup(gift_bt_on_cleanup)\n\tgift_bt.set_buff_tooltip(tr(\"I7WD\"))\n\n\tsprite_pt = ProjectileType.create(\"res://src/effects/keeper_grove_missile.tscn\", 4, 400, self)\n\tsprite_pt.enable_homing(sprite_hit, 0)\n\n\nfunc on_autocast(event: Event):\n\tvar p: Projectile = Projectile.create_from_unit_to_unit(sprite_pt, tower, 0, 0, tower, event.get_target(), true, false, false)\n\tp.set_projectile_scale(_stats.projectile_scale)\n\tp.set_color(Color8(50, 255, 50, 255))\n\n\nfunc get_mod_value_for_stat(mod_type: ModificationType.enm) -> float:\n\tvar value: float\n\n\tvar level: int = tower.get_level()\n\n\tmatch mod_type:\n\t\tModificationType.enm.MOD_EXP_RECEIVED: value = EXP_RECEIVED + level * EXP_RECEIVED_ADD\n\t\tModificationType.enm.MOD_ITEM_CHANCE_ON_KILL: value = ITEM_CHANCE + level * ITEM_CHANCE_ADD\n\t\tModificationType.enm.MOD_SPELL_DAMAGE_DEALT: value = SPELL_DAMAGE_DEALT + level * SPELL_DAMAGE_DEALT_ADD\n\t\tModificationType.enm.MOD_ATK_CRIT_CHANCE: value = ATK_CRIT_CHANCE + level * ATK_CRIT_CHANCE_ADD\n\t\tModificationType.enm.MOD_DAMAGE_ADD_PERC: value = DAMAGE_ADD_PERC + level * DAMAGE_ADD_PERC_ADD\n\t\tModificationType.enm.MOD_BUFF_DURATION: value = BUFF_DURATION + level * BUFF_DURATION_ADD\n\t\tModificationType.enm.MOD_ATTACKSPEED: value = ATTACKSPEED + level * ATTACKSPEED_ADD\n\t\t_:\n\t\t\tpush_error(\"Unknown mod_type used in Nature's Sprite script\")\n\t\t\tvalue = 0.0\n\n\tvalue *= _stats.buff_strength\n\n\treturn value\n"
  },
  {
    "path": "src/towers/tower_behaviors/necromantic_altar.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: simplified original script because it didn't use\n# Iterate.next_random().\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 200, damage_add = 12},\n\t\t2: {damage = 400, damage_add = 24},\n\t\t3: {damage = 800, damage_add = 48},\n\t\t4: {damage = 1700, damage_add = 100},\n\t}\n\n\nfunc on_autocast(_event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar iterate: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 875)\n\tvar next: Unit\n\tvar loop_counter: int = 3\n\tvar counter: int = 3\n\n\twhile true:\n\t\tloop_counter = loop_counter - 1\n\t\tnext = iterate.next_random()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\ttower.do_spell_damage(next, (_stats.damage + lvl * _stats.damage_add) * counter, tower.calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/spell_aire.tscn\", next)\n\t\tcounter = counter + 1\n\n\t\tif loop_counter == 0:\n\t\t\tbreak\n"
  },
  {
    "path": "src/towers/tower_behaviors/nortrom_the_silencer.gd",
    "content": "extends TowerBehavior\n\n\nvar silence_bt: BuffType\nvar aura_bt: BuffType\nvar glaive_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 7.0)\n\n\nfunc tower_init():\n\tsilence_bt = CbSilence.new(\"silence_bt\", 0, 0, false, self)\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/aries.tres\")\n\taura_bt.add_event_on_attack(aura_bt_on_attack)\n\taura_bt.set_buff_tooltip(tr(\"E4O4\"))\n\n\tglaive_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\tglaive_pt.set_event_on_interpolation_finished(glaive_pt_on_hit)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif tower.get_mana() < 40:\n\t\treturn\n\n\ttower.subtract_mana(40, false)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 800)\n\n\tvar lowest_health_creep: Unit = target\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tif next.get_health() < target.get_health():\n\t\t\tlowest_health_creep = next\n\n\tvar p: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(glaive_pt, tower, 1, 1, tower, lowest_health_creep, 0, true)\n\tp.set_projectile_scale(0.5)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar silenced_damage_multiplier: float = get_silenced_damage_multiplier()\n\n\tif target.is_silenced():\n\t\tevent.damage *= silenced_damage_multiplier\n\t\tEffect.create_scaled(\"res://src/effects/spell_breaker_target.tscn\", Vector3(target.get_x(), target.get_x(), 30), 0, 1)\n\n\nfunc periodic(_event: Event):\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 800)\n\tvar duration: float = 2.0 + 0.04 * tower.get_level()\n\n\tCombatLog.log_ability(tower, null, \"Curse of the Silent\")\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tsilence_bt.apply_only_timed(tower, next, duration)\n\n\n# NOTE: \"glaive_hit()\" in original script\nfunc glaive_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = tower.get_current_attack_damage_with_bonus()\n\tvar silenced_damage_multiplier: float = get_silenced_damage_multiplier()\n\n\tif target.is_silenced():\n\t\tdamage *= silenced_damage_multiplier\n\t\tEffect.create_scaled(\"res://src/effects/spell_breaker_target.tscn\", Vector3(target.get_x(), target.get_x(), 30), 0, 1)\n\n\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\n\n# NOTE: \"silence()\" in original script\nfunc aura_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar target: Creep = event.get_target()\n\tvar silence_chance: float = (0.03 + 0.0008 * tower.get_level()) * buffed_unit.get_base_attack_speed()\n\n\tif !tower.calc_chance(silence_chance):\n\t\treturn\n\n\tvar duration: float = 1.0 + 0.04 * tower.get_level()\n\tif target.get_size() == CreepSize.enm.BOSS:\n\t\tduration /= 2\n\n\tCombatLog.log_ability(buffed_unit, target, \"Global Silence Effect\")\n\n\tsilence_bt.apply_only_timed(tower, target, duration)\n\n\nfunc get_silenced_damage_multiplier() -> float:\n\tvar multiplier: float = 1.2 + 0.032 * tower.get_level()\n\n\treturn multiplier\n"
  },
  {
    "path": "src/towers/tower_behaviors/nuclear_missile_launcher.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] original script\n# implemented progress bar as text with bars like\n# \"|||||...\". Implemented it as an actual ProgressBar\n# instead. Also changed how current cooldown ratio is\n# calculated to be more straightforward.\n\n\nvar targeted_pt: BuffType\nvar _progress_bar: ProgressBar\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.5)\n\n\nfunc tower_init():\n\ttargeted_pt = BuffType.new(\"targeted_pt\", -1, 0, false, self)\n\ttargeted_pt.set_buff_icon(\"res://resources/icons/generic_icons/pokecog.tres\")\n\ttargeted_pt.add_event_on_create(targeted_pt_on_create)\n\ttargeted_pt.add_event_on_refresh(targeted_pt_on_refresh)\n\ttargeted_pt.set_buff_tooltip(tr(\"PVP0\"))\n\n\nfunc on_create(_preceding_tower: Tower):\n\t_progress_bar = ProgressBar.new()\n\t_progress_bar.size = Vector2(150, 20)\n\t_progress_bar.position.y = -Constants.TILE_SIZE_PIXELS / 2\n\t_progress_bar.position.x = -75\n\t_progress_bar.show_percentage = false\n\t_progress_bar.modulate = Color.RED\n\ttower._visual.add_child(_progress_bar)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\ttargeted_pt.apply(tower, target, tower.get_level())\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif !event.is_main_target():\n\t\tEffect.create_simple_at_unit(\"res://src/effects/frag_boom_spawn.tscn\", target)\n\n\t\treturn\n\n\tvar main_target_effect: int = Effect.create_simple_at_unit(\"res://src/effects/mortar_missile.tscn\", target)\n\tEffect.set_scale(main_target_effect, 3.0)\n\tEffect.set_animation_speed(main_target_effect, 0.5)\n\n\tvar target_buff: Buff = target.get_buff_of_type(targeted_pt)\n\n# \tNOTE: do not remove buff if user_int is above 0 so that\n# \tthe multiple launchers work correctly together\n\tif target_buff != null:\n\t\tif target_buff.user_int <= 0:\n\t\t\ttarget_buff.remove_buff()\n\t\telse:\n\t\t\ttarget_buff.user_int -= 1\n\n\nfunc periodic(_event: Event):\n\tvar remaining_cd: float = tower.get_remaining_cooldown()\n\tvar attack_speed: float = tower.get_current_attack_speed()\n\tvar cd_ratio: float = 1.0 - remaining_cd / attack_speed\n\n\t_progress_bar.set_as_ratio(cd_ratio)\n\n\nfunc targeted_pt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_int = 0\n\n\nfunc targeted_pt_on_refresh(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_int += 1\n"
  },
  {
    "path": "src/towers/tower_behaviors/obelisk_of_fortuity.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {miss_chance_base = 0.3},\n\t\t2: {miss_chance_base = 0.4},\n\t\t3: {miss_chance_base = 0.5},\n\t\t4: {miss_chance_base = 0.6},\n\t\t5: {miss_chance_base = 0.7},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tif tower.calc_bad_chance(_stats.miss_chance_base - tower.get_level() * 0.006):\n\t\tCombatLog.log_ability(tower, event.get_target(), \"Warming Up\")\n\t\tevent.damage = 0\n\t\ttower.get_player().display_floating_text_x(tr(\"FLOATING_TEXT_MISS\"), tower, Color8(255, 0, 0, 255), 0.05, 0.0, 2.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/owl_of_wisdom.gd",
    "content": "extends TowerBehavior\n\n\nvar missile_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {dmg_ratio_for_immune = 0.10, dmg_ratio_for_immune_add = 0.004, periodic_event_period = 5.0, energyball_chance = 0.25, energyball_radius_add = 1, energyball_dmg_base = 4500, energyball_dmg_exp_scale = 2.25},\n\t\t2: {dmg_ratio_for_immune = 0.15, dmg_ratio_for_immune_add = 0.006, periodic_event_period = 4.0, energyball_chance = 0.30, energyball_radius_add = 2, energyball_dmg_base = 6500, energyball_dmg_exp_scale = 3.25},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_periodic_event(periodic, _stats.periodic_event_period)\n\n\nfunc tower_init():\n\tmissile_pt = ProjectileType.create(\"res://src/projectiles/projectile_visuals/energy_ball.tscn\", 5.0, 950.0, self)\n\tmissile_pt.enable_homing(missile_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar chance: float = 0.25 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Energyball\")\n\n\ttomy_energyball_start(target)\n\n\nfunc on_create(_preceding: Tower):\n\ttower.user_int = 1\n\n\nfunc periodic(_event: Event):\n\tvar chance: float = 0.10 + 0.002 * tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 900)\n\n\twhile true:\n\t\tvar target: Creep = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tif tower.calc_chance(chance):\n\t\t\tCombatLog.log_ability(tower, target, \"Energy Detection\")\n\t\t\ttomy_energyball_start(target)\n\n\nfunc tomy_energyball_start(target: Creep):\n\tProjectile.create_from_unit_to_unit(missile_pt, tower, 0, 0, tower, target, true, false, false)\n\n\nfunc missile_pt_on_hit(projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar aoe_range: float = 100 + 1 * tower.get_level()\n\n\tvar wave_level: int = tower.get_player().get_team().get_level()\n\tvar damage_bonus_from_exp_max: float = 150.0 * wave_level\n\tvar damage_bonus_from_exp: float = min(_stats.energyball_dmg_exp_scale * tower.get_exp(), damage_bonus_from_exp_max)\n\tvar immune_damage_ratio: float = _stats.dmg_ratio_for_immune + _stats.dmg_ratio_for_immune_add * tower.get_level()\n\t\n\tvar energyball_damage: float\n\tif !target.is_immune():\n\t\tenergyball_damage = _stats.energyball_dmg_base + damage_bonus_from_exp\n\telse:\n\t\tenergyball_damage = (_stats.energyball_dmg_base + damage_bonus_from_exp) * immune_damage_ratio * tower.get_prop_spell_damage_dealt()\n\t\n\tif !target.is_immune():\n\t\ttower.do_spell_damage_aoe_unit(target, aoe_range, energyball_damage, tower.calc_spell_crit_no_bonus(), 0)\n\telse:\n\t\ttower.do_attack_damage_aoe_unit(target, aoe_range, energyball_damage, tower.calc_spell_crit_no_bonus(), 0)\n\n\tEffect.create_colored(\"res://src/effects/wisp_explode.tscn\", Vector3(projectile.get_x(), projectile.get_y(), 0.0), 0, 1, Color.BLUE)\n"
  },
  {
    "path": "src/towers/tower_behaviors/particle_accelerator.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_value = 0.02},\n\t\t2: {mod_value = 0.03},\n\t\t3: {mod_value = 0.04},\n\t}\n\n\nconst MOD_VALUE_ADD: float = 0.001\nconst STUN_DURATION: float = 2\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc update_effect_speed():\n\tvar effect_id: int = tower.user_int2\n\tvar new_speed: float = 0.5 + tower.user_real / 2\n\tEffect.set_animation_speed(effect_id, new_speed)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar acceleration_label: String = tr(\"GPF2\")\n\tmultiboard.set_key(0, acceleration_label)\n\n\tstun_bt = CbStun.new(\"particle_accelerator_stun\", 0, 0, false, self)\n\n\nfunc on_attack(_event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar modify_value: float = _stats.mod_value + MOD_VALUE_ADD * lvl\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, modify_value)\n\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, modify_value)\n\ttower.user_real = tower.user_real + modify_value\n\tupdate_effect_speed()\n\n\nfunc on_kill(event: Event):\n\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/ancient_protector_missile.tscn\", event.get_target())\n\tEffect.set_color(effect, Color.ORANGE)\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -tower.user_real)\n\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -tower.user_real)\n\tstun_bt.apply_only_timed(tower, tower, STUN_DURATION)\n\ttower.user_real = 0\n\tupdate_effect_speed()\n\n\nfunc on_create(_preceding: Tower):\n\tvar effect_pos: Vector3 = tower.get_position_wc3()\n\teffect_pos.z += 50\n\tvar effect: int = Effect.create_animated_scaled(\"res://src/effects/spirit_link_target.tscn\", effect_pos, 0, 1.5)\n\tEffect.set_auto_destroy_enabled(effect, false)\n\ttower.user_int2 = effect\n\ttower.user_real = 0\n\tupdate_effect_speed()\n\n\nfunc on_destruct():\n\tEffect.destroy_effect(tower.user_int2)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_float(tower.user_real * 100, 1))\n\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/phantom.gd",
    "content": "extends TowerBehavior\n\n\nvar wind_shear_bt: BuffType\nvar chainlightning_st: SpellType\nvar chainlightning_st_2: SpellType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {attack_speed = 0.10, buff_level = 0, user_real_base = 0, user_real_add = 1},\n\t\t2: {attack_speed = 0.15, buff_level = 5, user_real_base = 50, user_real_add = 3},\n\t\t3: {attack_speed = 0.20, buff_level = 10, user_real_base = 125, user_real_add = 6},\n\t\t4: {attack_speed = 0.25, buff_level = 15, user_real_base = 225, user_real_add = 10},\n\t\t5: {attack_speed = 0.30, buff_level = 20, user_real_base = 425, user_real_add = 18},\n\t}\n\n\nfunc phantom_attack(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tvar twr: Tower = b.get_buffed_unit()\n\n\tif b.get_caster().get_level() < 20:\n\t\tif twr.calc_chance(0.25 * twr.get_base_attack_speed()):\n\t\t\tCombatLog.log_ability(twr, event.get_target(), \"Wind Shear Bonus\")\n\n\t\t\tchainlightning_st.target_cast_from_caster(twr, event.get_target(), 1.0 + b.user_real * 0.04, twr.calc_spell_crit_no_bonus())\n\telse:\n\t\tif twr.calc_chance(0.25 * twr.get_base_attack_speed()):\n\t\t\tCombatLog.log_ability(twr, event.get_target(), \"Wind Shear Super Bonus\")\n\t\t\t\n\t\t\tchainlightning_st_2.target_cast_from_caster(twr, event.get_target(), 1.0 + b.user_real * 0.04, twr.calc_spell_crit_no_bonus())\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_ATTACKSPEED, _stats.attack_speed, 0.01)\n\t\n\twind_shear_bt = BuffType.new(\"wind_shear_bt\", 5.0, 0.1, true, self)\n\t\n\twind_shear_bt.set_buff_modifier(m)\n\t\n\twind_shear_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\t\n\twind_shear_bt.add_event_on_attack(phantom_attack)\n\t\n\twind_shear_bt.set_buff_tooltip(tr(\"TQVI\"))\n\n\tchainlightning_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 5.00, self)\n\tchainlightning_st.set_source_height(40.0)\n\tchainlightning_st.data.chain_lightning.damage = 100\n\tchainlightning_st.data.chain_lightning.damage_reduction = 0.25\n\tchainlightning_st.data.chain_lightning.chain_count = 3\n\n\tchainlightning_st_2 = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 5.00, self)\n\tchainlightning_st_2.set_source_height(40.0)\n\tchainlightning_st_2.data.chain_lightning.damage = 100\n\tchainlightning_st_2.data.chain_lightning.damage_reduction = 0.25\n\tchainlightning_st_2.data.chain_lightning.chain_count = 4\n\n\nfunc on_autocast(event: Event):\n\twind_shear_bt.apply_custom_timed(tower, event.get_target(), tower.get_level() + _stats.buff_level, 5.0 + tower.get_level() * 0.1).user_real = tower.get_level() * _stats.user_real_add + _stats.user_real_base\n"
  },
  {
    "path": "src/towers/tower_behaviors/plagued_crypt.gd",
    "content": "extends TowerBehavior\n\n\nvar plague_bt: BuffType\nvar army_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 3.0)\n\n\nfunc tower_init():\n\tplague_bt = BuffType.new(\"plague_bt\", 5.0, 0.2, false, self)\n\tplague_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\tplague_bt.add_event_on_create(cedi_crypt_plague_on_create)\n\tplague_bt.add_event_on_upgrade(cedi_crypt_plague_on_upgrade)\n\tplague_bt.add_event_on_refresh(cedi_crypt_plague_on_refresh)\n\tplague_bt.add_periodic_event(cedi_crypt_plague_periodic_damage, 1.0)\n#\tNOTE: The period of periodic event starts out at 0.01\n#\tand then gets changed to real period via\n#\tenable_advanced(). It starts at 0.01 to change to real\n#\tperiod as quickly as possible.\n\tplague_bt.add_periodic_event(cedi_crypt_plague_periodic_spread, 0.01)\n\tplague_bt.set_buff_tooltip(tr(\"I2A2\"))\n\n\tarmy_bt = BuffType.new(\"army_bt\", -1, 0, true, self)\n\tvar cedi_crypt_army_mod: Modifier = Modifier.new()\n\tcedi_crypt_army_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.05)\n\tcedi_crypt_army_mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, 0.0, 0.05)\n\tarmy_bt.set_buff_modifier(cedi_crypt_army_mod)\n\tarmy_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\tarmy_bt.set_buff_tooltip(tr(\"HDAQ\"))\n\n\tmultiboard = MultiboardValues.new(2)\n\tvar souls_extracted_label: String = tr(\"E8AJ\")\n\tvar infection_rate_label: String = tr(\"MIK6\")\n\tmultiboard.set_key(0, souls_extracted_label)\n\tmultiboard.set_key(1, infection_rate_label)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tplague_bt.apply(tower, target, level)\n\n\nfunc on_tower_details():\n\tvar army_buff: Buff = tower.get_buff_of_type(army_bt)\n\tvar army_buff_level: int\n\tif army_buff != null:\n\t\tarmy_buff_level = army_buff.get_level()\n\telse:\n\t\tarmy_buff_level = 0\n\tvar souls_extracted: String = str(army_buff_level)\n\tvar plague_spread_time: float = get_plague_spread_time()\n\tvar infection_rate: String = Utils.format_float(plague_spread_time, 2)\n\n\tmultiboard.set_value(0, souls_extracted)\n\tmultiboard.set_value(1, infection_rate)\n\n\treturn multiboard\n\n\nfunc periodic(_event: Event):\n\tvar it: Iterate = Iterate.over_corpses_in_range(tower, Vector2(tower.get_x(), tower.get_y()), 1150)\n\tvar corpse: Unit = it.next_corpse()\n\n\tif corpse == null:\n\t\treturn\n\n\tEffect.add_special_effect(\"res://src/effects/raise_skeleton.tscn\", Vector2(corpse.get_x(), corpse.get_y()))\n\n\tcorpse.remove_from_game()\n\n\tvar active_buff: Buff = tower.get_buff_of_type(army_bt)\n\tvar new_buff_level: int\n\tif active_buff != null:\n\t\tnew_buff_level = active_buff.get_level() + 1\n\telse:\n\t\tnew_buff_level = 1\n\t\n\tvar buff: Buff = army_bt.apply(tower, tower, new_buff_level)\n\tbuff.set_displayed_stacks(buff.get_level())\n\n\tvar stack_duration: float = (20.0 + 0.4 * tower.get_level()) * tower.get_prop_buff_duration()\n\tawait Utils.create_manual_timer(stack_duration, self).timeout\n\n#\tNOTE: after sleep\n\tif !Utils.unit_is_valid(tower):\n\t\treturn\n\n\tif !is_instance_valid(buff):\n\t\treturn\n\n\tvar reduced_buff_level: int = buff.get_level() - 1\n\tif reduced_buff_level > 0:\n\t\tbuff.set_level(reduced_buff_level)\n\telse:\n\t\tbuff.remove_buff()\n\n\n# NOTE: onCreate() in original script\nfunc cedi_crypt_plague_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar damage_increase_multiplier: int = 0\n\tbuff.user_int = damage_increase_multiplier\n\tvar first_periodic_call: int = 0\n\tbuff.user_int2 = first_periodic_call\n\n\tbuff.set_displayed_stacks(buff.user_int + 1)\n\n\n# NOTE: part of refresh() in original script\nfunc cedi_crypt_plague_on_upgrade(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tincrease_plague_stacks(buff)\n\n\n# NOTE: part of refresh() in original script\nfunc cedi_crypt_plague_on_refresh(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tincrease_plague_stacks(buff)\n\n\n# NOTE: part of refresh() in original script\nfunc increase_plague_stacks(buff: Buff):\n\tvar old_damage_increase_multiplier: int = buff.user_int\n\tvar new_damage_increase_multiplier: int = old_damage_increase_multiplier + 1\n\tbuff.user_int = new_damage_increase_multiplier\n\n\tbuff.set_displayed_stacks(buff.user_int + 1)\n\n\n# NOTE: periodicDamage() in original script\nfunc cedi_crypt_plague_periodic_damage(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar level: int = tower.get_level()\n\tvar damage_increase_multiplier: int = buff.user_int\n\tvar damage: float = (750 + 30 * level) + (375 + 15 * level) * damage_increase_multiplier\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: script doesn't spread when user_int2 is 0 because\n# that case happens 0.01s after buff is applied. Once we\n# call enable_advanced() with real duration of around 1.5s,\n# we will start doing real plague spreads.\n# NOTE: periodicSpread() in original script\nfunc cedi_crypt_plague_periodic_spread(event: Event):\n\tvar plague_buff: Buff = event.get_buff()\n\tvar target: Unit = plague_buff.get_buffed_unit()\n\tvar level: int = tower.get_level()\n\tvar first_periodic_call: int = plague_buff.user_int2\n\n\tif first_periodic_call == 1:\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 250)\n\t\t\n\t\twhile true:\n\t\t\tvar next: Unit = it.next_random()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tif next != target:\n\t\t\t\tplague_bt.apply(tower, next, level)\n\t\t\t\tbreak\n\telse:\n\t\tvar new_first_periodic_call: int = 1\n\t\tplague_buff.user_int2 = new_first_periodic_call\n\n\tvar plague_spread_time: float = get_plague_spread_time()\n\tevent.enable_advanced(plague_spread_time, false)\n\n\n# NOTE: plague spread time gets smaller as the level of army\n# buff increases\nfunc get_plague_spread_time():\n\tvar army_buff: Buff = tower.get_buff_of_type(army_bt)\n\tvar army_buff_level: int\n\tif army_buff == null:\n\t\tarmy_buff_level = 0\n\telse:\n\t\tarmy_buff_level = army_buff.get_level()\n\t\n\tvar plague_spread_time: float = 1.5 * pow(1.1, -army_buff_level)\n\n\treturn plague_spread_time\n"
  },
  {
    "path": "src/towers/tower_behaviors/planar_gate.gd",
    "content": "extends TowerBehavior\n\n\nvar eruption_bt: BuffType\nvar planar_shift_bt: BuffType\nvar bouncing_pt: ProjectileType\nvar falcon_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\n\teruption_bt = BuffType.new(\"eruption_bt\", 6, 0.18, true, self)\n\teruption_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\teruption_bt.set_buff_tooltip(tr(\"BOPO\"))\n\n\tplanar_shift_bt = BuffType.new(\"planar_shift_bt\", -1, 0, false, self)\n\tplanar_shift_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\tplanar_shift_bt.add_event_on_cleanup(planar_shift_bt_on_cleanup)\n\tplanar_shift_bt.set_buff_tooltip(tr(\"I8HW\"))\n\n\tbouncing_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1250, self)\n\tbouncing_pt.set_event_on_interpolation_finished(bouncing_pt_on_hit)\n\n\nfunc on_attack(event: Event):\n\tvar ignore_falcon_count_max_chance: float = 0.20\n\tvar ignore_falcon_count_max: bool = tower.calc_chance(ignore_falcon_count_max_chance)\n\n#\tCheck if the amount of birds summoned is low enough to create another one.\n\tvar falcon_count_max: int = 1 + tower.get_level() / 8\n\tif falcon_count >= falcon_count_max && !ignore_falcon_count_max:\n\t\treturn\n\n\tvar target: Unit = event.get_target()\n\n\tCombatLog.log_ability(tower, target, \"Planeshift\")\n\n\tvar crits: int = event.get_number_of_crits()\n\tvar cur_dmg: float = tower.get_current_attack_damage_with_bonus()\n\tvar eruption_buff: Buff = tower.get_buff_of_type(eruption_bt)\n\n#\tSet the projectile values.\n\tvar p: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(bouncing_pt, tower, 1, 1, tower, target, 0.5, true)\n\tp.user_real = 0.05 - 0.001 * tower.get_level() # damage multiplier loss per bounce\n\tp.user_real2 = 1 # Projectile's current damage multiplier\n\n\tif eruption_buff != null:\n\t\tp.user_int3 = 1\n\telse:\n\t\tp.user_int3 = 0\n\n#\tCheck for crits.\n\tif crits > 0:\n\t\tp.user_real3 = cur_dmg * (crits * (tower.get_prop_atk_crit_damage() - 1) + 1)\n\t\tp.user_int = crits\n\telse:\n\t\tp.user_real3 = cur_dmg\n\t\tp.user_int = 0\n\n#\tIncrease counter for birds summoned.\n\tfalcon_count += 1\n\n\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\nfunc on_autocast(_event: Event):\n\tvar effect_pos: Vector3 = tower.get_position_wc3()\n\n\teruption_bt.apply(tower, tower, tower.get_level())\n\n\tvar effect1: int = Effect.create_colored(\"res://src/effects/voodoo_aura.tscn\", effect_pos, 0, 1, Color8(1, 255, 255, 255))\n\tEffect.set_z_index(effect1, Effect.Z_INDEX_BELOW_TOWERS)\n\n\tawait Utils.create_manual_timer(0.3, self).timeout\n\n\tvar effect2: int = Effect.create_colored(\"res://src/effects/voodoo_aura.tscn\", effect_pos, 0, 2, Color8(1, 255, 255, 255))\n\tEffect.set_z_index(effect2, Effect.Z_INDEX_BELOW_TOWERS)\n\t\n\tawait Utils.create_manual_timer(0.3, self).timeout\n\t\n\tvar effect3: int = Effect.create_colored(\"res://src/effects/voodoo_aura.tscn\", effect_pos, 0, 3, Color8(1, 255, 255, 255))\n\tEffect.set_z_index(effect3, Effect.Z_INDEX_BELOW_TOWERS)\n\n\n# p.userInt = number of crits\n# p.userInt2 = UID\n# p.userInt3 = check for buff\n# p.userReal = damage loss per bounce\n# p.userReal2 = damage ratio of this projectile\n# p.userReal3 = damage to deal\n# NOTE: \"bounce()\" in original script\nfunc bouncing_pt_on_hit(p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n#\tCheck if this projectile has damage ratio left and if the target is still alive.\n\tif p.user_real2 <= 0 || target == null:\n#\t\tIf the projectile had no damage ratio, end here and decrease the tower userInt.\n\t\tfalcon_count -= 1\n\n\t\treturn\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 500)\n\tvar dmg_mod_buff: Buff = target.get_buff_of_type(planar_shift_bt)\n\n#\tCheck if the tower cast the buff since the last time this projectile hit.\n\tif tower.get_buff_of_type(eruption_bt) != null && p.user_int3 == 0:\n\t\tp.user_int3 = 1\n\n#\tCheck if the tower crit this attack, and if so, display\n#\tthe damage colored red above the tower with exclamation\n#\tmarks after it equal to the number of crits. This only\n#\truns the first time the projectile hits because\n#\tp.userInt is set to 0 at the end.\n\tif p.user_int > 0:\n\t\tvar crit_str: String = \"\"\n\t\tvar int_var: int = 0\n\n\t\twhile true:\n\t\t\tcrit_str += \"!\"\n\t\t\tint_var += 1\n\n\t\t\tif int_var == p.user_int:\n\t\t\t\tbreak\n\n\t\tvar floating_text: String = str(int(p.user_real3)) + crit_str\n\n\t\ttower.get_player().display_floating_text(floating_text, tower, Color8(255, 0, 0))\n\n#\tCheck if the buff was applied on the tower when it\n#\tlaunched this projectile, and if the target isn't immune\n#\tthen increase the damage it takes from astral, and apply\n#\tthe buff or if the buff was already applied, increase\n#\tthe amount of damage taken to remove when the buff gets\n#\tpurged or similar.\n\tif p.user_int3 == 1:\n\t\tif !target.is_immune():\n\t\t\tvar dmg_mod: float = p.user_real2 * 0.01\n\t\t\ttarget.modify_property(ModificationType.enm.MOD_DMG_FROM_ASTRAL, dmg_mod)\n\n\t\t\tif dmg_mod_buff != null:\n\t\t\t\tdmg_mod_buff.user_real += dmg_mod\n\t\t\telse:\n\t\t\t\tdmg_mod_buff = planar_shift_bt.apply(tower, target, 0)\n\t\t\t\tdmg_mod_buff.user_real = dmg_mod\n\n#\tDeal the damage (double if the projectile got buffed).\n\tvar damage: float = p.user_real3 * p.user_real2 * (1 + p.user_int3)\n\ttower.do_attack_damage(target, damage, 1.0)\n\n#\tChoose a target from all creeps in 500 range that isn't\n#\tthis projectile's target.\n\tvar next: Unit = it.next_random()\n\tif next == target && next != null:\n\t\tnext = it.next_random()\n\n#\tIf no valid targets in range, end here and decrease\n#\tfalcon count so portal can fire again.\n\tif next == null:\n\t\tfalcon_count -= 1\n\n\t\treturn\n\n#\tFire the projectile to the next unit and set all the\n#\tnecessary values.\n\tvar new_p: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(bouncing_pt, tower, 1, 1, target, next, 0.35, true)\n\n\tnew_p.user_int = 0\n\tnew_p.user_int3 = p.user_int3\n\tnew_p.user_real = p.user_real\n\tnew_p.user_real2 = p.user_real2 - p.user_real # decrease new projectile's damage multiplier\n\tnew_p.user_real3 = p.user_real3\n\n\n# In case the buff gets purged.\n# NOTE: \"removeMod()\" in original script\nfunc planar_shift_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tbuffed_unit.modify_property(ModificationType.enm.MOD_DMG_FROM_ASTRAL, -buff.user_real)\n"
  },
  {
    "path": "src/towers/tower_behaviors/poison_battery.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: rewrote script a bit. Instead of enabling/disabling\n# periodic event I added a flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where it refunds the cost of autocast in\n# on_autocast(). It refunds the cost by calling set_mana()\n# but the problem is that at the time when on_autocast() is\n# called, the mana cost has not been spent yet. Therefore,\n# refund fails if tower is at max mana because set_mana()\n# can't go above max mana. Not critical - don't need to fix.\n\n\nvar poison_bt: BuffType\nvar orb_pt: ProjectileType\n\nvar _battery_overload_is_active: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 300, projectile_damage_add = 12, poison_damage = 100, poison_damage_add = 3, mod_movespeed = -0.05, mod_movespeed_add = -0.0012},\n\t\t2: {projectile_damage = 750, projectile_damage_add = 30, poison_damage = 240, poison_damage_add = 8, mod_movespeed = -0.07, mod_movespeed_add = -0.0028},\n\t\t3: {projectile_damage = 1800, projectile_damage_add = 72, poison_damage = 600, poison_damage_add = 20, mod_movespeed = -0.10, mod_movespeed_add = -0.0040},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc on_autocast(_event: Event):\n\ttower.set_mana(tower.get_mana() + 100)\n\t_battery_overload_is_active = true\n\n\nfunc damage_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.poison_damage + _stats.poison_damage_add * level\n\n\ttower.do_spell_damage(buffed_unit, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.projectile_damage + _stats.projectile_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tpoison_bt.apply(tower, creep, level)\n\n\nfunc tower_init():\n\tvar modifier: Modifier = Modifier.new()\n\tmodifier.add_modification(ModificationType.enm.MOD_MOVESPEED, _stats.mod_movespeed, _stats.mod_movespeed_add)\n\n\tpoison_bt = BuffType.new(\"poison_bt\", 9, 0.3, false, self)\n\tpoison_bt.set_buff_icon(\"res://resources/icons/mechanical/battery.tres\")\n\tpoison_bt.add_periodic_event(damage_periodic, 1)\n\tpoison_bt.set_buff_modifier(modifier)\n\tpoison_bt.set_buff_tooltip(tr(\"UGKZ\"))\n\n\torb_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\torb_pt.enable_homing(hit, 0)\n\n\nfunc on_damage(event: Event):\n\tpoison_bt.apply(tower, event.get_target(), tower.get_level())\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.set_mana(0)\n\n\nfunc periodic(_event: Event):\n\tif !_battery_overload_is_active:\n\t\treturn\n\n\tif tower.get_mana() > 10:\n\t\tvar in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar target: Unit = in_range.next_random()\n\n\t\tif target != null:\n# \t\t\tNOTE: original script used createFromPointToUnit and made projectiles from high above the tower\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(orb_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\t\tp.set_projectile_scale(0.5)\n\n#\t\tSpend mana, note that mana is used for unsuccessful\n#\t\tattempts as well\n\t\ttower.set_mana(tower.get_mana() - 10)\n\telse:\n#\t\tTower is out of mana so stop shooting\n\t\t_battery_overload_is_active = false\n"
  },
  {
    "path": "src/towers/tower_behaviors/polar_bear_cub.gd",
    "content": "extends TowerBehavior\n\n\nvar cold_feet_bt: BuffType\nvar cold_arms_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {dmg_increase = 200},\n\t\t2: {dmg_increase = 250},\n\t\t3: {dmg_increase = 300},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_cleanup(event: Event):\n\tvar b: Buff = event.get_buff()\n\tb.get_buffed_unit().user_int = 0\n\n\nfunc tower_init():\n\tvar cold_feet_bt_mod: Modifier = Modifier.new()\n\tvar cold_arms_bt_mod: Modifier = Modifier.new()\n\n\tcold_feet_bt = BuffType.new(\"cold_feet_bt\", 6, 0, true, self)\n\tcold_feet_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0, -0.001)\n\tcold_feet_bt.set_buff_modifier(cold_feet_bt_mod)\n\tcold_feet_bt.set_buff_icon(\"res://resources/icons/generic_icons/barefoot.tres\")\n\tcold_feet_bt.add_event_on_cleanup(on_cleanup)\n\tcold_feet_bt.set_buff_tooltip(tr(\"RHKN\"))\n\n\tcold_arms_bt = BuffType.new(\"cold_arms_bt\", 6, 0, true, self)\n\tcold_arms_bt_mod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0, 0.001)\n\tcold_arms_bt.set_buff_modifier(cold_arms_bt_mod)\n\tcold_arms_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tcold_arms_bt.set_buff_tooltip(tr(\"ED2V\"))\n\n\nfunc on_attack(_event: Event):\n\tvar active_stack_count: int = tower.user_int\n\tvar new_stack_count: int = min(active_stack_count + 1, 10)\n\ttower.user_int = new_stack_count\n\t\n\tvar cold_feet_per_stack: int\n\tif tower.get_level() < 15:\n\t\tcold_feet_per_stack = 50\n\telif tower.get_level() < 25:\n\t\tcold_feet_per_stack = 40\n\telse:\n\t\tcold_feet_per_stack = 30\n\n\tvar cold_feet_buff_level: int = cold_feet_per_stack * new_stack_count\n\tvar cold_arms_buff_level: int = _stats.dmg_increase * new_stack_count\n\tvar cold_feet_buff: Buff = cold_feet_bt.apply(tower, tower, cold_feet_buff_level)\n\tvar cold_arms_buff: Buff = cold_arms_bt.apply(tower, tower, cold_arms_buff_level)\n\n\tcold_feet_buff.set_displayed_stacks(new_stack_count)\n\tcold_arms_buff.set_displayed_stacks(new_stack_count)\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/portal_to_swine_purgatory.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] fixed bug in original script\n# where it had special values for challenge creep sizes but\n# failed to use them because it used Creep.getSize()\n# function which substitues challenge sizes into mass/boss.\n\n# NOTE: [ORIGINAL_GAME_BUG] fixed bug in original script\n# where pig speed was the same for all tower tiers.\n\n# NOTE: changed Initiative stacks from ints to floats. This\n# way, the total can be 16 instead of confusing 48.\n\n\nclass PigData:\n\tvar dmg: float = 0\n\tvar crit: float = 0\n\tvar spell_crit: float = 0\n\tvar splash: float = 0\n\tvar target_is_air: bool = false\n\n\nvar boar_pt: ProjectileType\nvar air_boar_pt: ProjectileType\nvar projectile_to_pig_data_map: Dictionary = {}\nvar initiative_stack_count: float = 0\n\nconst creep_size_to_initiative_stack: Dictionary = {\n\tCreepSize.enm.MASS: 1,\n\tCreepSize.enm.CHALLENGE_MASS: 1.33,\n\tCreepSize.enm.NORMAL: 2,\n\tCreepSize.enm.CHAMPION: 3.33,\n\tCreepSize.enm.AIR: 3.33,\n\tCreepSize.enm.BOSS: 8.33,\n\tCreepSize.enm.CHALLENGE_BOSS: 8.33,\n}\nconst HOME_RANGE_BONUS_FOR_BOSSES: float = 75\nconst HOME_RANGE_ADD: float = 2\nconst SPLASH_DMG_RATIO: float = 0.15\nconst SPLASH_DMG_RATIO_ADD: float = 0.004\nconst SPLASH_RADIUS: float = 375\nconst INITIATIVE_STACK_MAX: float = 16\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {initiative_range = 900, pig_count = 2, home_range = 275, pig_speed = 380, pig_speed_add = 2},\n\t\t2: {initiative_range = 900, pig_count = 3, home_range = 290, pig_speed = 390, pig_speed_add = 4},\n\t\t3: {initiative_range = 1400, pig_count = 3, home_range = 310, pig_speed = 400, pig_speed_add = 8},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, _stats.initiative_range, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\n\tboar_pt = ProjectileType.create_ranged(\"res://src/projectiles/projectile_visuals/flying_pork.tscn\", 1500, _stats.pig_speed, self)\n\tboar_pt.disable_explode_on_expiration()\n\tboar_pt.enable_collision(boar_pt_on_collide, 0.0, TargetType.new(TargetType.CREEPS), false)\n\tboar_pt.enable_homing(boar_pt_on_hit, 20)\n\tboar_pt.enable_periodic(boar_pt_periodic, 1.0)\n\tboar_pt.set_event_on_cleanup(boar_pt_on_cleanup)\n\n\tair_boar_pt = ProjectileType.create_interpolate(\"res://src/projectiles/projectile_visuals/flying_pork.tscn\", 880, self)\n\tair_boar_pt.disable_explode_on_expiration()\n\tair_boar_pt.set_event_on_interpolation_finished(air_boar_pt_on_hit)\n\tair_boar_pt.set_event_on_cleanup(air_boar_pt_on_cleanup)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar target_pos: Vector3 = target.get_position_wc3()\n\tvar target_size: CreepSize.enm = target.get_size()\n\tvar target_is_air: bool = target_size == CreepSize.enm.AIR\n\tvar pig_count: int = get_base_pig_count()\n\n\tdo_rampage_of_pigs(target, target_pos, target_is_air, pig_count)\n\n\nfunc on_kill(event: Event):\n\tvar target: Unit = event.get_target()\n\tdo_initiative_ability(target)\n\n\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\nfunc on_unit_in_range(event: Event):\n\tvar target: Unit = event.get_target()\n\tdo_initiative_ability(target)\n\n\n# NOTE: deem_BoarHome() in original script\nfunc boar_pt_on_collide(p: Projectile, target: Unit):\n\tif target.get_size() == CreepSize.enm.AIR:\n\t\treturn\n\n\tif target == null:\n\t\treturn\n\n\tp.set_collision_enabled(false)\n\tp.set_homing_target(target)\n\tp.set_acceleration(24)\n\tp.set_color(Color8(255, 95, 95, 255))\n\tp.disable_periodic()\n\n\nfunc boar_pt_on_hit(p: Projectile, target: Unit):\n\tgeneric_boar_pt_on_hit(p, target)\n\n\n# NOTE: deem_BoarPeriodic() in original script\nfunc boar_pt_periodic(p: Projectile):\n\tvar new_direction: float = p.get_direction() + Globals.synced_rng.randf_range(-1, 1) * 12\n\tp.set_direction(new_direction)\n\n\nfunc boar_pt_on_cleanup(p: Projectile):\n\tgeneric_boar_on_cleanup(p)\n\n\nfunc air_boar_pt_on_hit(p: Projectile, target: Unit):\n\tgeneric_boar_pt_on_hit(p, target)\n\n\nfunc air_boar_pt_on_cleanup(p: Projectile):\n\tgeneric_boar_on_cleanup(p)\n\n\n# NOTE: deem_BoarClean() in original script\nfunc generic_boar_on_cleanup(p: Projectile):\n\tprojectile_to_pig_data_map.erase(p)\n\n\nfunc do_initiative_ability(target: Unit):\n#\tNOTE: important to use\n#\tget_size_including_challenge_sizes() here instead of\n#\tget_size() to get challenge sizes. Challenge sizes have\n#\tspecial values for initiative stacks.\n\tvar target_size: CreepSize.enm = target.get_size_including_challenge_sizes()\n\tvar initiative_stack: float = creep_size_to_initiative_stack[target_size]\n\tinitiative_stack_count += initiative_stack\n\n\twhile initiative_stack_count > INITIATIVE_STACK_MAX:\n\t\tinitiative_stack_count -= INITIATIVE_STACK_MAX\n\n\t\tCombatLog.log_ability(tower, target, \"Rampage of Pigs\")\n\n\t\tvar target_pos: Vector3 = target.get_position_wc3()\n\t\tvar target_is_air: bool = target_size == CreepSize.enm.AIR\n\t\tvar pig_count: int = get_base_pig_count()\n\t\tdo_rampage_of_pigs(target, target_pos, target_is_air, pig_count)\n\n\n# NOTE: need to pass target_pos_3d and target_is_air because\n# the tower shoots pigs with a delay and needs to keep\n# shooting at target's position even after it dies.\n# NOTE: PigNuggetOnAttack() + pignuggetlauncher() in\n# original script\nfunc do_rampage_of_pigs(target: Creep, target_pos_3d: Vector3, target_is_air, remaining_pig_count: int):\n\tvar target_pos: Vector2 = Vector2(target_pos_3d.x, target_pos_3d.y)\n\t\n\tvar level: int = tower.get_level()\n\n\tvar pig_speed: float = _stats.pig_speed + _stats.pig_speed_add * level\n\n\tvar tower_pos_3d: Vector3 = tower.get_position_wc3()\n\tvar tower_pos: Vector2 = tower.get_position_wc3_2d()\n\tvar vector_to_target: Vector2 = target_pos - tower_pos\n\tvar pig_direction: float = rad_to_deg(vector_to_target.angle())\n\n\tvar projectile: Projectile\n\tif target_is_air:\n\t\tif Utils.unit_is_valid(target):\n\t\t\tvar start_pos: Vector3 = Vector3(\n\t\t\t\ttower.get_x() + Globals.synced_rng.randi_range(-25, 25),\n\t\t\t\ttower.get_y() + Globals.synced_rng.randi_range(-25, 25),\n\t\t\t\ttower.get_z())\n\t\t\tvar z_arc: float = Globals.synced_rng.randf_range(0, 0.2)\n\t\t\tprojectile = Projectile.create_linear_interpolation_from_point_to_unit(air_boar_pt, tower, 0, 0, start_pos, target, z_arc, true)\n\t\telse:\n\t\t\tvar start_pos: Vector3 = tower_pos_3d + Vector3(\n\t\t\t\tGlobals.synced_rng.randi_range(-25, 25),\n\t\t\t\tGlobals.synced_rng.randi_range(-25, 25),\n\t\t\t\t0\n\t\t\t\t)\n\t\t\tvar end_pos: Vector3 = target_pos_3d + Vector3(\n\t\t\t\tGlobals.synced_rng.randi_range(-50, 50),\n\t\t\t\tGlobals.synced_rng.randi_range(-50, 50),\n\t\t\t\tGlobals.synced_rng.randi_range(-35, 35),\n\t\t\t\t)\n\t\t\tvar z_arc: float = Globals.synced_rng.randf_range(0, 0.3)\n\t\t\tprojectile = Projectile.create_linear_interpolation_from_point_to_point(air_boar_pt, tower, 0, 0, start_pos, end_pos, z_arc)\n\n\t\tprojectile.set_color(Color8(255, 105, 105, 255))\n\telse:\n\t\tvar start_pos: Vector3 = Vector3(\n\t\t\ttower.get_x() + Globals.synced_rng.randi_range(-25, 25),\n\t\t\ttower.get_y() + Globals.synced_rng.randi_range(-25, 25),\n\t\t\ttower.get_z() + 5.0)\n\t\tvar facing: float = pig_direction + 16 * Globals.synced_rng.randf_range(-1, 1)\n\t\tprojectile = Projectile.create(boar_pt, tower, 0, 0, start_pos, facing)\n\t\t\n\t\tvar home_range: float = _stats.home_range\n\t\tif Utils.unit_is_valid(target):\n\t\t\tvar target_size: CreepSize.enm = target.get_size()\n\t\t\tvar target_is_boss: bool = target_size == CreepSize.enm.BOSS\n\t\t\tif target_is_boss:\n\t\t\t\thome_range += HOME_RANGE_BONUS_FOR_BOSSES\n\n\t\tprojectile.set_collision_parameters(home_range, TargetType.new(TargetType.CREEPS))\n\n\t\tprojectile.set_speed(pig_speed)\n\n\tvar pig_data: PigData = PigData.new()\n\tpig_data.dmg = tower.get_current_attack_damage_with_bonus()\n\tpig_data.crit = tower.calc_attack_multicrit_no_bonus()\n\tpig_data.spell_crit = tower.calc_spell_crit_no_bonus()\n\tpig_data.splash = SPLASH_DMG_RATIO + SPLASH_DMG_RATIO_ADD * level\n\tpig_data.target_is_air = target_is_air\n\n\tprojectile_to_pig_data_map[projectile] = pig_data\n\n\tremaining_pig_count -= 1\n\n\tif remaining_pig_count > 0:\n\t\tawait Utils.create_manual_timer(0.25, self).timeout\n\t\t\n\t\tvar update_target_pos_3d: Vector3\n\t\tif Utils.unit_is_valid(target):\n\t\t\tupdate_target_pos_3d = target.get_position_wc3()\n\t\telse:\n\t\t\tupdate_target_pos_3d = target_pos_3d\n\t\t\t\n#\t\tNOTE: need to convert to null to avoid errors about\n#\t\tpassing previously freed reference\n\t\tvar updated_target: Unit\n\t\tif Utils.unit_is_valid(target):\n\t\t\tupdated_target = target\n\t\telse:\n\t\t\tupdated_target = null\n\n\t\tdo_rampage_of_pigs(updated_target, update_target_pos_3d, target_is_air, remaining_pig_count)\n\n\n# NOTE: deem_BoarHit() in original script\nfunc generic_boar_pt_on_hit(p: Projectile, target: Unit):\n\tvar pig_data: PigData = projectile_to_pig_data_map.get(p, null)\n\n\tif pig_data == null:\n\t\tpush_error(\"pig_data is somehow null.\")\n\n\t\treturn\n\n\tvar target_is_air: bool = pig_data.target_is_air\n\n\tif target != null || target_is_air:\n\t\tif target != null:\n\t\t\ttower.do_attack_damage(target, pig_data.dmg, pig_data.crit)\n\t\t\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/doom_death.tscn\", target, Unit.BodyPart.ORIGIN)\n\t\t\tEffect.set_z_index(effect, -1)\n\n\t\tvar pig_pos: Vector2 = p.get_position_wc3_2d()\n\t\tvar it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), pig_pos, SPLASH_RADIUS)\n\n\t\tvar hit_count: int = 0\n\t\twhile true:\n\t\t\tvar next: Unit = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tif !next.is_immune():\n\t\t\t\thit_count += 1\n\n\t\tif hit_count > 0:\n#\t\t\tSplit splash damage to target count\n\t\t\tvar splash_damage: float = pig_data.dmg * pig_data.splash / hit_count\n\n\t\t\ttower.do_spell_damage_aoe(pig_pos, SPLASH_RADIUS, splash_damage, pig_data.spell_crit, 0)\n\telse:\n\t\tp.avert_destruction()\n\t\tp.set_collision_enabled(true)\n\t\tp.set_acceleration(0)\n\t\tp.set_speed(400)\n\t\tp.set_color(Color.WHITE)\n\t\tp.enable_periodic(1.0)\n\n\nfunc get_base_pig_count() -> int:\n\tvar pig_count: int = _stats.pig_count\n\n\tvar level: int = tower.get_level()\n\tif level >= 5:\n\t\tpig_count += 1\n\tif level >= 15:\n\t\tpig_count += 1\n\n\treturn pig_count\n"
  },
  {
    "path": "src/towers/tower_behaviors/prince_of_lightning.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {strike_chance = 0.15, strike_damage = 2000, strike_damage_add = 100, mod_dmg_from_storm = 0.10, mod_dmg_from_storm_add = 0.002},\n\t\t2: {strike_chance = 0.20, strike_damage = 4000, strike_damage_add = 200, mod_dmg_from_storm = 0.15, mod_dmg_from_storm_add = 0.004},\n\t}\n\nconst STRIKE_CHANCE_ADD: float = 0.004\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_STORM, _stats.mod_dmg_from_storm, _stats.mod_dmg_from_storm_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/over_infinity.tres\")\n\taura_bt.set_buff_tooltip(tr(\"DELR\"))\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar strike_chance: float = _stats.strike_chance + STRIKE_CHANCE_ADD * tower.get_level()\n\tvar strike_damage: float = _stats.strike_damage + _stats.strike_damage_add * tower.get_level()\n\n\tif !tower.calc_chance(strike_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Lightning Strike\")\n\n\ttower.do_spell_damage(creep, strike_damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", creep, Unit.BodyPart.ORIGIN)\n"
  },
  {
    "path": "src/towers/tower_behaviors/princess_of_light.gd",
    "content": "extends TowerBehavior\n\n\nvar extract_bt: BuffType\nvar channel_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {extract_exp = 1, extract_exp_add = 0.05, channel_exp = 1, channel_mod_dmg = 0.15, channel_buff_duration = 10},\n\t\t2: {extract_exp = 2, extract_exp_add = 0.10, channel_exp = 2, channel_mod_dmg = 0.20, channel_buff_duration = 12},\n\t}\n\n\nconst EXTRACT_CHANCE: float = 0.33\nconst EXTRACT_DURATION: float = 10.0\nconst EXTRACT_COUNT: int = 10\nconst EXTRACT_COUNT_ADD: int = 1\nconst CHANNEL_MOD_DMG_ADD: float = 0.005\nconst CHANNEL_BUFF_DURATION_ADD: float = 0.1\nconst CHANNEL_STACK_COUNT: int = 15\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_spell_targeted(on_spell_target)\n\n\nfunc tower_init():\n\textract_bt = BuffType.new(\"extract_bt\", EXTRACT_DURATION, 0, false, self)\n\textract_bt.add_event_on_damaged(extract_bt_on_damaged)\n\textract_bt.set_buff_icon(\"res://resources/icons/generic_icons/gold_bar.tres\")\n\textract_bt.set_buff_tooltip(tr(\"PGA5\"))\n\n\tchannel_bt = BuffType.new(\"channel_bt\", -1, 0, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.001)\n\tchannel_bt.set_buff_modifier(mod)\n\tchannel_bt.set_buff_icon(\"res://resources/icons/generic_icons/aquarius.tres\")\n\tchannel_bt.set_buff_tooltip(tr(\"ETOI\"))\n\n\nfunc on_spell_target(event: Event):\n\tvar caster: Unit = event.get_target()\n\tvar buff: Buff = tower.get_buff_of_type(channel_bt)\n\tvar tower_level: int = tower.get_level()\n\tvar buff_level: int = int((_stats.channel_mod_dmg + CHANNEL_MOD_DMG_ADD * tower_level) * 1000)\n\tvar stack_duration: float = _stats.channel_buff_duration + CHANNEL_BUFF_DURATION_ADD * tower_level\n\n\tif !caster is Tower:\n\t\treturn\n\n\tcaster.add_exp(1)\n\n\tif buff == null:\n\t\tbuff = channel_bt.apply(tower, tower, buff_level)\n\t\tbuff.user_int = 1\n\t\tbuff.set_displayed_stacks(1)\n\telse:\n\t\tvar reached_max_stacks: bool = buff.user_int >= CHANNEL_STACK_COUNT\n\t\tif reached_max_stacks:\n\t\t\treturn\n\n\t\tbuff.user_int += 1\n\t\tbuff.set_level(buff.get_level() + buff_level)\n\t\tbuff.set_displayed_stacks(buff.user_int)\n\n\tawait Utils.create_manual_timer(stack_duration, self).timeout\n\n\tif Utils.unit_is_valid(tower):\n\t\tbuff = tower.get_buff_of_type(channel_bt)\n\n\t\tif buff == null:\n\t\t\treturn\n\n\t\tif buff.user_int <= 1:\n\t\t\tbuff.remove_buff()\n\t\telse:\n\t\t\tbuff.user_int -= 1\n\t\t\tbuff.set_level(buff.get_level() - buff_level)\n\t\t\tbuff.set_displayed_stacks(buff.user_int)\n\n\nfunc on_autocast(event: Event):\n\tvar level: int = tower.get_level()\n\tvar buff: Buff = extract_bt.apply(tower, event.get_target(), level)\n\tvar extraction_count: int = EXTRACT_COUNT + EXTRACT_COUNT_ADD * level\n\tbuff.user_int = extraction_count\n\n\nfunc extract_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar exp_gain: float = _stats.extract_exp + buff.get_level() * _stats.extract_exp_add\n\tvar extract_count: int = buff.user_int\n\n\tif !tower.calc_chance(EXTRACT_CHANCE):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Extract Experience\")\n\n\tif extract_count > 0:\n\t\tevent.get_target().add_exp(exp_gain)\n\t\tbuff.user_int -= 1\n\telse:\n\t\tbuff.remove_buff()\n"
  },
  {
    "path": "src/towers/tower_behaviors/razorboar_thornweaver.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Quillboar Thornweaver\"=>\"Razorboar Thornweaver\"\n\n\nvar thornspray_pt: ProjectileType\nvar thorns_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {occasional_thornspray_chance = 0.12, occasional_thornspray_chance_add = 0.0015, double_chance = 0.05, triple_chance = 0.03},\n\t\t2: {occasional_thornspray_chance = 0.15, occasional_thornspray_chance_add = 0.0018, double_chance = 0.07, triple_chance = 0.05},\n\t\t3: {occasional_thornspray_chance = 0.18, occasional_thornspray_chance_add = 0.0021, double_chance = 0.09, triple_chance = 0.07},\n\t}\n\n\nconst QUILLSPRAY_STACKS_MAX: int = 40\nconst QUILLSPRAY_STACK_BONUS: float = 0.11\nconst QUILLSPRAY_DAMAGE_RATIO: float = 0.30\nconst QUILLSPRAY_DAMAGE_RATIO_ADD: float = 0.002\nconst QUILLSPRAY_DEBUFF_DURATION: float = 1.5\nconst QUILLSPRAY_RANGE: float = 800\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tthorns_bt = BuffType.new(\"thorns_bt\", QUILLSPRAY_DEBUFF_DURATION, 0, false, self)\n\tthorns_bt.set_buff_icon(\"res://resources/icons/generic_icons/polar_star.tres\")\n\tthorns_bt.set_buff_tooltip(tr(\"F7TS\"))\n\n\tthornspray_pt = ProjectileType.create(\"res://src/projectiles/projectile_visuals/quillspray_projectile.tscn\", 2, 1300, self)\n\tthornspray_pt.enable_homing(on_projectile_hit, 0)\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar chance: float = _stats.occasional_thornspray_chance + _stats.occasional_thornspray_chance_add * level\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Occasional Thornspray\")\n\n\tdo_thornspray_series()\n\n\nfunc on_autocast(_event: Event):\n\tdo_thornspray_series()\n\n\nfunc on_projectile_hit(_projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\t\n\tvar level: int = tower.get_level()\n\n\tvar active_buff: Buff = target.get_buff_of_type(thorns_bt)\n\n\tvar active_stacks: int\n\tif active_buff != null:\n\t\tactive_stacks = active_buff.user_int\n\telse:\n\t\tactive_stacks = 0\n\n\tvar thorns_multiplier: float = pow(1.0 + QUILLSPRAY_STACK_BONUS, active_stacks)\n\tvar damage_ratio: float = (QUILLSPRAY_DAMAGE_RATIO + QUILLSPRAY_DAMAGE_RATIO_ADD * level) * thorns_multiplier\n\tvar damage: float = damage_ratio * tower.get_current_attack_damage_with_bonus()\n\n\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\n\tvar new_stacks: int = min(active_stacks + 1, QUILLSPRAY_STACKS_MAX)\n\n#\tNOTE: weaker tier tower increases buff effect without\n#\trefreshing duration\n\tactive_buff = thorns_bt.apply(tower, target, 1)\n\tactive_buff.user_int = new_stacks\n\tactive_buff.set_displayed_stacks(new_stacks)\n\n\nfunc do_thornspray_series():\n\tvar level: int = tower.get_level()\n\n\tthornspray(1350)\n\n\tif level == 25:\n\t\tif tower.calc_chance(_stats.triple_chance):\n\t\t\tCombatLog.log_ability(tower, null, \"Tripple Thornspray\")\n\t\t\tthornspray(1500)\n\t\t\tthornspray(1700)\n\t\telse:\n\t\t\tCombatLog.log_ability(tower, null, \"Double Thornspray\")\n\t\t\tthornspray(1500)\n\telif level > 15:\n\t\tif tower.calc_chance(_stats.double_chance):\n\t\t\tCombatLog.log_ability(tower, null, \"Double Thornspray\")\n\t\t\tthornspray(1500)\n\n\nfunc thornspray(speed: float):\n\tvar creeps_in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), QUILLSPRAY_RANGE)\n\n\twhile true:\n\t\tvar creep: Unit = creeps_in_range.next()\n\n\t\tif creep == null:\n\t\t\tbreak\n\n\t\tvar projectile: Projectile = Projectile.create_from_unit_to_unit(thornspray_pt, tower, 1.0, 1.0, tower, creep, true, false, false)\n\t\tprojectile.set_projectile_scale(0.7)\n\t\tprojectile._speed = speed\n"
  },
  {
    "path": "src/towers/tower_behaviors/red_ball_lightning.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {shock_damage = 1200, shock_damage_add = 48, mod_spell_damage = 0.20, mod_spell_damage_add = 0.004},\n\t\t2: {shock_damage = 3500, shock_damage_add = 140, mod_spell_damage = 0.35, mod_spell_damage_add = 0.006},\n\t}\n\nconst SHOCK_CHANCE: float = 0.30\nconst SHOCK_CHANCE_ADD: float = 0.005\nconst SHOCK_CRIT_CHANCE: float = 0.10\nconst SHOCK_CRIT_DAMAGE: float = 0.60\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, _stats.mod_spell_damage, _stats.mod_spell_damage_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\taura_bt.set_buff_tooltip(tr(\"DG3B\"))\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar shock_chance: float = SHOCK_CHANCE + SHOCK_CHANCE_ADD * tower.get_level()\n\tvar shock_damage: float = _stats.shock_damage + _stats.shock_damage_add * tower.get_level()\n\tvar shock_crit_ratio: float = tower.calc_spell_crit(0.1, 0.6)\n\n\tif !tower.calc_chance(shock_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Lightning Shock\")\n\n\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, tower, creep)\n\tlightning.modulate = Color.RED\n\tlightning.set_lifetime(0.2)\n\n\ttower.do_spell_damage(creep, shock_damage, shock_crit_ratio)\n"
  },
  {
    "path": "src/towers/tower_behaviors/regenerating_well.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] changed autocast type\n# AC_TYPE_ALWAYS_BUFF->AC_TYPE_ALWAYS_IMMEDIATE because the\n# autocast is an AoE effect. Original script must have used\n# AC_TYPE_ALWAYS_BUFF by mistake.\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {replenish_mana = 0.10, replenish_mana_add = 0.004, mod_spell_dmg = 0.15, mod_spell_dmg_add = 0.006},\n\t\t2: {replenish_mana = 0.15, replenish_mana_add = 0.006, mod_spell_dmg = 0.20, mod_spell_dmg_add = 0.008},\n\t\t3: {replenish_mana = 0.20, replenish_mana_add = 0.008, mod_spell_dmg = 0.25, mod_spell_dmg_add = 0.010},\n\t}\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, _stats.mod_spell_dmg, _stats.mod_spell_dmg_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\taura_bt.set_buff_tooltip(tr(\"B1E6\"))\n\n\nfunc on_autocast(_event: Event):\n\tvar towers_in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 500)\n\tvar mana_gain_ratio: float = _stats.replenish_mana + _stats.replenish_mana_add * tower.get_level()\n\n\twhile true:\n\t\tvar target: Unit = towers_in_range.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tvar is_same_family: bool = target.get_family() == tower.get_family()\n\n\t\tvar replenish_mana: float\n\t\tif is_same_family:\n\t\t\treplenish_mana = target.get_overall_mana() * mana_gain_ratio * 0.5\n\t\telse:\n\t\t\treplenish_mana = target.get_overall_mana() * mana_gain_ratio\n\n\t\ttarget.add_mana(replenish_mana)\n"
  },
  {
    "path": "src/towers/tower_behaviors/rooted_chasm.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: The original script uses time_level_add value to\n# change duration of entangle based on tower tier. Don't\n# need to do this in youtd2, can directly define different\n# durations.\n\n\nvar entangle_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {entangle_duration = 1.50, base_entangle_dps = 120},\n\t\t2: {entangle_duration = 2.25, base_entangle_dps = 660},\n\t\t3: {entangle_duration = 3.00, base_entangle_dps = 1800},\n\t\t4: {entangle_duration = 3.75, base_entangle_dps = 4300},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tentangle_bt = CbStun.new(\"entangle_bt\", _stats.entangle_duration, 0.75, false, self)\n\tentangle_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\tentangle_bt.add_periodic_event(entangle_bt_damage, 1.0)\n\n\nfunc on_create(_preceding_tower: Tower):\n\t#\tbase entangle dps\n\ttower.user_int = _stats.base_entangle_dps\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(0.125 + tower.get_level() * 0.002):\n\t\treturn\n\n\tvar target: Creep = event.get_target()\n\n\tif target.get_size() < CreepSize.enm.BOSS && target.get_size() != CreepSize.enm.AIR:\n\t\tCombatLog.log_ability(tower, target, \"Entangle\")\n\t\t\n\t\tentangle_bt.apply(tower, target, 0)\n\n#\t\tNOTE: not sure what reorder() does. Tower script\n#\t\tworks correctly without this.\n#\t\ttarget.reorder()\n\n\nfunc entangle_bt_damage(event: Event):\n\tvar buff: Buff = event.get_buff()\n\n\tvar t = buff.get_caster()\n\tvar c: Creep = buff.get_buffed_unit()\n\tt.do_spell_damage(c, t.user_int + t.user_int * t.get_level() / 20, t.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/rotted_flashing_grave.gd",
    "content": "extends TowerBehavior\n\n# NOTE: modified this script because the original did a\n# bunch of unnecessary things.\n\n# NOTE: changed missile speed in csv for this tower.\n# 3000->9001. This tower uses \"lightning\" projectile visual\n# so slow speed looks weird because it makes the damage\n# delayed compared to the lightning visual.\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_attack(on_attack)\n\n\nfunc on_attack(_event: Event):\n\tvar iterator: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), tower.get_range())\n\tvar random_unit: Unit = iterator.next_random()\n\n\ttower.issue_target_order(random_unit)\n"
  },
  {
    "path": "src/towers/tower_behaviors/rowing_boat.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {plunder_amount = 0.3, mod_bounty = 0.10, mod_bounty_add = 0.005},\n\t\t2: {plunder_amount = 1.3, mod_bounty = 0.10, mod_bounty_add = 0.010},\n\t\t3: {plunder_amount = 2.4, mod_bounty = 0.15, mod_bounty_add = 0.010},\n\t\t4: {plunder_amount = 4.0, mod_bounty = 0.20, mod_bounty_add = 0.010},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tvar bounty_mod: Modifier = Modifier.new()\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n#\tSet by aura\n\tbounty_mod.add_modification(ModificationType.enm.MOD_BOUNTY_RECEIVED, _stats.mod_bounty, _stats.mod_bounty_add)\n\taura_bt.set_buff_modifier(bounty_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/gold_bar.tres\")\n\taura_bt.set_buff_tooltip(tr(\"KAMW\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar gold_plundered_label: String = tr(\"OMXK\")\n\tmultiboard.set_key(0, gold_plundered_label)\n\n\nfunc on_attack(_event: Event):\n# \tThe gold, that will be granted to the player on this attack \n\tvar gold_granted: float = _stats.plunder_amount\n#\tSet the statistics\n\ttower.user_real = tower.user_real + gold_granted\n\ttower.get_player().give_gold(gold_granted, tower, false, true)\n\n\nfunc on_create(preceding_tower: Tower):\n\tvar parent: Tower = preceding_tower\n\n# \tTotal gold, earned by this towers pirates ability \n\tif parent != null && parent.get_family() == tower.get_family():\n\t\ttower.user_real = parent.user_real\n\telse:\n\t\ttower.user_real = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar gold_plundered_text: String = Utils.format_float(tower.user_real, 2)\n\tmultiboard.set_value(0, gold_plundered_text)\n\t\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/ruined_wind_tower.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {item_rarity = Rarity.enm.COMMON},\n\t\t2: {item_rarity = Rarity.enm.UNCOMMON},\n\t\t3: {item_rarity = Rarity.enm.RARE},\n\t\t4: {item_rarity = Rarity.enm.UNIQUE},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc on_attack(_event: Event):\n\tvar itm: Item\n\tvar i: int = 1\n\n\tvar item_rarity: Rarity.enm = _stats.item_rarity\n\n\twhile true:\n\t\tif i > 6:\n\t\t\tbreak\n\n\t\titm = tower.get_held_item(i)\n\n\t\tif itm != null && itm.get_rarity() != item_rarity:\n\t\t\titm.drop()\n\t\t\titm.fly_to_stash(0.0)\n\n\t\ti = i + 1\n"
  },
  {
    "path": "src/towers/tower_behaviors/rundown_iron_sentry.gd",
    "content": "extends TowerBehavior\n\n\nvar alert_bt: BuffType\nvar trespasser_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {alert_duration = 5, armor_shred_chance = 0.40, armor_shred_amount = 3, armor_shred_amount_add = 0.10, awareness_duration = 5},\n\t\t2: {alert_duration = 10, armor_shred_chance = 0.50, armor_shred_amount = 4, armor_shred_amount_add = 0.15, awareness_duration = 8},\n\t\t3: {alert_duration = 15, armor_shred_chance = 0.60, armor_shred_amount = 5, armor_shred_amount_add = 0.20, awareness_duration = 12},\n\t}\n\nconst ARMOR_SHRED_STACKS_MAX: int = 5\nconst ALERT_MOD_DMG: float = 0.075\nconst ALERT_MOD_DMG_ADD: float = 0.005\nconst ALERT_RANGE: int = 500\nconst TRESSPASSER_RANGE: int = 925\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, TRESSPASSER_RANGE, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\talert_bt = BuffType.new(\"alert_bt\", 0, 0, true, self)\n\tvar alert_mod: Modifier = Modifier.new()\n\talert_mod.add_modification(ModificationType.enm.MOD_DAMAGE_BASE_PERC, ALERT_MOD_DMG, ALERT_MOD_DMG_ADD)\n\talert_bt.set_buff_modifier(alert_mod)\n\talert_bt.set_buff_icon(\"res://resources/icons/generic_icons/barbute.tres\")\n\talert_bt.set_buff_tooltip(tr(\"RILU\"))\n\n\ttrespasser_bt = BuffType.new(\"trespasser_bt\", -1, 0, false, self)\n\tvar trespasser_mod: Modifier = Modifier.new()\n\ttrespasser_mod.add_modification(ModificationType.enm.MOD_ARMOR, 0.0, -0.01)\n\ttrespasser_bt.set_buff_modifier(trespasser_mod)\n\ttrespasser_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\ttrespasser_bt.set_buff_tooltip(tr(\"G6KV\"))\n\n\nfunc on_unit_in_range(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar creep_size: CreepSize.enm = creep.get_size_including_challenge_sizes()\n\tvar level: int = tower.get_level()\n\tvar buff: Buff = creep.get_buff_of_type(trespasser_bt)\n\n\tvar buff_level: int = int((_stats.armor_shred_amount + _stats.armor_shred_amount_add * level) * 100)\n\tif buff != null:\n\t\tbuff_level = min(buff_level + buff.get_level(), buff_level * ARMOR_SHRED_STACKS_MAX)\n\n#\tNOTE: original script relies of sizes mapping to\n#\tspecific int's. Do this mapping here instead.\n\tvar size_multiplier_map: Dictionary = {\n\t\tCreepSize.enm.MASS: 1,\n\t\tCreepSize.enm.NORMAL: 3,\n\t\tCreepSize.enm.AIR: 4,\n\t\tCreepSize.enm.CHAMPION: 5,\n\t\tCreepSize.enm.CHALLENGE_MASS: 2,\n\t\tCreepSize.enm.BOSS: 6,\n\t\tCreepSize.enm.CHALLENGE_BOSS: 8,\n\t}\n\tvar size_multiplier: int = size_multiplier_map[creep_size]\n\n\tvar mod_damage_value: float = (0.05 + 0.001 * level) * size_multiplier\n\n\tvar alert_sizes: Array[CreepSize.enm] = [\n\t\tCreepSize.enm.AIR,\n\t\tCreepSize.enm.CHAMPION,\n\t\tCreepSize.enm.BOSS,\n\t\tCreepSize.enm.CHALLENGE_BOSS\n\t]\n\tvar size_is_big_enough_for_alert: bool = alert_sizes.has(creep_size)\n\n\tif tower.calc_chance(_stats.armor_shred_chance):\n\t\tvar trespasser_buff: Buff = trespasser_bt.apply(tower, creep, buff_level)\n\t\ttrespasser_buff.set_displayed_stacks(trespasser_buff.get_level())\n\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, mod_damage_value)\n\n\tif size_is_big_enough_for_alert:\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), ALERT_RANGE)\n\n\t\twhile true:\n\t\t\tvar next: Unit = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tvar alert_duration: float = _stats.alert_duration\n\t\t\talert_bt.apply_custom_timed(tower, next, 0, alert_duration)\n\n\tawait Utils.create_manual_timer(_stats.awareness_duration, self).timeout\n\n\tif Utils.unit_is_valid(tower):\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE_PERC, -mod_damage_value)\n"
  },
  {
    "path": "src/towers/tower_behaviors/sacred_altar.gd",
    "content": "extends TowerBehavior\n\n\nvar entangle_bt: BuffType\nvar aura_bt: BuffType\n\n\nfunc tower_init():\n\tentangle_bt = CbStun.new(\"entangle_bt\", 1.2, 0, false, self)\n\tentangle_bt.set_buff_icon(\"res://resources/icons/generic_icons/ophiucus.tres\")\n\tentangle_bt.add_periodic_event(entangle_bt_periodic, 1.0)\n\tentangle_bt.set_buff_tooltip(tr(\"VCJ3\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/holy_grail.tres\")\n\taura_bt.add_event_on_attack(aura_bt_on_attack)\n\taura_bt.set_buff_tooltip(tr(\"VWLB\"))\n\n\nfunc aura_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar target: Creep = event.get_target()\n\tvar entangle_chance: float = (0.10 + 0.002 * caster.get_level()) * buffed_tower.get_base_attack_speed()\n\tvar target_is_boss: bool = target.get_size() >= CreepSize.enm.BOSS\n\tvar target_is_air: bool = target.get_size() == CreepSize.enm.AIR\n\n\tif !caster.calc_chance(entangle_chance):\n\t\treturn\n\n\tif target_is_boss || target_is_air:\n\t\treturn\n\n\tCombatLog.log_ability(caster, target, \"Sacred Altar Entangle\")\n\n\tentangle_bt.apply(caster, target, caster.get_level())\n\n\nfunc entangle_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar damage: float = 700 + 35 * buff.get_level()\n\n\tcaster.do_spell_damage(creep, damage, caster.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/sacrificial_lamb.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: weird thing about Sacrifice ability. The description\n# says: \"...to boost the dps of a tower in 500 range by 30%\n# of its total damage for 6 seconds\". Is it 30% of total\n# damage of caster or target? According to original script,\n# it's 30% of caster so I reproduced the same behavior.\n# \n# But this behavior doesn't make sense. What's the point of\n# making caster lose 100% damage so that another tower will\n# get a bonus of 30% from caster's damage? Seems like a net\n# negative in all cases.\n# \n# Would make more sense if it was the other way. Then, if\n# this tower casts Sacrifice on a very powerful tower,\n# losing 100% of this tower's damage to gain 30% bonus to\n# very powerful tower could be a net win.\n\n\nvar sacrifice_boost_bt: BuffType\nvar sacrifice_fatigue_bt: BuffType\nvar bloodspill_boost_bt: BuffType\nvar bloodspill_fatigue_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {bloodspill_chance_add = 0.002, bloodspill_mod_attack_speed = 0.50, bloodspill_exp = 0.25, sacrifice_dmg_ratio = 0.30},\n\t\t2: {bloodspill_chance_add = 0.004, bloodspill_mod_attack_speed = 0.75, bloodspill_exp = 0.50, sacrifice_dmg_ratio = 0.45},\n\t}\n\nconst BLOODSPILL_DMG_LOSS: float = 1.0\nconst BLOODSPILL_MOD_ATTACKSPEED_ADD: float = 0.01\nconst BLOODSPILL_CHANCE: float = 0.15\nconst BLOODSPILL_RANGE: float = 200\nconst SACRIFICE_RANGE: float = 500\nconst SACRIFICE_DMG_RATIO_ADD: float = 0.006\nconst SACRIFICE_DMG_LOSS: float = 1.0\nconst BUFF_DURATION: float = 6\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tbloodspill_boost_bt = BuffType.new(\"bloodspill_boost_bt\", BUFF_DURATION, 0, true, self)\n\tvar dave_blood_target: Modifier = Modifier.new()\n\tdave_blood_target.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, BLOODSPILL_MOD_ATTACKSPEED_ADD)\n\tbloodspill_boost_bt.set_buff_modifier(dave_blood_target)\n\tbloodspill_boost_bt.set_buff_icon(\"res://resources/icons/generic_icons/sprint.tres\")\n\tbloodspill_boost_bt.set_buff_tooltip(tr(\"YX3K\"))\n\n\tbloodspill_fatigue_bt = BuffType.new(\"bloodspill_fatigue_bt\", BUFF_DURATION, 0, false, self)\n\tvar dave_blood_altar: Modifier = Modifier.new()\n\tdave_blood_altar.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -BLOODSPILL_DMG_LOSS, 0.0)\n\tbloodspill_fatigue_bt.set_buff_modifier(dave_blood_altar)\n\tbloodspill_fatigue_bt.set_buff_icon(\"res://resources/icons/generic_icons/bat_mask.tres\")\n\tbloodspill_fatigue_bt.set_buff_tooltip(tr(\"OOCC\"))\n\n\tsacrifice_boost_bt = BuffType.new(\"sacrifice_boost_bt\", BUFF_DURATION, 0, true, self)\n\tsacrifice_boost_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\tsacrifice_boost_bt.add_event_on_cleanup(dave_sacrifice_target_on_cleanup)\n\tsacrifice_boost_bt.set_buff_tooltip(tr(\"N984\"))\n\n\tsacrifice_fatigue_bt = BuffType.new(\"sacrifice_fatigue_bt\", BUFF_DURATION, 0, false, self)\n\tvar dave_sacrifice_altar: Modifier = Modifier.new()\n\tdave_sacrifice_altar.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -SACRIFICE_DMG_LOSS, 0.0)\n\tsacrifice_fatigue_bt.set_buff_modifier(dave_sacrifice_altar)\n\tsacrifice_fatigue_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\tsacrifice_fatigue_bt.set_buff_tooltip(tr(\"LW5F\"))\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar chance: float = BLOODSPILL_CHANCE + _stats.bloodspill_chance_add * level\n\tvar blood_altar_buff: Buff = tower.get_buff_of_type(bloodspill_fatigue_bt)\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), BLOODSPILL_RANGE)\n# \tNOTE: subtract 1 to exclude the tower itself\n\tvar num_towers: int = it.count() - 1\n\n\tif !Utils.rand_chance(Globals.synced_rng, chance):\n\t\treturn\n\n\tif blood_altar_buff != null:\n\t\treturn\n\t\n\tif num_towers == 0:\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Blood Spill\")\n\n\tEffect.create_simple_at_unit(\"res://src/effects/blood_splatter.tscn\", tower)\n\n\twhile true:\n\t\tvar target: Unit = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tif target != tower:\n\t\t\tvar buff_level: int = int((_stats.bloodspill_mod_attack_speed * 100 + level) / num_towers)\n\t\t\tbloodspill_boost_bt.apply(tower, target, buff_level)\n\n\tbloodspill_fatigue_bt.apply(tower, tower, level)\n\tvar exp_gain: float = _stats.bloodspill_exp * num_towers\n\ttower.add_exp(exp_gain)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Tower = event.get_target()\n\tvar same_family: bool = tower.get_family() == target.get_family()\n\tvar active_buff: Buff = target.get_buff_of_type(sacrifice_boost_bt)\n\n\tif same_family:\n\t\treturn\n\n\tif active_buff != null:\n\t\tsacrifice_boost_bt.apply(tower, target, 0)\n\telse:\n\t\tvar applied_buff: Buff = sacrifice_boost_bt.apply(tower, target, 0)\n\t\tvar sacrifice_dmg_ratio: float = _stats.sacrifice_dmg_ratio + SACRIFICE_DMG_RATIO_ADD * tower.get_level()\n\t\tvar mod_dps_add_value: float = tower.get_current_attack_damage_with_bonus() * sacrifice_dmg_ratio\n\t\tapplied_buff.user_real = mod_dps_add_value\n\t\ttarget.modify_property(ModificationType.enm.MOD_DPS_ADD, mod_dps_add_value)\n\n\tsacrifice_fatigue_bt.apply(tower, tower, tower.get_level())\n\n\nfunc dave_sacrifice_target_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar mod_dps_add_value: float = buff.user_real\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_DPS_ADD, -mod_dps_add_value)\n"
  },
  {
    "path": "src/towers/tower_behaviors/safirons_cold_grave.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"\"Sapphiron's Cold Grave\"=\"Safiron's Cold Grave\n\n\nvar liquid_ice_bt: BuffType\nvar shard_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tshard_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 300, 400, self)\n\tshard_pt.set_event_on_expiration(shard_pt_on_expiration)\n\tshard_pt.enable_collision(shard_pt_on_collide, 75, TargetType.new(TargetType.CREEPS), true)\n\n\tliquid_ice_bt = BuffType.new(\"liquid_ice_bt\", -1, 0, false, self)\n\tliquid_ice_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_dot.tres\")\n\tliquid_ice_bt.set_buff_tooltip(tr(\"MRU0\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tvar p: Projectile = Projectile.create_from_unit_to_unit(shard_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, target, false, true, false)\n\tvar splits_remaining: int = 4\n\tp.user_int = splits_remaining\n\n\nfunc shard_pt_on_expiration(p: Projectile):\n\tvar splits_remaining: int = p.user_int\n\tvar angle: float = p.get_direction()\n\n\tif splits_remaining > 0:\n\t\tsplits_remaining -= 1\n\t\tp.user_int = splits_remaining\n\t\tp = Projectile.create(shard_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), p.get_position_wc3(), angle + 15.0)\n\t\tp.user_int = splits_remaining\n\t\tp = Projectile.create(shard_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), p.get_position_wc3(), angle - 15.0)\n\t\tp.user_int = splits_remaining\n\n\nfunc shard_pt_on_collide(p: Projectile, target: Unit):\n\tvar caster: Unit = p.get_caster()\n\tvar buff: Buff = target.get_buff_of_type(liquid_ice_bt)\n\tvar dmg_from_ice_add: float = 0.15 + 0.004 * caster.get_level()\n\tvar damage: float = 2280 + 85 * caster.get_level()\n\n\tcaster.do_spell_damage(target, damage, caster.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", target)\n\ttarget.modify_property(ModificationType.enm.MOD_DMG_FROM_ICE, dmg_from_ice_add)\n\n\tif buff == null:\n\t\tbuff = liquid_ice_bt.apply(caster, target, 1)\n\t\tbuff.user_real = dmg_from_ice_add\n\telse:\n\t\tbuff.set_level(buff.get_level() + 1)\n\t\tbuff.user_real += dmg_from_ice_add\n\n\tbuff = target.get_buff_of_type(liquid_ice_bt)\n\tif buff != null:\n\t\tvar stack_count: int = roundi(buff.user_real * 100)\n\t\tbuff.set_displayed_stacks(stack_count)\n\n\t# NOTE: removed this floating text because it happens too often\n\t# var total_dmg_from_ice: float = buff.user_real\n\t# var floating_text: String = Utils.format_percent(total_dmg_from_ice, 0)\n\t# caster.get_player().display_floating_text(floating_text, target, Color8(255, 191, 255))\n"
  },
  {
    "path": "src/towers/tower_behaviors/scales.gd",
    "content": "extends TowerBehavior\n\n\nvar electrify_bt: BuffType\nvar lightning_st: SpellType\nvar multiboard: MultiboardValues\nvar lightmare_is_active: bool = false\nvar i_scale_level: int = 0\nvar i_scale_value: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage_for_electrify)\n\ttriggers.add_event_on_damage(on_damage_for_overcharge)\n\ttriggers.add_periodic_event(periodic, 0.33)\n\n\nfunc tower_init():\n\tlightning_st = SpellType.new(SpellType.Name.FORKED_LIGHTNING, 2.0, self)\n\tlightning_st.set_source_height(300.0)\n\tlightning_st.set_damage_event(mock_eye_glare_st_on_damage)\n\tlightning_st.data.forked_lightning.damage = 1.0\n\tlightning_st.data.forked_lightning.target_count = 3\n\n\telectrify_bt = BuffType.new(\"electrify_bt\", 5, 0, false, self)\n\telectrify_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\telectrify_bt.add_periodic_event(electrify_bt_periodic, 1.0)\n\telectrify_bt.set_buff_tooltip(tr(\"CO3N\"))\n\n\tmultiboard = MultiboardValues.new(3)\n\tvar spell_damage_bonus_label: String = tr(\"A9ZA\")\n\tvar spell_crit_damage_bonus_label: String = tr(\"KPO5\")\n\tvar spell_crit_chance_bonus_label: String = tr(\"AMJ9\")\n\tmultiboard.set_key(0, spell_damage_bonus_label)\n\tmultiboard.set_key(1, spell_crit_damage_bonus_label)\n\tmultiboard.set_key(2, spell_crit_chance_bonus_label)\n\n\nfunc on_create(_preceding: Tower):\n\ti_scale_level = tower.get_player().get_team().get_level()\n\n\nfunc on_attack(_event: Event):\n\tvar i: int = tower.get_player().get_team().get_level()\n\tvar i2: = i\n\n\tif i > i_scale_level:\n\t\ti -= i_scale_level\n\t\ti_scale_value += i\n\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, i / 60.0)\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, i / 60.0)\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, i / 800.0)\n\n\t\ti_scale_level = i2\n\n\nfunc on_damage_for_electrify(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar electrify_chance: float = 0.2 + 0.008 * level\n\n\tif !tower.calc_chance(electrify_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Electrify\")\n\telectrify_bt.apply(tower, target, level)\n\n\nfunc on_damage_for_overcharge(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tovercharge_damage(target, level)\n\n\nfunc periodic(_event: Event):\n\tif !lightmare_is_active:\n\t\treturn\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1500)\n\n\tvar next: Unit = it.next()\n\n\tif next != null:\n\t\tvar damage: float = 1300 + 52 * tower.get_level()\n\t\tlightning_st.target_cast_from_caster(tower, next, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc on_autocast(_event: Event):\n\tvar effect: int = Effect.create_animated(\"res://src/effects/cloud_of_fog_cycle.tscn\", Vector3(tower.get_x(), tower.get_y(), tower.get_z() + Constants.TILE_SIZE_WC3), 0)\n\tEffect.set_lifetime(effect, 10.0)\n\n\tlightmare_is_active = true\n\n\tawait Utils.create_manual_timer(10.0, self).timeout\n\n\tlightmare_is_active = false\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar spell_damage: String = Utils.format_percent(i_scale_value * 1.66 / 100, 2)\n\tvar spell_crit_damage: String = Utils.format_percent(i_scale_value * 1.66 / 100, 2)\n\tvar spell_crit_chance: String = Utils.format_percent(i_scale_value * 0.125 / 100, 2)\n\tmultiboard.set_value(0, spell_damage)\n\tmultiboard.set_value(1, spell_crit_damage)\n\tmultiboard.set_value(2, spell_crit_chance)\n\n\treturn multiboard\n\n\n# NOTE: \"overchargeA()\" in original script\nfunc mock_eye_glare_st_on_damage(event: Event, _dummy: SpellDummy):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tovercharge_damage(target, level)\n\n\nfunc overcharge_damage(target: Unit, level: int):\n\tvar i: int = 0\n\tvar damage: float = 900 + 36 * level\n\n\twhile true:\n\t\tvar target_health_ratio: float = target.get_health_ratio()\n\n\t\tif target_health_ratio <= 0.405:\n\t\t\tbreak\n\n\t\tvar overcharge_chance: float = 0.25 + 0.01 * level - 0.05 * i\n\n\t\tif !tower.calc_chance(overcharge_chance):\n\t\t\tbreak\n\n\t\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/holy_bolt.tscn\", target, Unit.BodyPart.CHEST)\n\t\tEffect.set_color(effect, Color.LIGHT_BLUE)\n\t\t\n\t\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus() )\n\n\t\ti += 1\n\n\n# NOTE: \"elec()\" in original script\nfunc electrify_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 225)\n\tvar damage: float = 900 + 36 * tower.get_level()\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\treturn\n\n\t\tif next != target:\n\t\t\ttower.do_spell_damage(next, damage, tower.calc_spell_crit_no_bonus())\n\t\t\tovercharge_damage(next, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/sea_turtle.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mana_per_attack = 64, mana_per_attack_add = 2.56},\n\t\t2: {mana_per_attack = 128, mana_per_attack_add = 5.12},\n\t\t3: {mana_per_attack = 192, mana_per_attack_add = 7.68},\n\t}\n\nconst MANA_LOSS_PER_SEC: float = 0.0175\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 1)\n\n\nfunc on_attack(_event: Event):\n\tvar mana_gain: float = max(_stats.mana_per_attack, (_stats.mana_per_attack + _stats.mana_per_attack_add * tower.get_level()) * tower.get_base_mana_regen_bonus_percent())\n\n\ttower.add_mana(mana_gain)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar damage: float = tower.get_mana()\n\ttower.do_attack_damage(creep, damage, tower.calc_attack_multicrit_no_bonus())\n\n\nfunc periodic(_event: Event):\n\tvar mana_loss: float = tower.get_mana() * MANA_LOSS_PER_SEC\n\ttower.subtract_mana(mana_loss, false)\n"
  },
  {
    "path": "src/towers/tower_behaviors/servant_of_the_twin_flames.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed bug where Twin Disciplines\n# gave 1% per stack for tier 2 tower, even though it's\n# supposed to be 2% according to ability description. Fixed\n# this bug by changing the level_add part of buff\n# modification to 0.02 for tier 2.\n# \n# Also fixed color of pulse effects. They were swapped (red\n# vs green).\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed small bug in original\n# script where \"Twin Disciplines\" would not trigger if\n# attack crit chance is exactly equal to spell crit chance.\n# Rare, but possible.\n\n# NOTE: green = attack damage\n# \t\tred = spell damage\n\n\nvar attack_bt: BuffType\nvar spell_bt: BuffType\nvar red_pt: ProjectileType\nvar green_pt: ProjectileType\n\nvar red_flame_count: int = 0\nvar green_flame_count: int = 0\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {flame_dmg_ratio = 0.65, flame_dmg_ratio_add = 0.005, pulse_dmg_ratio = 0.55, pulse_dmg_ratio_add = 0.005, twin_disciplines_crit = 0.01},\n\t\t2: {flame_dmg_ratio = 0.75, flame_dmg_ratio_add = 0.010, pulse_dmg_ratio = 0.75, pulse_dmg_ratio_add = 0.010, twin_disciplines_crit = 0.02},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tattack_bt = BuffType.new(\"attack_bt\", 7, 0, true, self)\n\tvar dave_physical_mod: Modifier = Modifier.new()\n\tdave_physical_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.0, _stats.twin_disciplines_crit)\n\tattack_bt.set_buff_modifier(dave_physical_mod)\n\tattack_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\tattack_bt.set_buff_tooltip(tr(\"GAL7\"))\n\n\tspell_bt = BuffType.new(\"spell_bt\", 7, 0, true, self)\n\tvar dave_spell_mod: Modifier = Modifier.new()\n\tdave_spell_mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, 0.0, _stats.twin_disciplines_crit)\n\tspell_bt.set_buff_modifier(dave_spell_mod)\n\tspell_bt.set_buff_icon(\"res://resources/icons/generic_icons/ankh.tres\")\n\tspell_bt.set_buff_tooltip(tr(\"VKU9\"))\n\n\tred_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\tred_pt.set_event_on_interpolation_finished(red_pt_on_hit)\n\n\tgreen_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\tgreen_pt.set_event_on_interpolation_finished(green_pt_on_hit)\n\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar attack_crit_chance: float = tower.get_prop_atk_crit_chance()\n\tvar spell_crit_chance: float = tower.get_spell_crit_chance()\n\tvar flame_count_for_pulse: int = get_flame_count_for_pulse()\n\tvar pulse_damage: float = get_pulse_damage()\n\n\tif tower.calc_chance(spell_crit_chance):\n\t\tCombatLog.log_ability(tower, target, \"Red Flame\")\n\n\t\tProjectile.create_bezier_interpolation_from_unit_to_unit(red_pt, tower, 1, 1, tower, target, 0, 0.3, 0, true)\n\t\tred_flame_count += 1\n\n\tif tower.calc_chance(attack_crit_chance):\n\t\tCombatLog.log_ability(tower, target, \"Green Flame\")\n\t\t\n\t\tProjectile.create_bezier_interpolation_from_unit_to_unit(green_pt, tower, 1, 1, tower, target, 0, -0.3, 0, true)\n\t\tgreen_flame_count += 1\n\n\tvar do_red_pulse: bool = red_flame_count >= flame_count_for_pulse\n\tvar do_green_pulse: bool = green_flame_count >= flame_count_for_pulse\n\n\tif do_red_pulse:\n\t\tCombatLog.log_ability(tower, null, \"Red Pulse\")\n\t\t\n\t\tred_flame_count = 0\n\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 900)\n\n\t\twhile true:\n\t\t\tvar creep: Unit = it.next()\n\n\t\t\tif creep == null:\n\t\t\t\tbreak\n\n\t\t\ttower.do_spell_damage(creep, pulse_damage, tower.calc_spell_crit_no_bonus())\n\t\t\tSFX.sfx_at_unit(SfxPaths.FIRE_BALL, creep)\n\n\t\t\tvar effect_target: int = Effect.create_simple_at_unit_attached(\"res://src/effects/immolation_damage.tscn\", creep, Unit.BodyPart.CHEST)\n\t\t\tEffect.set_color(effect_target, Color.RED)\n\n\t\t\tvar effect_caster: int = Effect.create_colored(\"res://src/effects/zombify_target.tscn\", Vector3(tower.get_x() - 48, tower.get_y() + 48, tower.get_z() + 80), 0.0, 1, Color.RED)\n\t\t\tEffect.set_lifetime(effect_caster, 0.5)\n\n\tif do_green_pulse:\n\t\tCombatLog.log_ability(tower, null, \"Green Pulse\")\n\t\t\n\t\tgreen_flame_count = 0\n\t\t\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 900)\n\n\t\twhile true:\n\t\t\tvar creep: Unit = it.next()\n\n\t\t\tif creep == null:\n\t\t\t\tbreak\n\n\t\t\ttower.do_attack_damage(creep, pulse_damage, tower.calc_attack_multicrit_no_bonus())\n\t\t\tSFX.sfx_at_unit(SfxPaths.FIRE_SPLASH, creep)\n\t\t\t\n\t\t\tvar effect_target: int = Effect.create_simple_at_unit_attached(\"res://src/effects/flame_strike_embers.tscn\", creep, Unit.BodyPart.CHEST)\n\t\t\tEffect.set_color(effect_target, Color.GREEN)\n\n\t\t\tvar effect_caster: int = Effect.create_colored(\"res://src/effects/zombify_target.tscn\", Vector3(tower.get_x() + 48, tower.get_y() + 48, tower.get_z() + 80), 0.0, 1, Color.GREEN)\n\t\t\tEffect.set_lifetime(effect_caster, 0.5)\n\n\nfunc on_damage(event: Event):\n\tif !event.is_attack_damage_critical():\n\t\treturn\n\n\tvar physical_buff: Buff = tower.get_buff_of_type(attack_bt)\n\tvar spell_buff: Buff = tower.get_buff_of_type(spell_bt)\n\tvar attack_crit_chance: float = tower.get_prop_atk_crit_chance()\n\tvar spell_crit_chance: float = tower.get_spell_crit_chance()\n\n\tvar physical_buff_level: int\n\tif physical_buff != null:\n\t\tphysical_buff_level = physical_buff.get_level()\n\telse:\n\t\tphysical_buff_level = 0\n\n\tvar spell_buff_level: int\n\tif spell_buff != null:\n\t\tspell_buff_level = spell_buff.get_level()\n\telse:\n\t\tspell_buff_level = 0\n\n\tif attack_crit_chance <= spell_crit_chance || spell_buff_level == 10:\n\t\tif physical_buff == null:\n\t\t\tattack_bt.apply(tower, tower, 1)\n\t\telse:\n\t\t\tvar new_buff_level: int = min(physical_buff_level + 1, 10)\n\t\t\tattack_bt.apply(tower, tower, new_buff_level)\n\n\t\tphysical_buff = tower.get_buff_of_type(attack_bt)\n\t\tphysical_buff.set_displayed_stacks(physical_buff.get_level())\n\telif attack_crit_chance > spell_crit_chance || physical_buff_level == 10:\n\t\tif spell_buff == null:\n\t\t\tspell_bt.apply(tower, tower, 1)\n\t\telse:\n\t\t\tvar new_buff_level: int = min(spell_buff_level + 1, 10)\n\t\t\tspell_bt.apply(tower, tower, new_buff_level)\n\n\t\tspell_buff = tower.get_buff_of_type(spell_bt)\n\t\tspell_buff.set_displayed_stacks(spell_buff.get_level())\n\n\nfunc red_pt_on_hit(_projectile: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar damage: float = get_flame_damage()\n\ttower.do_attack_damage(creep, damage, tower.calc_attack_multicrit_no_bonus())\n\n\nfunc green_pt_on_hit(_projectile: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar damage: float = get_flame_damage()\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc get_flame_count_for_pulse() -> int:\n\tvar flame_count: int\n\tif tower.get_level() < 15:\n\t\tflame_count = 8\n\telif tower.get_level() < 25:\n\t\tflame_count = 7\n\telse:\n#\t\timplicit \"if tower.get_level() == 25\"\n\t\tflame_count = 6\n\n\treturn flame_count\n\n\nfunc get_flame_damage() -> float:\n\tvar level: int = tower.get_level()\n\tvar current_attack_damage: float = tower.get_current_attack_damage_with_bonus()\n\tvar damage_ratio: float = _stats.flame_dmg_ratio + _stats.flame_dmg_ratio_add * level\n\tvar damage: float = current_attack_damage * damage_ratio\n\n\treturn damage\n\n\nfunc get_pulse_damage() -> float:\n\tvar level: int = tower.get_level()\n\tvar current_attack_damage: float = tower.get_current_attack_damage_with_bonus()\n\tvar damage_ratio: float = _stats.pulse_dmg_ratio + _stats.pulse_dmg_ratio_add * level\n\tvar damage: float = current_attack_damage * damage_ratio\n\n\treturn damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/sewer_connection.gd",
    "content": "extends TowerBehavior\n\n\nvar toxic_bt: BuffType\n\n\n# NOTE: vapor damage stat is multiplied by 10 and divided by\n# 10 later, idk why.\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {vapor_damage = 2000, vapor_damage_add = 80},\n\t\t2: {vapor_damage = 6000, vapor_damage_add = 240},\n\t\t3: {vapor_damage = 12000, vapor_damage_add = 480},\n\t\t4: {vapor_damage = 22000, vapor_damage_add = 880},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc D1000_Toxic_Damage(event: Event):\n\tvar b: Buff = event.get_buff()\n\tb.get_caster().do_spell_damage(b.get_buffed_unit(), b.get_level() / 10, b.get_caster().calc_spell_crit_no_bonus())\n\n\nfunc tower_init():\n\ttoxic_bt = BuffType.new(\"toxic_bt\", 10, 0, false, self)\n\ttoxic_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\ttoxic_bt.add_periodic_event(D1000_Toxic_Damage, 1)\n\ttoxic_bt.set_buff_tooltip(tr(\"JMRY\"))\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(0.3):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Toxic Vapor\")\n\n\ttoxic_bt.apply(tower, event.get_target(), int(tower.get_level() * _stats.vapor_damage_add + _stats.vapor_damage))\n"
  },
  {
    "path": "src/towers/tower_behaviors/shadow.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original script uses a built-in \"laser\" ability. Had\n# to re-implement it here using a periodic event and\n# lightning visual.\n\n# NOTE: added display of DPS for Dark Shroud ability in\n# tower details.\n\n\nvar multiboard: MultiboardValues\nvar aura_bt: BuffType\nvar orb_pt: ProjectileType\nvar lesser_orb_pt: ProjectileType\nvar _tower_creation_time: float = 0.0\nvar _dark_shroud_damage_dealt: float = 0.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/alien_skull.tres\")\n\taura_bt.set_buff_tooltip(tr(\"ETJO\"))\n\taura_bt.add_event_on_damage(aura_bt_on_damage)\n\n\torb_pt = ProjectileType.create(\"path_to_projectile_sprite\", 8, 200, self)\n\torb_pt.enable_periodic(orb_pt_periodic, 1.0)\n\n\tlesser_orb_pt = ProjectileType.create(\"path_to_projectile_sprite\", 3, 0, self)\n\tlesser_orb_pt.enable_periodic(lesser_orb_pt_periodic, 1.0)\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar dark_shroud_dps_label: String = tr(\"BTFP\")\n\tmultiboard.set_key(0, dark_shroud_dps_label)\n\n\nfunc on_create(_preceding: Tower):\n\t_tower_creation_time = Utils.get_time()\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar tower_lifetime: float = Utils.get_time() - _tower_creation_time\n\tvar dark_shroud_dps: float = Utils.divide_safe(_dark_shroud_damage_dealt, tower_lifetime)\n\tvar dark_shroud_dps_string: String = Utils.format_float(dark_shroud_dps, 0)\n\tmultiboard.set_value(0, dark_shroud_dps_string)\n\n\treturn multiboard\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar projectile_count: int = 3 + level / 5\n\tvar x: float = tower.get_x()\n\tvar y: float = tower.get_y()\n\tvar damage_ratio: float = tower.get_current_attack_damage_with_bonus() * (0.05 + 0.002 * level)\n\n\tvar dark_orbs_chance: float = 0.20\n\n\tif !tower.calc_chance(dark_orbs_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Dark Orbs\")\n\n\tfor i in range(0, projectile_count):\n\t\tvar facing: float = i * 360.0 / projectile_count\n\t\tvar p: Projectile = Projectile.create(orb_pt, tower, damage_ratio, tower.calc_spell_crit_no_bonus(), Vector3(x, y, 80.0), facing)\n\t\tp.set_projectile_scale(1.75)\n\n\nfunc on_kill(event: Event):\n\tvar level: int = tower.get_level()\n\tvar creep: Creep = event.get_target()\n\tvar x: float = creep.get_x()\n\tvar y: float = creep.get_y()\n\tvar damage_ratio: float = tower.get_current_attack_damage_with_bonus() * (0.03 + 0.0012 * level)\n\tvar p: Projectile = Projectile.create(lesser_orb_pt, tower, damage_ratio, tower.calc_spell_crit_no_bonus(), Vector3(x, y, 80.0), 0)\n\tp.set_projectile_scale(1.25)\n\n\nfunc aura_bt_on_damage(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar target: Unit = event.get_target()\n\tvar damage: float = event.damage * (0.10 + 0.005 * caster.get_level())\n\n\t_dark_shroud_damage_dealt += damage\n\n\tevent.damage *= 0.9\n\n\tcaster.do_custom_attack_damage(target, damage, 1, AttackType.enm.DECAY)\n\n\nfunc orb_pt_periodic(p: Projectile):\n\torb_pt_periodic_generic(p)\n\n\nfunc lesser_orb_pt_periodic(p: Projectile):\n\torb_pt_periodic_generic(p)\n\n\nfunc orb_pt_periodic_generic(p: Projectile):\n\tvar caster: Unit = p.get_caster()\n\tvar it: Iterate = Iterate.over_units_in_range_of(caster, TargetType.new(TargetType.CREEPS), Vector2(p.get_x(), p.get_y()), 450)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar start_pos: Vector3 = Vector3(p.get_x(), p.get_y(), 0)\n\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_point_to_unit(InterpolatedSprite.LIGHTNING, start_pos, next)\n\t\tlightning.modulate = Color.PURPLE\n\t\tlightning.set_lifetime(0.1)\n\n\t\tp.do_spell_damage(next, 1.0)\n\n\t\tvar effect: int = Effect.create_simple_at_unit(\"res://src/effects/zombify_target.tscn\", next)\n\t\tEffect.set_color(effect, Color.PURPLE)\n"
  },
  {
    "path": "src/towers/tower_behaviors/shaman.gd",
    "content": "extends TowerBehavior\n\n\nvar bloodlust_bt: BuffType\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {bloodlust_crit_damage = 0.45, bloodlust_crit_damage_add = 0.004, bloodlust_attack_speed = 0.15, bloodlust_attack_speed_add = 0.002, bloody_experience_range = 250, bloody_experience_level_cap = 10},\n\t\t2: {bloodlust_crit_damage = 0.55, bloodlust_crit_damage_add = 0.006, bloodlust_attack_speed = 0.20, bloodlust_attack_speed_add = 0.003, bloody_experience_range = 300, bloody_experience_level_cap = 15},\n\t\t3: {bloodlust_crit_damage = 0.65, bloodlust_crit_damage_add = 0.008, bloodlust_attack_speed = 0.25, bloodlust_attack_speed_add = 0.004, bloody_experience_range = 350, bloody_experience_level_cap = 20},\n\t}\n\nconst BLOODLUST_DURATION: float = 5.0\nconst BLOODLUST_DURATION_ADD: float = 0.12\nconst BLOODY_EXPERIENCE_EXP_GAIN: float = 1\n\n\nfunc tower_init():\n\tbloodlust_bt = BuffType.new(\"bloodlust_bt\", BLOODLUST_DURATION, BLOODLUST_DURATION_ADD, true, self)\n\tvar bloodlust_mod: Modifier = Modifier.new()\n\tbloodlust_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, _stats.bloodlust_attack_speed, _stats.bloodlust_attack_speed_add)\n\tbloodlust_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, _stats.bloodlust_crit_damage, _stats.bloodlust_crit_damage_add)\n\tbloodlust_bt.set_buff_icon(\"res://resources/icons/generic_icons/moebius_trefoil.tres\")\n\tbloodlust_bt.set_buff_modifier(bloodlust_mod)\n\tbloodlust_bt.set_buff_tooltip(tr(\"NSMT\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.add_event_on_damage(bloody_exp_aura_on_damage)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/gold_bar.tres\")\n\taura_bt.set_buff_tooltip(tr(\"UFI6\"))\n\n\nfunc on_autocast(event: Event):\n\tvar level: int = tower.get_level()\n\n\tbloodlust_bt.apply(tower, event.get_target(), level)\n\n\nfunc bloody_exp_aura_on_damage(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar max_level_for_gain: int = _stats.bloody_experience_level_cap + caster.get_level() / 5\n\n\tif event.get_number_of_crits() > 0 && (buffed_tower.get_level() < max_level_for_gain || buffed_tower == caster):\n\t\tvar exp_gained: float = BLOODY_EXPERIENCE_EXP_GAIN * buffed_tower.get_base_attack_speed() * (800.0 / buffed_tower.get_base_range())\n\t\tbuffed_tower.add_exp(exp_gained)\n"
  },
  {
    "path": "src/towers/tower_behaviors/shard_of_souls.gd",
    "content": "class_name ShardofSouls1 extends TowerBehavior\n\n\n# NOTE: original script uses linked list to track which\n# creeps are affected. I changed it to assign id to each\n# linked group and check for all units in game if they have\n# buff with same id.\n\n# NOTE: it is weird that autocast type is\n# AC_TYPE_ALWAYS_BUFF but it needs to be this way. The\n# on_autocast() uses the target, so IMMEDIATE type wouldn't\n# work because it has no target. Also, ALWAYS needs to be\n# used instead of OFFENSIVE because this tower doesn't\n# attack so it never triggers AC_TYPE_OFFENSIVE_BUFF.\n\n\nstatic var soul_link_id_max: int = 0\n\n\nvar soul_link_bt: BuffType\nvar is_soul_link_damage: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {link_damage_ratio = 0.125, link_damage_ratio_add = 0.003, link_distance = 600},\n\t\t2: {link_damage_ratio = 0.15, link_damage_ratio_add = 0.003, link_distance = 700},\n\t}\n\nconst SOUL_LINK_DURATION: float = 2.5\nconst SOUL_LINK_COUNT: int = 3\nconst SOUL_CONSUMPTION_EXP_GAIN: int = 1\n\n\nfunc tower_init():\n\tsoul_link_bt = BuffType.new(\"soul_link_bt\", SOUL_LINK_DURATION, 0, false, self)\n\tsoul_link_bt.add_event_on_damaged(soul_link_on_damaged)\n\tsoul_link_bt.add_event_on_death(soul_link_on_death)\n\tsoul_link_bt.set_buff_icon(\"res://resources/icons/generic_icons/aquarius.tres\")\n\tsoul_link_bt.set_buff_tooltip(tr(\"LRFT\"))\n\n\nfunc on_autocast(event: Event):\n\tvar level: int = tower.get_level()\n\tvar main_target: Unit = event.get_target()\n\tvar current_target: Unit = event.get_target()\n\tvar counter: int = 0\n\tvar target_list: Array[Unit] = []\n\n\tvar max_targets: int = SOUL_LINK_COUNT\n\tif level == 25:\n\t\tmax_targets += 2\n\telif level >= 15:\n\t\tmax_targets += 1\n\n\tif current_target.get_buff_of_type(soul_link_bt) == null:\n\t\ttarget_list.append(current_target)\n\t\tcounter += 1\n\telse:\n\t\treturn\n\n\twhile true:\n\t\tif counter == max_targets:\n\t\t\tbreak\n\n\t\tvar creeps_in_range: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), current_target, _stats.link_distance)\n\t\t\n\t\tvar next: Unit = null\n\n\t\twhile true:\n\t\t\tnext = creeps_in_range.next()\n\n\t\t\tif next == null || next.get_buff_of_type(soul_link_bt) == null:\n\t\t\t\tbreak\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\ttarget_list.append(next)\n\t\tcurrent_target = next\n\t\tcounter += 1\n\n\tvar soul_link_id: int = ShardofSouls1.soul_link_id_max\n\tShardofSouls1.soul_link_id_max += 1\n\n\tfor target in target_list:\n\t\tvar buff: Buff = soul_link_bt.apply(tower, target, level)\n\t\tbuff.user_int = soul_link_id\n\n\t\tif target != main_target:\n\t\t\tvar lightning: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_unit(InterpolatedSprite.LIGHTNING, target, main_target)\n\t\t\tlightning.modulate = Color.PURPLE\n\t\t\tlightning.set_lifetime(0.4)\n\n\nfunc soul_link_on_damaged(event: Event):\n#\tStop infinite recursion\n\tif is_soul_link_damage:\n\t\treturn\n\n\tvar damage_source: Tower = event.get_target()\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tvar damage: float = event.damage * (_stats.link_damage_ratio + _stats.link_damage_ratio_add * caster.get_level())\n\tif event.is_spell_damage():\n\t\tdamage /= damage_source.get_prop_spell_damage_dealt()\n\n\tvar target_list: Array[Unit] = []\n\n\tvar creeps_in_range: Iterate = Iterate.over_units_in_range_of_unit(caster, TargetType.new(TargetType.CREEPS), buff.get_buffed_unit(), 10000)\n\n\tCombatLog.log_ability(caster, null, \"Soul Link share damage\")\n\n\twhile creeps_in_range.count() > 0:\n\t\tvar creep: Unit = creeps_in_range.next()\n\t\tvar creep_buff: Buff = creep.get_buff_of_type(soul_link_bt)\n\n\t\tif creep_buff == null:\n\t\t\tcontinue\n\n\t\tvar same_link: bool = buff.user_int == creep_buff.user_int\n\n\t\tif same_link:\n\t\t\ttarget_list.append(creep)\n\n\n\tis_soul_link_damage = true\n\tfor target in target_list:\n\t\tif event.is_spell_damage():\n\t\t\tdamage_source.do_spell_damage(target, damage, 1)\n\t\telse:\n\t\t\tdamage_source.do_attack_damage(target, damage, 1)\n\tis_soul_link_damage = false\n\n\nfunc soul_link_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Unit = buff.get_caster()\n\tCombatLog.log_ability(caster, null, \"Soul Consumption\")\n\tcaster.add_exp(SOUL_CONSUMPTION_EXP_GAIN)\n"
  },
  {
    "path": "src/towers/tower_behaviors/silver_knight.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {transmute_chance = 0.035, transmute_gold = 6, gold_greed_value = 16},\n\t\t2: {transmute_chance = 0.050, transmute_gold = 18, gold_greed_value = 44},\n\t}\n\nconst TRANSMUTE_CHANCE_ADD: float = 0.0004\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar gold_greed_damage_label: String = tr(\"DUIY\")\n\tmultiboard.set_key(0, gold_greed_damage_label)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar transmute_chance: float = _stats.transmute_chance + TRANSMUTE_CHANCE_ADD * tower.get_level()\n\tvar gold_greed_damage: float = get_current_gold_greed_damage()\n\n\tif creep.is_immune():\n\t\treturn\n\n\tif creep.get_size() < CreepSize.enm.CHAMPION && tower.calc_chance(transmute_chance):\n\t\tCombatLog.log_ability(tower, creep, \"Transmute\")\n\n\t\ttower.kill_instantly(creep)\n\t\ttower.get_player().give_gold(_stats.transmute_gold, tower, true, true)\n\telse:\n\t\ttower.do_spell_damage(creep, gold_greed_damage, tower.calc_spell_crit_no_bonus())\n\t\tvar gold_greed_text: String = str(int(tower.get_prop_spell_damage_dealt() * gold_greed_damage))\n\t\ttower.get_player().display_floating_text_x(gold_greed_text, creep, Color8(255, 200, 0, 255), 0.05, 0.0, 2.0)\n\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar gold_greed_damage: float = get_current_gold_greed_damage()\t\n\tvar gold_greed_damage_string: String = Utils.format_float(roundf(gold_greed_damage), 2)\n\tmultiboard.set_value(0, gold_greed_damage_string)\n\n\treturn multiboard\n\n\nfunc get_current_gold_greed_damage() -> float:\n\tvar current_gold: float = tower.get_player().get_gold()\n\tvar damage: float = _stats.gold_greed_value * pow(current_gold, 0.5)\n\n\treturn damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/skink.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: removed check for validity of poison caster. It's\n# not needed because in youtd2, buffs get automatically\n# removed when caster becomes invalid.\n\n\nvar poison_skin_bt: BuffType\nvar poison_bt: BuffType\n\nconst POISON_DURATION: float = 5.0\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {dmg = 3, dmg_add = 0.12},\n\t\t2: {dmg = 10, dmg_add = 0.4},\n\t\t3: {dmg = 30, dmg_add = 1.2},\n\t\t4: {dmg = 76.5, dmg_add = 3.06},\n\t\t5: {dmg = 127.5, dmg_add = 5.1},\n\t}\n\n\nfunc poison_skin_bt_on_attack(event: Event):\n\tvar poisonskin_buff: Buff = event.get_buff()\n\n\tvar skink: Tower = poisonskin_buff.get_caster()\n\tvar level: int = skink.get_level()\n\tvar buffed_tower: Tower = poisonskin_buff.get_buffed_unit()\n\tvar target: Unit = event.get_target()\n\n\tvar active_buff: Buff = target.get_buff_of_type(poison_bt)\n\n\tvar active_stacks: int = 0\n\tvar active_damage: float = 0\n\tif active_buff != null:\n\t\tactive_stacks = active_buff.user_int\n\t\tactive_damage = active_buff.user_real\n\n\tvar new_stacks: int = active_stacks + 1\n\tvar attack_speed_and_range_adjustment: float = buffed_tower.get_current_attack_speed() / (buffed_tower.get_base_range() / 800.0)\n\tvar added_damage: float = (_stats.dmg + _stats.dmg_add * level) * attack_speed_and_range_adjustment\n\tvar new_damage: float = active_damage + added_damage\n\n#\tNOTE: weaker tier tower increases buff effect without\n#\trefreshing duration\n\tactive_buff = poison_bt.apply(skink, target, 1)\n\tactive_buff.user_int = new_stacks\n\tactive_buff.set_displayed_stacks(new_stacks)\n\tactive_buff.user_real = new_damage\n\n\nfunc poison_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar damage: float = buff.user_real\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/chimaera_acid.tscn\", tower, Unit.BodyPart.HEAD)\n\n\nfunc tower_init():\n\tpoison_skin_bt = BuffType.create_aura_effect_type(\"poison_skin_bt\", true, self)\n\tpoison_skin_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tpoison_skin_bt.add_event_on_attack(poison_skin_bt_on_attack)\n\tpoison_skin_bt.set_buff_tooltip(tr(\"Z9Z7\"))\n\n\tpoison_bt = BuffType.new(\"poison_bt\", POISON_DURATION, 0.0, false, self)\n\tpoison_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tpoison_bt.add_periodic_event(poison_bt_periodic, 1.0)\n\tpoison_bt.set_buff_tooltip(tr(\"VS62\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_bug_nest.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {bug_dmg = 6, production_for_decrease = 12},\n\t\t2: {bug_dmg = 12, production_for_decrease = 10},\n\t\t3: {bug_dmg = 20, production_for_decrease = 8},\n\t\t4: {bug_dmg = 30, production_for_decrease = 6},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc on_kill(_event: Event):\n\tCombatLog.log_ability(tower, null, \"Create Bug #%d\" % (tower.user_int + 1))\n\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE, max(_stats.bug_dmg - tower.user_int / _stats.production_for_decrease, 1))\n\ttower.user_int = tower.user_int + 1\n\n\nfunc on_create(preceding_tower: Tower):\n\tvar prev: Tower = preceding_tower\n\tvar N: int\n\tvar mults: int\n\n\tif prev != null:\n\t\tif prev.get_family() == tower.get_family():\n\t\t\ttower.user_int = prev.user_int\n\t\telse:\n\t\t\ttower.user_int = int(prev.get_kills() * 0.6)\n\n\t\tmults = tower.user_int / _stats.production_for_decrease\n\n\t\tif mults >= _stats.bug_dmg:\n\t\t\tmults = _stats.bug_dmg - 1\n\n\t\tN = mults * _stats.production_for_decrease\n\t\tN = int((_stats.bug_dmg + 0.5 - mults / 2.0) * N) + (tower.user_int - N) * (_stats.bug_dmg - mults)\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_BASE, N)\n\telse:\n\t\ttower.user_int = 0\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_fire_sprayer.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {miss_chance_add = 0.008},\n\t\t2: {miss_chance_add = 0.009},\n\t\t3: {miss_chance_add = 0.010},\n\t\t4: {miss_chance_add = 0.011},\n\t\t5: {miss_chance_add = 0.012},\n\t\t6: {miss_chance_add = 0.013},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tif tower.calc_bad_chance(0.33 - _stats.miss_chance_add * tower.get_level()):\n\t\tevent.damage = 0\n\t\ttower.get_player().display_floating_text_x(tr(\"FLOATING_TEXT_MISS\"), tower, Color8(255, 0, 0, 255), 0.05, 0.0, 2.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_frost_fire.gd",
    "content": "extends TowerBehavior\n\n# NOTE: some stats are multiplied by 1000\n\nvar slow_bt: BuffType\n\n\nconst SLOW_DURATION: float = 4.0\nconst SLOW_CHILL_RADIUS: float = 250\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {dmg_to_undead_add = 0.002, aoe_damage = 50, aoe_damage_add = 2, slow_value = 0.05, slow_value_add = 0.002, slow_duration_add = 0.02},\n\t\t2: {dmg_to_undead_add = 0.004, aoe_damage = 200, aoe_damage_add = 8, slow_value = 0.06, slow_value_add = 0.004, slow_duration_add = 0.04},\n\t\t3: {dmg_to_undead_add = 0.006, aoe_damage = 550, aoe_damage_add = 24, slow_value = 0.08, slow_value_add = 0.006, slow_duration_add = 0.06},\n\t\t4: {dmg_to_undead_add = 0.008, aoe_damage = 1000, aoe_damage_add = 48, slow_value = 0.10, slow_value_add = 0.008, slow_duration_add = 0.08},\n\t\t5: {dmg_to_undead_add = 0.010, aoe_damage = 1800, aoe_damage_add = 96, slow_value = 0.12, slow_value_add = 0.010, slow_duration_add = 0.10},\n\t}\n\n\t\nfunc tower_init():\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.slow_value, -_stats.slow_value_add)\n\tslow_bt = BuffType.new(\"slow_bt\", SLOW_DURATION, _stats.slow_duration_add, false, self)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_tooltip(tr(\"NIT5\"))\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, SLOW_CHILL_RADIUS)\n\n\tvar spelldmg: float = _stats.aoe_damage + _stats.aoe_damage_add * level\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tslow_bt.apply(tower, next, level)\n\t\ttower.do_spell_damage(next, spelldmg, tower.calc_spell_crit_no_bonus())\n\n\tEffect.create_simple_at_unit(\"res://src/effects/raise_skeleton.tscn\", target)\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_ice_mine.gd",
    "content": "extends TowerBehavior\n\n\nvar slow_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {slow_value = 0.075, slow_duration = 2.0, aoe_range = 250, aoe_damage = 150, aoe_damage_add = 7.5},\n\t\t2: {slow_value = 0.090, slow_duration = 3.0, aoe_range = 300, aoe_damage = 500, aoe_damage_add = 25},\n\t\t3: {slow_value = 0.110, slow_duration = 4.0, aoe_range = 350, aoe_damage = 1250, aoe_damage_add = 62.5},\n\t\t4: {slow_value = 0.140, slow_duration = 5.0, aoe_range = 400, aoe_damage = 2500, aoe_damage_add = 125},\n\t}\n\n\nconst NOVA_CHANCE: float = 0.20\nconst NOVA_CHANCE_ADD: float = 0.004\nconst EXTRA_CRIT_CHANCE: float = 0.30\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\n\tslow_bt = BuffType.new(\"slow_bt\", _stats.slow_duration, 0.0, false, self)\n\tm.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.slow_value, 0.0)\n\tslow_bt.set_buff_modifier(m)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"SW2E\"))\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar nova_chance: float = NOVA_CHANCE + NOVA_CHANCE_ADD * level\n\n\tif !tower.calc_chance(nova_chance):\n\t\treturn\n\n\tvar target: Unit = event.get_target()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, _stats.aoe_range)\n\tvar next: Unit\n\n\tCombatLog.log_ability(tower, target, \"Ice Nova\")\n\n\twhile true:\n\t\tnext = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tslow_bt.apply(tower, next, level)\n\n\tvar damage: float = _stats.aoe_damage + _stats.aoe_damage_add * tower.get_level()\n\ttower.do_spell_damage_aoe_unit(target, _stats.aoe_range, damage, tower.calc_spell_crit(EXTRA_CRIT_CHANCE, 0.0), 0)\n\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", target)\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_light.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Commented out sections\n# relevant to invisibility because invisible waves are\n# not implemented.\n\n\nvar holy_weak_bt: BuffType\nvar magical_sight_bt: BuffType\n\n\n# NOTE: mod_value and mod_value_add are multiplied by 1000,\n# leaving as in original\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {magical_sight_range = 650, vuln = 0.05, vuln_add = 0.002, duration = 3, duration_add = 0.12},\n\t\t2: {magical_sight_range = 700, vuln = 0.10, vuln_add = 0.004, duration = 3, duration_add = 0.16},\n\t\t3: {magical_sight_range = 750, vuln = 0.15, vuln_add = 0.006, duration = 4, duration_add = 0.16},\n\t\t4: {magical_sight_range = 800, vuln = 0.20, vuln_add = 0.008, duration = 4, duration_add = 0.20},\n\t\t5: {magical_sight_range = 850, vuln = 0.30, vuln_add = 0.010, duration = 5, duration_add = 0.20},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar light_mod: Modifier = Modifier.new()\n\tholy_weak_bt = BuffType.new(\"holy_weak_bt\", _stats.duration, _stats.duration_add, false, self)\n\tlight_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, _stats.vuln, _stats.vuln_add)\n\tlight_mod.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, _stats.vuln, _stats.vuln_add)\n\tholy_weak_bt.set_buff_modifier(light_mod)\n\tholy_weak_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\tholy_weak_bt.set_buff_tooltip(tr(\"Y0VY\"))\n\n\nfunc on_damage(event: Event):\n\tvar creep: Creep = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tif creep.get_category() == CreepCategory.enm.UNDEAD:\n\t\tholy_weak_bt.apply(tower, creep, level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_ray_blaster.gd",
    "content": "extends TowerBehavior\n\n\nvar phazed_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {value = 500, value_add = 30, duration = 5},\n\t\t2: {value = 800, value_add = 35, duration = 5},\n\t\t3: {value = 1000, value_add = 40, duration = 5},\n\t\t4: {value = 1200, value_add = 45, duration = 6},\n\t\t5: {value = 1500, value_add = 50, duration = 6},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar iron_mod: Modifier = Modifier.new()\n\tphazed_bt = BuffType.new(\"phazed_bt\", 0, 0, false, self)\n\tiron_mod.add_modification(ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH, 0.0, 0.0001)\n\tiron_mod.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH, 0.0, 0.0001)\n\tphazed_bt.set_buff_modifier(iron_mod)\n\tphazed_bt.set_buff_icon(\"res://resources/icons/generic_icons/amber_mosquito.tres\")\n\tphazed_bt.set_buff_tooltip(tr(\"TILM\"))\n\n\nfunc on_damage(event: Event):\n\tphazed_bt.apply_custom_timed(tower, event.get_target(), _stats.value + _stats.value_add * tower.get_level(), _stats.duration + tower.get_level() * 0.1)\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_serpent_ward.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUFF] Changed autocast.buff_type\n# (null->charm_bt). This fixes issue where tower would\n# rebuff a unit which is already buffed.\n\n\nvar charm_bt: BuffType\n\n\nconst BUFF_DURATION: float = 5.0\nconst BUFF_DURATION_BONUS_AT_25: float = 5.0\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_mana = 0.10, mod_mana_add = 0.006, mod_mana_regen = 0.10, mod_mana_regen_add = 0.006, mod_spell_damage = 0.05, mod_spell_damage_add = 0.003},\n\t\t2: {mod_mana = 0.20, mod_mana_add = 0.012, mod_mana_regen = 0.20, mod_mana_regen_add = 0.012, mod_spell_damage = 0.10, mod_spell_damage_add = 0.006},\n\t\t3: {mod_mana = 0.30, mod_mana_add = 0.018, mod_mana_regen = 0.30, mod_mana_regen_add = 0.018, mod_spell_damage = 0.15, mod_spell_damage_add = 0.009},\n\t\t4: {mod_mana = 0.40, mod_mana_add = 0.024, mod_mana_regen = 0.40, mod_mana_regen_add = 0.024, mod_spell_damage = 0.20, mod_spell_damage_add = 0.012},\n\t}\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_MANA_PERC, _stats.mod_mana, _stats.mod_mana_add)\n\tm.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, _stats.mod_mana_regen, _stats.mod_mana_regen_add)\n\tm.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, _stats.mod_spell_damage, _stats.mod_spell_damage_add)\n\tcharm_bt = BuffType.new(\"charm_bt\", 0, 0, true, self)\n\tcharm_bt.set_buff_icon(\"res://resources/icons/generic_icons/charm.tres\")\n\tcharm_bt.set_buff_modifier(m)\n\tcharm_bt.set_buff_tooltip(tr(\"YNTO\"))\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tvar duration: float = BUFF_DURATION\n\tif level == 25:\n\t\tduration += BUFF_DURATION_BONUS_AT_25\n\n\tcharm_bt.apply_custom_timed(tower, target, level, duration)\n"
  },
  {
    "path": "src/towers/tower_behaviors/small_torch.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage = 60, damage_add = 3},\n\t\t2: {damage = 215, damage_add = 11},\n\t\t3: {damage = 600, damage_add = 30},\n\t\t4: {damage = 1200, damage_add = 60},\n\t\t5: {damage = 2150, damage_add = 107},\n}\n\n\nfunc on_autocast(event: Event):\n\tEffect.create_simple_at_unit(\"res://src/effects/firelord_death_explode.tscn\", event.get_target())\n\ttower.do_spell_damage_aoe_unit(event.get_target(), 200, _stats.damage + _stats.damage_add * tower.get_level(), tower.calc_spell_crit_no_bonus(), 0.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/sniper.gd",
    "content": "extends TowerBehavior\n\n\nvar rocket_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {rocket_damage = 400, rocket_damage_add = 10, aoe_radius = 150},\n\t\t2: {rocket_damage = 1200, rocket_damage_add = 30, aoe_radius = 160},\n\t\t3: {rocket_damage = 2400, rocket_damage_add = 60, aoe_radius = 170},\n\t\t4: {rocket_damage = 4000, rocket_damage_add = 100, aoe_radius = 180},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc rocket_hit(p: Projectile, _t: Unit):\n\tp.do_spell_damage_pb_aoe(_stats.aoe_radius, _stats.rocket_damage + _stats.rocket_damage_add * tower.get_level(), 0)\n\tvar effect: int = Effect.add_special_effect(\"res://src/effects/frag_boom_spawn.tscn\", Vector2(p.get_x(), p.get_y()))\n\tEffect.set_scale(effect, 2)\n\n\nfunc tower_init():\n\trocket_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 750, self)\n\trocket_pt.set_event_on_interpolation_finished(rocket_hit)\n#\tNOTE: -70% from tower specials +95% from this = 125%\n#\ttotal damage to mass\n\trocket_pt.set_bonus_to_size(CreepSize.enm.MASS, 0.95)\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(0.30 + 0.006 * tower.get_level()):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Rocket Strike\")\n\n\tProjectile.create_linear_interpolation_from_unit_to_unit(rocket_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, event.get_target(), 0.25, true)\n"
  },
  {
    "path": "src/towers/tower_behaviors/solar_collector.gd",
    "content": "extends TowerBehavior\n\n\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {attack_mana_cost = 1, release_energy_dmg = 4000, release_energy_dmg_add = 150, stun_duration = 3, stun_duration_for_bosses = 1},\n\t\t2: {attack_mana_cost = 2, release_energy_dmg = 12000, release_energy_dmg_add = 450, stun_duration = 5, stun_duration_for_bosses = 1.75},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_autocast(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar creep_size: CreepSize.enm = creep.get_size()\n\tvar damage: float = _stats.release_energy_dmg + _stats.release_energy_dmg_add * tower.get_level()\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/revive_human.tscn\", creep, Unit.BodyPart.CHEST)\n\n\tvar stun_duration: float\n\tif creep_size < CreepSize.enm.BOSS:\n\t\tstun_duration = _stats.stun_duration\n\telse:\n\t\tstun_duration = _stats.stun_duration_for_bosses\n\n\tstun_bt.apply_only_timed(tower, creep, stun_duration)\n\n\nfunc on_attack(_event: Event):\n\tvar mana: float = tower.get_mana()\n\n\tif mana < _stats.attack_mana_cost:\n\t\ttower.order_stop()\n\telse:\n\t\ttower.subtract_mana(_stats.attack_mana_cost, false)\n"
  },
  {
    "path": "src/towers/tower_behaviors/solar_emitter.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {aura_range = 800, mod_armor = 10, mod_armor_add = 0.3, vuln = 0.10, vuln_add = 0.003},\n\t\t2: {aura_range = 1100, mod_armor = 15, mod_armor_add = 0.5, vuln = 0.15, vuln_add = 0.005},\n\t}\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ARMOR, -_stats.mod_armor, -_stats.mod_armor_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_ASTRAL, _stats.vuln, _stats.vuln_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_NATURE, _stats.vuln, _stats.vuln_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_FIRE, _stats.vuln, _stats.vuln_add)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_IRON, _stats.vuln, _stats.vuln_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\taura_bt.set_buff_tooltip(tr(\"TDD3\"))\n"
  },
  {
    "path": "src/towers/tower_behaviors/sorceress.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: the way this tower works is that the player cycles\n# through modifications and then applies/removes current\n# modification from the missiles. Missiles can have a\n# combination of multiple modifications, not just the\n# currently selected one! The amount of applied\n# modifications is limited by missile damage - it cannot go\n# below 0.\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Changed cd of autocasts to\n# 0.25s because 0s cooldown is not supported by youtd2\n# engine.\n\n\nenum MissileMod {\n\tSLOW,\n\tSILENCE,\n\tREGEN,\n\tARMOR,\n\tSPELL,\n\tAOE,\n\n\tCOUNT,\n}\n\n\nclass Data:\n\tvar slow: int = 0 # +0.05 slow%\n\tvar silence: int = 0 # +5.0s duration\n\tvar regen: int = 0 # +0.05 regen%\n\tvar armor: int = 0 # +1 armor%\n\tvar spell: int = 0 # +0.06 vuln%\n\tvar aoe: int = 150 # No percentage, integer value! Equals to radius of aoe\n\tvar dmg: int = 100 # damage dealt by missile\n\n\nconst missile_mod_to_string: Dictionary = {\n\tMissileMod.SLOW: \"Slow\",\n\tMissileMod.SILENCE: \"Silence\",\n\tMissileMod.REGEN: \"Health Regen\",\n\tMissileMod.ARMOR: \"Armor\",\n\tMissileMod.SPELL: \"Spell Vuln\",\n\tMissileMod.AOE: \"AoE\",\n}\n\nvar silence_bt: BuffType\nvar slow_bt: BuffType\nvar sunder_bt: BuffType\nvar spell_vuln_bt: BuffType\nvar cripple_bt: BuffType\nvar missile_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar data: Data\nvar current_missile_mod: MissileMod\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_level_changed(on_level_changed)\n\n\nfunc tower_init():\n\ttower.hide_attack_projectiles()\n\n\tsilence_bt = CbSilence.new(\"sorceress_silence\", 0, 0, false, self)\n\n\tmissile_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 1200, 1200, self)\n\tmissile_pt.enable_collision(missile_pt_on_collision, 150, TargetType.new(TargetType.CREEPS), false)\n\n\tslow_bt = BuffType.new(\"slow_bt\", 5, 0, false, self)\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.01)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"K7X4\"))\n\n\tsunder_bt = BuffType.new(\"sunder_bt\", 5, 0, false, self)\n\tvar sunder_bt_mod: Modifier = Modifier.new()\n\tsunder_bt_mod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, 0.0, -0.01)\n\tsunder_bt.set_buff_modifier(sunder_bt_mod)\n\tsunder_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tsunder_bt.set_buff_tooltip(tr(\"SFT7\"))\n\n\tspell_vuln_bt = BuffType.new(\"spell_vuln_bt\", 5, 0, false, self)\n\tvar spell_vuln_bt_mod: Modifier = Modifier.new()\n\tspell_vuln_bt_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.0, 0.01)\n\tspell_vuln_bt.set_buff_modifier(spell_vuln_bt_mod)\n\tspell_vuln_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tspell_vuln_bt.set_buff_tooltip(tr(\"UGC2\"))\n\n\tcripple_bt = BuffType.new(\"cripple_bt\", 5, 0, false, self)\n\tvar cripple_bt_mod: Modifier = Modifier.new()\n\tcripple_bt_mod.add_modification(ModificationType.enm.MOD_HP_REGEN_PERC, 0.0, -0.01)\n\tcripple_bt.set_buff_modifier(cripple_bt_mod)\n\tcripple_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_meteor.tres\")\n\tcripple_bt.set_buff_tooltip(tr(\"TYIV\"))\n\n\tmultiboard = MultiboardValues.new(8)\n\tvar damager_perc_label: String = tr(\"SIKM\")\n\tvar mod_label: String = tr(\"VQNG\")\n\tvar slow_label: String = tr(\"WX62\")\n\tvar silence_label: String = tr(\"GIDV\")\n\tvar health_regen_label: String = tr(\"XCGT\")\n\tvar armor_label: String = tr(\"DEOM\")\n\tvar spell_vuln_label: String = tr(\"KVQT\")\n\tvar aoe_label: String = tr(\"V5X0\")\n\tmultiboard.set_key(0, damager_perc_label)\n\tmultiboard.set_key(1, mod_label)\n\tmultiboard.set_key(2, slow_label)\n\tmultiboard.set_key(3, silence_label)\n\tmultiboard.set_key(4, health_regen_label)\n\tmultiboard.set_key(5, armor_label)\n\tmultiboard.set_key(6, spell_vuln_label)\n\tmultiboard.set_key(7, aoe_label)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, 1.0, tower, target, false, true, false)\n\tp.set_collision_parameters(data.aoe, TargetType.new(TargetType.CREEPS))\n\tp.set_z(60)\n\n\nfunc on_damage(event: Event):\n\tevent.damage = 0\n\n\nfunc on_level_changed(event: Event):\n\tvar dmg_change: int\n\tif event.level_increased():\n\t\tdmg_change = 2\n\telse:\n\t\tdmg_change = -2\n\n\tdata.dmg += dmg_change\n\n\nfunc on_create(_preceding_tower: Tower):\n\tdata = Data.new()\n\tdata.dmg += 2 * tower.get_level()\n\tcurrent_missile_mod = MissileMod.SLOW\n\n\nfunc on_autocast_choose(_event: Event):\n\tcurrent_missile_mod = (current_missile_mod + 1) as MissileMod\n\tif current_missile_mod >= MissileMod.COUNT:\n\t\tcurrent_missile_mod = 0 as MissileMod\n\n\tvar floating_text: String = missile_mod_to_string[current_missile_mod]\n\ttower.get_player().display_small_floating_text(floating_text, tower, Color8(255, 255, 255), 40)\n\n\nfunc on_autocast_add(_event: Event):\n\tvar dmg_before: int = data.dmg\n\t\n\tmatch current_missile_mod:\n\t\tMissileMod.SLOW:\n\t\t\tif data.dmg >= 20:\n\t\t\t\tdata.slow += 8\n\t\t\t\tdata.dmg -= 20\n\t\t\t\tvar slow_text: String = \"+%s\" % tr(\"HPSI\")\n\t\t\t\ttower.get_player().display_small_floating_text(slow_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.SILENCE: \n\t\t\tif data.dmg >= 40:\n\t\t\t\tdata.silence += 5\n\t\t\t\tdata.dmg -= 40\n\t\t\t\tvar silence_text: String = \"+%s\" % tr(\"XEU6\")\n\t\t\t\ttower.get_player().display_small_floating_text(silence_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.REGEN: \n\t\t\tif data.dmg >= 25:\n\t\t\t\tdata.regen += 10\n\t\t\t\tdata.dmg -= 25\n\t\t\t\tvar regen_text: String = \"+%s\" % tr(\"IIAL\")\n\t\t\t\ttower.get_player().display_small_floating_text(regen_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.ARMOR:\n\t\t\tif data.dmg >= 25:\n\t\t\t\tdata.armor += 6\n\t\t\t\tdata.dmg -= 25\n\t\t\t\tvar armor_text: String = \"+%s\" % tr(\"YYNF\")\n\t\t\t\ttower.get_player().display_small_floating_text(armor_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.SPELL:\n\t\t\tif data.dmg >= 25:\n\t\t\t\tdata.spell += 12\n\t\t\t\tdata.dmg -= 25\n\t\t\t\tvar spell_vuln_text: String = \"+%s\" % tr(\"NLWT\")\n\t\t\t\ttower.get_player().display_small_floating_text(spell_vuln_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.AOE:\n\t\t\tif data.dmg >= 15:\n\t\t\t\tdata.aoe += 50\n\t\t\t\tdata.dmg -= 15\n\t\t\t\tvar aoe_text: String = \"+%s\" % tr(\"CTRS\")\n\t\t\t\ttower.get_player().display_small_floating_text(aoe_text, tower, Color8(255, 255, 255), 40)\n\n\tvar dmg_after: int = data.dmg\n\tvar dmg_changed: bool = dmg_before != dmg_after\n\n\tif !dmg_changed:\n\t\tvar cant_increase_modification_text: String = tr(\"NYGB\")\n\t\ttower.get_player().display_small_floating_text(cant_increase_modification_text, tower, Color8(255, 0, 0), 40)\n\n\nfunc on_autocast_remove(_event: Event):\n\tvar dmg_before: int = data.dmg\n\n\tmatch current_missile_mod:\n\t\tMissileMod.SLOW:\n\t\t\tif data.slow >= 8:\n\t\t\t\tdata.slow -= 8\n\t\t\t\tdata.dmg += 20\n\t\t\t\tvar slow_text: String = \"-%s\" % tr(\"HPSI\")\n\t\t\t\ttower.get_player().display_small_floating_text(slow_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.SILENCE: \n\t\t\tif data.silence >= 5:\n\t\t\t\tdata.silence -= 5\n\t\t\t\tdata.dmg += 40\n\t\t\t\tvar silence_text: String = \"-%s\" % tr(\"XEU6\")\n\t\t\t\ttower.get_player().display_small_floating_text(silence_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.REGEN: \n\t\t\tif data.regen >= 10:\n\t\t\t\tdata.regen -= 10\n\t\t\t\tdata.dmg += 25\n\t\t\t\tvar regen_text: String = \"-%s\" % tr(\"IIAL\")\n\t\t\t\ttower.get_player().display_small_floating_text(regen_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.ARMOR:\n\t\t\tif data.armor >= 6:\n\t\t\t\tdata.armor -= 6\n\t\t\t\tdata.dmg += 25\n\t\t\t\tvar armor_text: String = \"-%s\" % tr(\"YYNF\")\n\t\t\t\ttower.get_player().display_small_floating_text(armor_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.SPELL:\n\t\t\tif data.spell >= 12:\n\t\t\t\tdata.spell -= 12\n\t\t\t\tdata.dmg += 25\n\t\t\t\tvar spell_vuln_text: String = \"-%s\" % tr(\"NLWT\")\n\t\t\t\ttower.get_player().display_small_floating_text(spell_vuln_text, tower, Color8(255, 255, 255), 40)\n\t\tMissileMod.AOE:\n\t\t\tif data.aoe > 150:\n\t\t\t\tdata.aoe -= 50\n\t\t\t\tdata.dmg += 15\n\t\t\t\tvar aoe_text: String = \"-%s\" % tr(\"CTRS\")\n\t\t\t\ttower.get_player().display_small_floating_text(aoe_text, tower, Color8(255, 255, 255), 40)\n\n\tvar dmg_after: int = data.dmg\n\tvar dmg_changed: bool = dmg_before != dmg_after\n\n\tif !dmg_changed:\n\t\tvar cant_decrease_modification_text: String = tr(\"U8NM\")\n\t\ttower.get_player().display_small_floating_text(cant_decrease_modification_text, tower, Color8(255, 0, 0), 40)\n\n\n# NOTE: original script does a weird thing with multiple\n# calls to displayTimedText(). Seems like in original\n# engine, the \"onTowerDetails()\" callback is called once\n# when tower details menu is opened. So what happened was\n# player opened details and then some extra text was printed\n# to the screen.\n# \n# In youtd2 engine onTowerDetails() is called repeatedly to\n# keep TowerDetails up to date.\n# \n# So I changed the script to display these stats in details.\nfunc on_tower_details() -> MultiboardValues:\n\tvar damage_string: String = Utils.format_percent(data.dmg / 100.0, 0)\n\tvar modification_string: String = missile_mod_to_string[current_missile_mod]\n\tvar slow_string: String = Utils.format_percent(data.slow / 100.0, 0)\n\tvar silence_duration_string: String = Utils.format_float(data.silence, 0)\n\tvar silence_string: String = tr(\"MY4I\").format({SILENCE_DURATION = silence_duration_string})\n\tvar regen_string: String = Utils.format_percent(data.regen / 100.0, 0)\n\tvar armor_string: String = Utils.format_percent(data.armor / 100.0, 0)\n\tvar spell_string: String = Utils.format_percent(data.spell / 100.0, 0)\n\tvar aoe_string: String = Utils.format_float(data.aoe, 0)\n\n\tmultiboard.set_value(0, damage_string)\n\tmultiboard.set_value(1, modification_string)\n\tmultiboard.set_value(2, slow_string)\n\tmultiboard.set_value(3, silence_string)\n\tmultiboard.set_value(4, regen_string)\n\tmultiboard.set_value(5, armor_string)\n\tmultiboard.set_value(6, spell_string)\n\tmultiboard.set_value(7, aoe_string)\n\t\n\treturn multiboard\n\n\n# NOTE: \"coll()\" in original script\nfunc missile_pt_on_collision(_p: Projectile, target: Unit):\n\tvar silence_chance: float = 0.50\n\n\tif data.slow > 0:\n\t\tslow_bt.apply(tower, target, data.slow)\n\n\tif data.silence > 0:\n\t\tif tower.calc_chance(silence_chance):\n\t\t\tsilence_bt.apply_only_timed(tower, target, data.silence)\n\n\tif data.regen > 0:\n\t\tcripple_bt.apply(tower, target, data.regen)\n\n\tif data.armor > 0:\n\t\tsunder_bt.apply(tower, target, data.armor)\n\n\tif data.spell:\n\t\tspell_vuln_bt.apply(tower, target, data.spell)\n\n\tif data.dmg > 0:\n\t\tvar damage: float = tower.get_current_attack_damage_with_bonus() * data.dmg / 100.0\n\t\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/soul_vault.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Original script uses\n# \"acidbomb\" cast for the acid skull ability. Implemented it\n# using regular projectile instead. Final behavior is the\n# same.\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Original script applies\n# armor debuffs before acid skull hits the targets. That is\n# weird, changed it so that debuffs are applied after the\n# projectile hits the target.\n\n\nvar acid_skull_bt: BuffType\nvar soulsteal_bt: BuffType\nvar aura_bt: BuffType\nvar acid_skull_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\tvar sir_soul_vault_aura_mod: Modifier = Modifier.new()\n\tsir_soul_vault_aura_mod.add_modification(ModificationType.enm.MOD_ARMOR_PERC, -0.25, -0.002)\n\taura_bt.set_buff_modifier(sir_soul_vault_aura_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\taura_bt.set_buff_tooltip(tr(\"RGDD\"))\n\n\tacid_skull_bt = BuffType.new(\"acid_skull_bt\", 4.5, 0, false, self)\n\tvar sir_soul_vault_acid_skull_mod: Modifier = Modifier.new()\n\tsir_soul_vault_acid_skull_mod.add_modification(ModificationType.enm.MOD_ARMOR, 0.50, 0.02)\n\tacid_skull_bt.set_buff_modifier(sir_soul_vault_acid_skull_mod)\n\tacid_skull_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\tacid_skull_bt.set_buff_tooltip(tr(\"Y5US\"))\n\n\tsoulsteal_bt = BuffType.new(\"soulsteal_bt\", 1000, 0, false, self)\n\tvar sir_soul_vault_soulsteal_mod: Modifier = Modifier.new()\n\tsir_soul_vault_soulsteal_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.50, 0.02)\n\tsoulsteal_bt.set_buff_modifier(sir_soul_vault_soulsteal_mod)\n\tsoulsteal_bt.set_buff_icon(\"res://resources/icons/generic_icons/ghost.tres\")\n\tsoulsteal_bt.set_buff_tooltip(tr(\"MJC1\"))\n\n\tacid_skull_pt = ProjectileType.create(\"path_to_projectile_sprite\", 20, 700, self)\n\tacid_skull_pt.enable_homing(acid_skull_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar acid_skull_chance: float = 0.25 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(acid_skull_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Acid Skull\")\n\n\tProjectile.create_from_unit_to_unit(acid_skull_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar soulsteal_chance: float = 0.125 + 0.001 * tower.get_level()\n\n\tif !tower.calc_chance(soulsteal_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Soul Steal\")\n\n\tsoulsteal_bt.apply(tower, target, tower.get_level())\n\n\nfunc acid_skull_pt_on_hit(_projectile: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 225)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar is_main_target: bool = next == target\n\n\t\tvar skull_damage: float\n\t\tif is_main_target:\n\t\t\tskull_damage = 1800 * (1.0 + 0.05 * tower.get_level())\n\t\telse:\n\t\t\tskull_damage = 1440 * (1.0 + 0.05 * tower.get_level())\n\n\t\ttower.do_spell_damage(next, skull_damage, tower.calc_spell_crit_no_bonus())\n\t\tacid_skull_bt.apply(tower, next, tower.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/soulflame_device.gd",
    "content": "extends TowerBehavior\n\n\nvar evil_device_bt: BuffType\nvar soulfire_bt: BuffType\nvar awaken_bt: BuffType\nvar soulflame_pt: ProjectileType\nvar multiboard: MultiboardValues\nvar awaken_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tevil_device_bt = BuffType.create_aura_effect_type(\"evil_device_bt\", true, self)\n\tevil_device_bt.set_buff_icon(\"res://resources/icons/generic_icons/pokecog.tres\")\n\tevil_device_bt.add_event_on_create(evil_device_bt_on_create)\n\tevil_device_bt.add_event_on_cleanup(evil_device_bt_on_cleanup)\n\tevil_device_bt.add_periodic_event(evil_device_bt_periodic, 5)\n\tevil_device_bt.set_buff_tooltip(tr(\"Q9GW\"))\n\n\tsoulfire_bt = BuffType.new(\"soulfire_bt\", 5, 0, false, self)\n\tsoulfire_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_dot.tres\")\n\tsoulfire_bt.add_periodic_event(soulfire_bt_periodic, 1)\n\tsoulfire_bt.add_event_on_death(soulfire_bt_on_death)\n\tsoulfire_bt.set_buff_tooltip(tr(\"RSZ5\"))\n\n\tawaken_bt = BuffType.new(\"awaken_bt\", 3, 0, true, self)\n\tvar awaken_bt_mod: Modifier = Modifier.new()\n\tawaken_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.50, 0.02)\n\tawaken_bt.set_buff_modifier(awaken_bt_mod)\n\tawaken_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\tawaken_bt.set_buff_tooltip(tr(\"QODF\"))\n\n\tsoulflame_pt = ProjectileType.create(\"path_to_projectile_sprite\", 5, 9000, self)\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar awaken_count_label: String = tr(\"Q0SH\")\n\tmultiboard.set_key(0, awaken_count_label)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar soulfire_chance: float = 0.2 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(soulfire_chance):\n\t\treturn\n\n\tashbringer_soulfire_apply(target, 1)\n\n\nfunc on_autocast(_event: Event):\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.TOWERS), tower, 350)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tawaken_bt.apply(tower, next, tower.get_level())\n\n\tawaken_count += 1\n\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.01)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, str(awaken_count))\n\n\treturn multiboard\n\n\nfunc evil_device_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tevil_device_bt_update(buff)\n\n\nfunc evil_device_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, -buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, -buff.user_int2 / 1000.0)\n\n\nfunc evil_device_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tevil_device_bt_update(buff)\n\n\nfunc evil_device_bt_update(buff: Buff):\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar caster: Unit = buff.get_caster()\n\tvar caster_level: int = caster.get_level()\n\tvar caster_level_factor: float = 0.5 + 0.02 * caster_level\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, -buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, -buff.user_int2 / 1000.0)\n\n\tvar spell_crit_chance_innate: float = Constants.INNATE_MOD_SPELL_CRIT_CHANCE - caster_level * Constants.INNATE_MOD_SPELL_CRIT_CHANCE_LEVEL_ADD\n\tvar spell_crit_dmg_innate: float = Constants.INNATE_MOD_SPELL_CRIT_DAMAGE - caster_level * Constants.INNATE_MOD_SPELL_CRIT_DAMAGE_LEVEL_ADD\n#\tNOTE: 1.0 is 0.0 in original script. Changed it to 1.0\n#\tbecause in youtd2 get_attack_speed_modifier() is based\n#\taround 1.0.\n\tvar attack_speed_innate: float = 1.0 + caster_level * Constants.INNATE_MOD_ATTACKSPEED_LEVEL_ADD\n\n\tbuff.user_real = (caster.get_prop_spell_damage_dealt() - 1.0) * caster_level_factor\n\tbuff.user_real2 = (caster.get_spell_crit_chance() - spell_crit_chance_innate) * caster_level_factor\n\tbuff.user_real3 = (caster.get_spell_crit_damage() - spell_crit_dmg_innate) * caster_level_factor\n\tbuff.user_int = int((caster.get_attack_speed_modifier() - attack_speed_innate) * caster_level_factor * 1000.0)\n\tbuff.user_int2 = int((caster.get_prop_trigger_chances() - 1.0) * caster_level_factor * 1000.0)\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, buff.user_int2 / 1000.0)\n\n\nfunc soulfire_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar stack_count: int = buff.user_int\n\tvar damage_per_stack = 1000 + 40 * tower.get_level()\n\tvar damage: float = damage_per_stack * stack_count\n\n\ttower.do_spell_damage(buffed_unit, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc soulfire_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), buffed_unit, 200)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", buffed_unit)\n\n\tashbringer_consumption_missile(buffed_unit)\n\n\ttower.add_mana(5.0)\n\n\tvar nearby_count: int = it.count()\n\n\tvar stack_count_on_dead_creep: int\n\tif buff != null:\n\t\tstack_count_on_dead_creep = buff.user_int\n\telse:\n\t\tstack_count_on_dead_creep = 0\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar stack_gain: int = floori(Utils.divide_safe(stack_count_on_dead_creep, nearby_count))\n\t\tashbringer_soulfire_apply(next, stack_gain)\n\n\nfunc ashbringer_consumption_missile(target: Unit):\n\tvar destination_pos: Vector3 = Vector3(tower.get_x(), tower.get_y(), 215)\n\n\tProjectile.create_from_unit_to_point(soulflame_pt, target, 0, 0, target, destination_pos, false, true)\n\n\nfunc ashbringer_soulfire_apply(target: Unit, stack_gain: int):\n\tvar buff: Buff = target.get_buff_of_type(soulfire_bt)\n\n\tif stack_gain < 1:\n\t\tstack_gain = 1\n\n\tvar active_stack_count: int = 0\n\tif buff != null:\n\t\tactive_stack_count = buff.user_int\n\n\tvar new_stack_count: int = active_stack_count + stack_gain\n\n\tbuff = soulfire_bt.apply(tower, target, 1)\n\tbuff.user_int = new_stack_count\n\tbuff.set_displayed_stacks(new_stack_count)\n"
  },
  {
    "path": "src/towers/tower_behaviors/spell_collector.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] (NOT FIXED) Original\n# script has a bug where if multiple towers from Spell\n# Collectors family are built, then only one tower will\n# receive bonuses when other towers cast spells. Didn't fix\n# this bug, translated version also behaves like this. If\n# you want to fix this, check other tower scripts for an\n# example fix. There are other towers with a similar effect\n# - they also use an aura to detect some event but share the\n# bonuses correctly with all towers of the family.\n\n# NOTE: reworked how delay between missiles is implemented.\n# Original script uses JASS timer and Launch() function.\n# Translated script does everything inside on_attack() and\n# uses await().\n\n\nvar spell_pt: ProjectileType\nvar spell_gathering_bt: BuffType\nvar missile_stacks_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {missile_count_max = 10, missile_count_max_add = 1, missile_damage = 2000, missile_damage_add = 80, missile_crit_chance = 0.050, missile_crit_chance_add = 0.002, missile_crit_dmg = 0.10, missile_crit_dmg_add = 0.004},\n\t\t2: {missile_count_max = 20, missile_count_max_add = 2, missile_damage = 4000, missile_damage_add = 160, missile_crit_chance = 0.075, missile_crit_chance_add = 0.003, missile_crit_dmg = 0.15, missile_crit_dmg_add = 0.006},\n\t}\n\n\nvar BARRAGE_CHANCE: float = 0.20\nvar BARRAGE_CHANCE_ADD: float = 0.008\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tspell_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1200, self)\n\tspell_pt.set_event_on_interpolation_finished(spell_pt_on_hit)\n\n\tspell_gathering_bt = BuffType.create_aura_effect_type(\"spell_gathering_bt\", true, self)\n\tspell_gathering_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\tspell_gathering_bt.add_event_on_spell_casted(spell_gathering_bt_on_spell_casted)\n\tspell_gathering_bt.set_buff_tooltip(tr(\"LLEH\"))\n\n\tmissile_stacks_bt = BuffType.new(\"missile_stacks_bt\", 20, 0, true, self)\n\tmissile_stacks_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\tmissile_stacks_bt.set_buff_tooltip(tr(\"RK0P\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar harvest_count_label: String = tr(\"X7BJ\")\n\tmultiboard.set_key(0, harvest_count_label)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar chance: float = BARRAGE_CHANCE + BARRAGE_CHANCE_ADD * tower.get_level()\n\tvar missile_crit_chance: float = _stats.missile_crit_chance + _stats.missile_crit_chance_add * tower.get_level()\n\tvar missile_crit_dmg: float = _stats.missile_crit_dmg + _stats.missile_crit_dmg_add * tower.get_level()\n\tvar missile_count_max: int = _stats.missile_count_max + _stats.missile_count_max_add * tower.get_level() / 5\n\tvar stacks_buff: Buff = tower.get_buff_of_type(missile_stacks_bt)\n\n\tvar missile_count: int\n\tif stacks_buff != null:\n\t\tmissile_count = min(stacks_buff.get_level() + 1, missile_count_max)\n\telse:\n\t\tmissile_count = 1\n\n\tvar delay_between_missiles: float = max(0.2, tower.get_current_attack_speed() / missile_count)\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Magical Barrage\")\n\n\tfor i in range(0, missile_count):\n\t\tif !Utils.unit_is_valid(tower) || !Utils.unit_is_valid(target):\n\t\t\treturn\n\n\t\tvar projectile: Projectile = Projectile.create_bezier_interpolation_from_unit_to_unit(spell_pt, tower, 1.0, tower.calc_spell_crit_no_bonus(), tower, target, 0.0, 0.0, 0.0, true)\n\t\tvar missile_number: int = i + 1\n\t\tprojectile.user_real = missile_crit_chance * missile_number\n\t\tprojectile.user_real2 = missile_crit_dmg * missile_number\n\n\t\tawait Utils.create_manual_timer(delay_between_missiles, self).timeout\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar buff: Buff = tower.get_buff_of_type(missile_stacks_bt)\n\tvar lvl: int = 0\n\n\tif buff != null:\n\t\tlvl = min(buff.get_level() + 1, 10 + tower.get_level() / 5)\n\n\tvar spells_harvested: String = Utils.format_float(lvl, 0)\n\tmultiboard.set_value(0, spells_harvested)\n\n\treturn multiboard\n\n\nfunc spell_gathering_bt_on_spell_casted(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\n\tvar stacks_buff: Buff = caster.get_buff_of_type(missile_stacks_bt)\n\tvar stacks_count: int\n\tif stacks_buff != null:\n\t\tstacks_count = stacks_buff.get_level() + 1\n\telse:\n\t\tstacks_count = 1\n\n\tstacks_buff = missile_stacks_bt.apply(caster, caster, stacks_count)\n\tstacks_buff.set_displayed_stacks(stacks_count)\n\n\tvar autocast: Autocast = event.get_autocast_type()\n\tvar autocast_cooldown: float = autocast.get_cooldown()\n\n\tawait Utils.create_manual_timer(autocast_cooldown, self).timeout\n\n\tif Utils.unit_is_valid(caster):\n\t\tstacks_buff = caster.get_buff_of_type(missile_stacks_bt)\n\n\t\tif stacks_buff != null:\n\t\t\tstacks_buff.set_level(stacks_buff.get_level() - 1)\n\t\t\tstacks_buff.set_displayed_stacks(stacks_buff.get_level())\n\t\t\tif stacks_buff.get_level() == 0:\n\t\t\t\tstacks_buff.remove_buff()\n\n\nfunc spell_pt_on_hit(p: Projectile, target: Unit):\n\tvar caster: Tower = p.get_caster()\n\tvar damage: float = _stats.missile_damage + _stats.missile_damage_add * caster.get_level()\n\n\tif target != null && caster != null:\n\t\tcaster.do_spell_damage(target, damage, caster.calc_spell_crit(p.user_real, p.user_real2))\n"
  },
  {
    "path": "src/towers/tower_behaviors/spider_queen.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Nerubian Queen\"=>\"Spider Queen\"\n\n\nvar multiboard: MultiboardValues\nvar parasite_bt: BuffType\nvar spider_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tparasite_bt = BuffType.new(\"parasite_bt\", 10, 0, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tparasite_bt.set_buff_modifier(mod)\n\tparasite_bt.add_periodic_event(parasite_bt_periodic, 1.0)\n\tparasite_bt.add_event_on_death(parasite_bt_on_death)\n\tparasite_bt.set_buff_icon(\"res://resources/icons/generic_icons/amber_mosquito.tres\")\n\tparasite_bt.set_buff_tooltip(tr(\"GBJV\"))\n\n\tspider_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 500, self)\n\tspider_pt.set_event_on_cleanup(spider_pt_on_cleanup)\n\tspider_pt.disable_explode_on_hit()\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar damage_gained_label: String = tr(\"GTNC\")\n\tmultiboard.set_key(0, damage_gained_label)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar chance: float = 0.30 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Inject Parasite\")\n\n\tparasite_bt.apply(tower, target, tower.get_level())\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_real = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar damage_gained: String = Utils.format_percent(tower.user_real, 0)\n\tmultiboard.set_value(0, damage_gained)\n\n\treturn multiboard\n\n\nfunc parasite_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar level: int = buff.get_level()\n\tvar damage: float = 500 + 100 * level\n\tvar mod_armor: float = -(0.02 + 0.0008 * level)\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\ttarget.modify_property(ModificationType.enm.MOD_ARMOR_PERC, mod_armor)\n\n\nfunc parasite_bt_on_death(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar creep: Unit = buff.get_buffed_unit()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), creep, 500)\n\n\tEffect.create_simple(\"res://src/effects/crypt_fiend_eggsack.tscn\", Vector2(creep.get_x(), creep.get_y()))\n\n\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0075)\n\ttower.user_real += 0.0075\n\n\tvar new_host: Unit = it.next()\n\tvar temp: Unit = null\n\twhile true:\n\t\tif new_host == null || new_host.get_buff_of_type(parasite_bt) == null:\n\t\t\tbreak\n\n\t\tif new_host != creep:\n\t\t\ttemp = new_host\n\n\t\tnew_host = it.next()\n\n#\tFind a new host! Prefers targets that aren't carrying\n#\tparasites already.\n\tif new_host == null:\n\t\tif temp == null:\n#\t\t\tNo one to jump to! parasite dies :(\n\t\t\tEffect.create_scaled(\"res://src/effects/frost_armor_damage_purple.tscn\", Vector3(creep.get_x(), creep.get_y(), 0), 0, 1)\n\t\t\t\n\t\t\treturn\n\t\telse:\n#\t\t\tCan only jump to a target that already has a\n#\t\t\tparasite. Do it anyway, to refresh the buff\n#\t\t\tduration.\n\t\t\tnew_host = temp\n\n\tvar projectile: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(spider_pt, tower, 0, 0, creep, new_host, 0.5, true)\n\tprojectile.set_projectile_scale(0.2)\n\n\nfunc spider_pt_on_cleanup(projectile: Projectile):\n\tvar creep: Creep = projectile.get_target()\n\tvar caster: Unit = projectile.get_caster()\n\n\tif !Utils.unit_is_valid(creep):\n\t\treturn\n\t\n\tparasite_bt.apply(caster, creep, caster.get_level())\n"
  },
  {
    "path": "src/towers/tower_behaviors/star_gazer.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {damage_bonus = 0.01},\n\t\t2: {damage_bonus = 0.02},\n\t\t3: {damage_bonus = 0.03},\n\t\t4: {damage_bonus = 0.04},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\n\tif creep.is_immune():\n\t\ttower.do_attack_damage(creep, tower.get_current_attack_damage_with_bonus() * 0.8, tower.calc_attack_multicrit(0, 0, 0))\n\telse:\n\t\ttower.do_spell_damage(creep, tower.get_current_attack_damage_with_bonus() * (1 + _stats.damage_bonus * tower.get_level()), tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/storm_battery.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: rewrote script a bit. Instead of enabling/disabling\n# periodic event I added a flag.\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) Original script has\n# a bug where it refunds the cost of autocast in\n# on_autocast(). It refunds the cost by calling set_mana()\n# but the problem is that at the time when on_autocast() is\n# called, the mana cost has not been spent yet. Therefore,\n# refund fails if tower is at max mana because set_mana()\n# can't go above max mana. Not critical - don't need to fix.\n\n\nvar electrified_bt: BuffType\nvar missile_pt: ProjectileType\n\nvar _battery_overload_is_active: bool = false\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {projectile_damage = 300, projectile_damage_add = 12, damage_increase = 0.4, damage_increase_add = 0.008, mod_dmg_from_fire = 0.05},\n\t\t2: {projectile_damage = 750, projectile_damage_add = 30, damage_increase = 0.8, damage_increase_add = 0.016, mod_dmg_from_fire = 0.10},\n\t\t3: {projectile_damage = 1800, projectile_damage_add = 72, damage_increase = 1.2, damage_increase_add = 0.024, mod_dmg_from_fire = 0.15},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc on_autocast(_event: Event):\n\ttower.set_mana(tower.get_mana() + 100)\n\t_battery_overload_is_active = true\n\n\nfunc debuff_on_damaged(event: Event):\n\tvar b: Buff = event.get_buff()\n\tvar level: int = tower.get_level()\n\tvar extra_damage_chance: float = 0.2 + 0.003 * level\n\n\tif !tower.calc_chance(extra_damage_chance):\n\t\tCombatLog.log_ability(tower, b.get_buffed_unit(), \"Electrify Effect\")\n\n\t\tvar damage_multiplier: float = _stats.damage_increase + _stats.damage_increase_add * level\n\t\tevent.damage = event.damage * damage_multiplier\n\n\t\tvar damage_text: String = Utils.format_float(event.damage, 0)\n\t\ttower.get_player().display_small_floating_text(damage_text, b.get_buffed_unit(), Color8(128, 255, 255), 20)\n\n\nfunc hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar damage: float = _stats.projectile_damage + _stats.projectile_damage_add * level\n\n\ttower.do_spell_damage(creep, damage, tower.calc_spell_crit_no_bonus())\n\telectrified_bt.apply(tower, creep, level)\n\n\nfunc tower_init():\n\telectrified_bt = BuffType.new(\"electrified_bt\", 9, 0.3, false, self)\n\telectrified_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\telectrified_bt.add_event_on_damaged(debuff_on_damaged)\n\telectrified_bt.set_buff_tooltip(tr(\"NVVL\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\tmissile_pt.enable_homing(hit, 0)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\telectrified_bt.apply(tower, target, level)\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_int = 0\n\ttower.set_mana(0)\n\n\nfunc periodic(_event: Event):\n\tif !_battery_overload_is_active:\n\t\treturn\n\n\tif tower.get_mana() > 10:\n\t\tvar in_range: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar target: Unit = in_range.next_random()\n\n\t\tif target != null:\n# \t\t\tNOTE: original script used createFromPointToUnit and made projectiles from high above the tower\n\t\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\t\tp.set_projectile_scale(0.5)\n\n#\t\tSpend mana, note that mana is used for unsuccessful\n#\t\tattempts as well\n\t\ttower.set_mana(tower.get_mana() - 10)\n\telse:\n#\t\tTower is out of mana so stop shooting\n\t\t_battery_overload_is_active = false\n"
  },
  {
    "path": "src/towers/tower_behaviors/storm_coil.gd",
    "content": "extends TowerBehavior\n\n\nvar surge_bt: BuffType\nvar slow_bt: BuffType\nvar aura_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tslow_bt = BuffType.new(\"slow_bt\", 1.5, 0, false, self)\n\tvar slow_bt_mod: Modifier = Modifier.new()\n\tslow_bt_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.0001)\n\tslow_bt.set_buff_modifier(slow_bt_mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"MBIW\"))\n\n\tsurge_bt = BuffType.new(\"surge_bt\", 4.0, 0.1, true, self)\n\tsurge_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tsurge_bt.add_periodic_event(surge_bt_periodic, 0.4)\n\tsurge_bt.set_buff_tooltip(tr(\"PHHY\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", false, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\taura_bt.add_event_on_damaged(aura_bt_on_damaged)\n\taura_bt.set_buff_tooltip(tr(\"ZF40\"))\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar distance_to_target: float = tower.get_position_wc3_2d().distance_to(target.get_position_wc3_2d())\n\tvar damage: float = distance_to_target * 12.0 * tower.get_current_attack_damage_with_bonus() / tower.get_base_damage()\n\n\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\ttower.get_player().display_floating_text_x(str(int(damage)), target, Color8(255, 200, 0, 255), 0.05, 0.0, 2.0)\n\n\tvar slow_buff_level: int = floori(distance_to_target * 3)\n\tslow_bt.apply(tower, target, slow_buff_level)\n\n\nfunc on_autocast(event: Event):\n\tvar creep: Unit = event.get_target()\n\n\tvar buff: Buff = surge_bt.apply(tower, creep, tower.get_level())\n\tbuff.user_real = creep.get_x()\n\tbuff.user_real2 = creep.get_y()\n\n\nfunc surge_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar surge_pos: Vector2 = Vector2(buff.user_real, buff.user_real2)\n\tvar distance_to_target: float = surge_pos.distance_to(target.get_position_wc3_2d())\n\tvar damage: float = 4 * distance_to_target * (1 + 0.02 * tower.get_level())\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\ttower.get_player().display_floating_text_x(str(int(damage)), target, Color8(150, 150, 255, 255), 0.05, 0.0, 2.0)\n\tEffect.create_simple_at_unit(\"res://src/effects/spell_ailb.tscn\", target)\n\n\nfunc aura_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar tower_pos: Vector2 = tower.get_position_wc3_2d()\n\tvar target_pos: Vector2 = target.get_position_wc3_2d()\n\tvar distance_to_target: float = tower_pos.distance_to(target_pos)\n\tvar damage_multiplier: float = 1.0 + distance_to_target * (0.00020 + 0.000006 * tower.get_level())\n\tvar attacking_tower: Tower = event.get_target()\n\tvar attacking_element: Element.enm = attacking_tower.get_element()\n\n\tif attacking_element == Element.enm.STORM:\n\t\tevent.damage *= damage_multiplier\n"
  },
  {
    "path": "src/towers/tower_behaviors/storm_focus.gd",
    "content": "extends TowerBehavior\n\n\nvar freezing_bt: BuffType\nvar aura_bt: BuffType\n\n\nfunc tower_init():\n\tfreezing_bt = BuffType.new(\"freezing_bt\", 5, 0.05, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_AIR, 0.1, 0.008)\n\tfreezing_bt.set_buff_modifier(mod)\n\tfreezing_bt.set_buff_icon(\"res://resources/icons/generic_icons/energy_breath.tres\")\n\tfreezing_bt.set_buff_tooltip(tr(\"EY29\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\taura_bt.add_event_on_create(gust_on_create)\n\taura_bt.add_periodic_event(gust_periodic, 1.0)\n\taura_bt.add_event_on_cleanup(gust_on_cleanup)\n\taura_bt.set_buff_tooltip(tr(\"N6RI\"))\n\n\nfunc gust_on_create(event: Event):\n#\tSstore tower's bonus damage in buff's user_real\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_real = 0.0\n\n\nfunc gust_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar multiplier: float = 0.5 + 0.008 * tower.get_level()\n\tvar dmg_to_air: float = target.get_damage_to_size(CreepSize.enm.AIR)\n\n\tvar bonus_damage: float = 1.0 * (dmg_to_air - 1.0) * multiplier\n\t\n\tvar target_has_freezing_gust: bool = target.get_buff_of_type(freezing_bt) != null\n\tif target_has_freezing_gust:\n\t\tbonus_damage *= 2.0\n\n\ttarget.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, bonus_damage - buff.user_real)\n\tbuff.user_real = bonus_damage\n\n\nfunc gust_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar bonus_dmg: float = buff.user_real\n\ttarget.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -bonus_dmg)\n"
  },
  {
    "path": "src/towers/tower_behaviors/stormy_dog.gd",
    "content": "extends TowerBehavior\n\n\nvar roar_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {buff_scale = 6},\n\t\t2: {buff_scale = 9},\n\t\t3: {buff_scale = 12},\n\t\t4: {buff_scale = 15},\n\t\t5: {buff_scale = 18},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.05, 0.0005)\n\n\troar_bt = BuffType.new(\"roar_bt\", 5.0, 0.0, true, self)\n\troar_bt.set_buff_icon(\"res://resources/icons/generic_icons/wolf_howl.tres\")\n\troar_bt.set_buff_modifier(mod)\n\troar_bt.set_buff_tooltip(tr(\"XYY8\"))\n\n\n# NOTE: need to skip stacking for buffs with higher active\n# tier. apply() will reject buffs from lower tier tower, so\n# it's not possible to increase level and therefore stacks.\nfunc on_damage(_event: Event):\n\tif !tower.calc_chance(0.3):\n\t\treturn\n\t\n\tvar level: int = tower.get_level()\n\n\tCombatLog.log_ability(tower, null, \"Thunderous Roar\")\n\t\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 420.0)\n\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/roar.tscn\", tower, Unit.BodyPart.ORIGIN)\n\n\twhile true:\n\t\tvar target: Unit = it.next()\n\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tvar original_buff: Buff = target.get_buff_of_type(roar_bt)\n\n\t\tvar tier_is_weaker_than_active: bool = original_buff != null && tower.get_tier() < original_buff.get_tower_tier()\n\t\tif tier_is_weaker_than_active:\n\t\t\tcontinue\n\n\t\tvar original_stacks: int = 0\n\t\tvar original_buff_level: int = 0\n\t\tif original_buff != null:\n\t\t\toriginal_stacks = original_buff.user_int\n\t\t\toriginal_buff_level = original_buff.get_level()\n\n\t\tvar new_stacks: int\n\t\tvar new_buff_level: int\n\t\tif original_buff == null:\n\t\t\tnew_stacks = 1\n\t\t\tnew_buff_level = _stats.buff_scale * level\n\t\telse:\n\t\t\tif original_stacks < 100:\n\t\t\t\tnew_stacks = original_stacks + 1\n\t\t\t\tnew_buff_level = original_buff_level + _stats.buff_scale\n\t\t\telse:\n\t\t\t\tnew_stacks = original_stacks\n\t\t\t\tnew_buff_level = original_buff_level\n\n\t\tvar new_buff: Buff = roar_bt.apply(tower, target, new_buff_level)\n\n#\t\tNOTE: need to check for this condition because\n#\t\tapply() can reject reapply if this tower has lower\n#\t\ttier than the original buff caster. In that case,\n#\t\tlower tier tower can't increase level of buff -\n#\t\ttherefore can't increase stacks.\n\t\tvar was_able_to_increase_stacks: bool = new_buff.get_level() == new_buff_level\n\t\tif was_able_to_increase_stacks:\n\t\t\tnew_buff.user_int = new_stacks\n\t\t\tnew_buff.set_displayed_stacks(new_stacks)\n"
  },
  {
    "path": "src/towers/tower_behaviors/sun_crusader.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: changed buff types a bit. In original script they\n# are two separate types, made it into one type which\n# changes based on tier.\n\n\nvar crusader_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {blessed_weapon_damage = 500, for_the_god_effect = 0.40, for_the_god_effect_add = 0.01, for_the_god_level = 400, for_the_god_level_add = 10},\n\t\t2: {blessed_weapon_damage = 1000, for_the_god_effect = 0.80, for_the_god_effect_add = 0.02, for_the_god_level = 800, for_the_god_level_add = 20},\n\t}\n\nconst BLESSED_WEAPON_CHANCE: float = 0.15\nconst BLESSED_WEAPON_DAMAGE_ADD: float = 50\nconst BLESSED_WEAPON_MANA_GAIN: float = 2\nconst BLESSED_WEAPON_MANA_GAIN_ADD: float = 0.1\nconst FOR_THE_GOD_DURATION: float = 8.0\nconst FOR_THE_GOD_DURATION_ADD: float = 0.1\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tcrusader_bt = BuffType.new(\"crusader_bt\", FOR_THE_GOD_DURATION, FOR_THE_GOD_DURATION_ADD, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, _stats.for_the_god_effect, _stats.for_the_god_effect_add)\n\tmod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, _stats.for_the_god_effect, _stats.for_the_god_effect_add)\n\tcrusader_bt.set_buff_modifier(mod)\n\tcrusader_bt.set_buff_icon(\"res://resources/icons/generic_icons/angel_wings.tres\")\n\tcrusader_bt.set_buff_tooltip(tr(\"WED6\"))\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(BLESSED_WEAPON_CHANCE):\n\t\treturn\n\n\tCombatLog.log_ability(tower, event.get_target(), \"Blessed Weapon\")\n\n\tvar damage: float = _stats.blessed_weapon_damage + BLESSED_WEAPON_DAMAGE_ADD * tower.get_level()\n\tvar mana_gain: float = BLESSED_WEAPON_MANA_GAIN + BLESSED_WEAPON_MANA_GAIN_ADD * tower.get_level()\n\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/holy_bolt.tscn\", event.get_target(), Unit.BodyPart.CHEST)\n\ttower.do_spell_damage(event.get_target(), damage, tower.calc_spell_crit_no_bonus())\n\ttower.add_mana(mana_gain)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tcrusader_bt.apply(tower, target, level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/taita_the_hermit.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] (NOT FIXED) this tower will deal\n# 0 damage if Frost Bolt ability hits a creep with no Icy\n# Touch stacks. Kind of weird.\n\n\nvar cold_blood_bt: BuffType\nvar icy_touch_bt: BuffType\nvar frostbolt_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\tcold_blood_bt = BuffType.new(\"cold_blood_bt\", 3, 0, true, self)\n\tvar dave_taita_blood_mod: Modifier = Modifier.new()\n\tdave_taita_blood_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.5, 0.005)\n\tcold_blood_bt.set_buff_modifier(dave_taita_blood_mod)\n\tcold_blood_bt.set_buff_icon(\"res://resources/icons/generic_icons/azul_flake.tres\")\n\tcold_blood_bt.set_buff_tooltip(tr(\"BZF0\"))\n\n\ticy_touch_bt = BuffType.new(\"icy_touch_bt\", 5, 0, false, self)\n\tvar dave_taita_touch_mod: Modifier = Modifier.new()\n\tdave_taita_touch_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.1)\n\ticy_touch_bt.set_buff_modifier(dave_taita_touch_mod)\n\ticy_touch_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\ticy_touch_bt.set_buff_tooltip(tr(\"YSCT\"))\n\n\tfrostbolt_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 900, self)\n\tfrostbolt_pt.enable_homing(frostbolt_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar speed: float = Constants.DEFAULT_MOVE_SPEED\n\tvar current_speed: float = creep.get_current_movespeed()\n\tvar slow: float = (speed - current_speed) / speed\n\n\tif !tower.calc_chance(slow):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Frost Bolt\")\n\n\tProjectile.create_from_unit_to_unit(frostbolt_pt, tower, 1, 1, tower, creep, true, false, false)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar buff: Buff = target.get_buff_of_type(icy_touch_bt)\n\tvar buff_level: int = 0\n\tvar damage: float = tower.get_current_attack_damage_with_bonus()\n\tvar level: int = tower.get_level()\n\n\tif buff != null:\n\t\tbuff_level = buff.get_level()\n\t\tevent.damage = event.damage * (1 + buff_level * (0.1 + 0.02 * level))\n\n\tif buff_level < 6:\n\t\ticy_touch_bt.apply(tower, target, buff_level + 1)\n\n\tbuff = target.get_buff_of_type(icy_touch_bt)\n\tif buff != null:\n\t\tbuff.set_displayed_stacks(buff.get_level())\n\n\nfunc on_kill(_event: Event):\n\tvar level: int = tower.get_level()\n\n\tcold_blood_bt.apply(tower, tower, level)\n\n\nfunc frostbolt_pt_on_hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\tvar buff: Buff = creep.get_buff_of_type(icy_touch_bt)\n\n\tvar buff_level: int\n\tif buff != null:\n\t\tbuff_level = buff.get_level()\n\telse:\n\t\tbuff_level = 0\n\n\tvar damage: float = tower.get_current_attack_damage_with_bonus() * buff_level * (0.2 + (0.004 * level))\n\tif creep.is_stunned():\n\t\tdamage *= 2\n\n\tCombatLog.log_ability(tower, creep, \"Frost Bolt Hit AoE\")\n\n\ttower.do_attack_damage_aoe_unit(creep, 200, damage, tower.calc_attack_multicrit_no_bonus(), 0.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/teacher.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\nvar green_pt: ProjectileType\nvar blue_pt: ProjectileType\nvar red_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {exp_teach = 1.0},\n\t\t2: {exp_teach = 1.3},\n\t\t3: {exp_teach = 1.5},\n\t\t4: {exp_teach = 1.8},\n\t\t5: {exp_teach = 2.0},\n\t\t6: {exp_teach = 2.2},\n\t}\n\n\nfunc hit(p: Projectile, result: Unit):\n\tif result == null:\n\t\treturn\n\n\tvar t: Tower = p.get_caster()\n\n\tif result.get_instance_id() == p.user_int:\n\t\tresult.add_exp(p.user_real)\n\n\t\tif p.user_int2 == t.get_instance_id():\n\t\t\tt.user_real2 = t.user_real2 + p.user_real * result.get_prop_exp_received()\n\n\nfunc teacher_attack(xp: float):\n\tvar in_range: Iterate\n\tvar result: Unit\n\tvar pt: ProjectileType\n\tvar p: Projectile\n\tvar i: int\n\n\tif tower.calc_chance(0.10 + 0.006 * tower.get_level()):\n\t\tin_range = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 600)\n\n\t\tresult = in_range.next_random()\n\n\t\tif result == tower:\n\t\t\tresult = in_range.next_random()\n\n\t\tif result != null:\n\t\t\ti = Globals.synced_rng.randi_range(1, 3)\n\n\t\t\tif i == 1:\n\t\t\t\tpt = green_pt\n\t\t\telif i == 2:\n\t\t\t\tpt = red_pt\n\t\t\telif i == 3:\n\t\t\t\tpt = blue_pt\n\n\t\t\tCombatLog.log_ability(tower, result, \"Knowledge\")\n\n\t\t\tp = Projectile.create_from_unit_to_unit(pt, tower, 1.0, 1.0, tower, result, true, false, true)\n\t\t\tp.set_projectile_scale(0.7)\n\t\t\tp.user_real = xp\n\t\t\tp.user_int = result.get_instance_id()\n\t\t\tp.user_int2 = tower.get_instance_id()\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(1)\n\tvar xp_granted_label: String = tr(\"WXGT\")\n\tmultiboard.set_key(0, xp_granted_label)\n\n\tgreen_pt = ProjectileType.create(\"path_to_projectile_sprite\", 20.0, 450.00, self)\n\tgreen_pt.disable_explode_on_hit()\n\tgreen_pt.enable_homing(hit, 0)\n\tblue_pt = ProjectileType.create(\"path_to_projectile_sprite\", 20.0, 450.00, self)\n\tblue_pt.disable_explode_on_hit()\n\tblue_pt.enable_homing(hit, 0)\n\tred_pt = ProjectileType.create(\"path_to_projectile_sprite\", 20.0, 450.00, self)\n\tred_pt.disable_explode_on_hit()\n\tred_pt.enable_homing(hit, 0)\n\n\nfunc on_attack(_event: Event):\n\tteacher_attack(_stats.exp_teach)\n\ttower.set_animation_by_index(tower, 3)\n\n\nfunc on_create(preceding_tower: Tower):\n\tvar preceding: Tower = preceding_tower\n\n\tif preceding != null && preceding.get_family() == tower.get_family():\n\t\ttower.user_real2 = preceding.user_real2\n\telse:\n\t\ttower.user_real2 = 0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, Utils.format_float(tower.user_real2, 1))\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/tentacle_spawn.gd",
    "content": "extends TowerBehavior\n\n\nvar rend_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {apply_level = 1, periodic_damage = 20, periodic_damage_add = 0.8},\n\t\t2: {apply_level = 2, periodic_damage = 60, periodic_damage_add = 2.4},\n\t\t3: {apply_level = 3, periodic_damage = 120, periodic_damage_add = 4.8},\n\t\t4: {apply_level = 4, periodic_damage = 240, periodic_damage_add = 10},\n\t\t5: {apply_level = 5, periodic_damage = 480, periodic_damage_add = 20},\n\t\t6: {apply_level = 6, periodic_damage = 960, periodic_damage_add = 40},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.02, 0.01)\n\n\trend_bt = BuffType.new(\"rend_bt\", 6, 0, false, self)\n\trend_bt.set_buff_icon(\"res://resources/icons/generic_icons/triple_scratches.tres\")\n\trend_bt.add_periodic_event(drol_tentacleDamage, 1)\n\trend_bt.set_buff_modifier(m)\n\trend_bt.set_buff_tooltip(tr(\"OH6K\"))\n\n\nfunc drol_tentacleDamage(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tif !b.get_buffed_unit().is_immune():\n\t\tb.get_caster().do_spell_damage(b.get_buffed_unit(), b.user_real, b.get_caster().calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit(\"res://src/effects/blood_splatter.tscn\", b.get_buffed_unit(), Unit.BodyPart.CHEST)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tif !tower.calc_chance(0.25 + tower.get_level() * 0.01):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Rend\")\n\t\n\trend_bt.apply(tower, target, _stats.apply_level).user_real = _stats.periodic_damage + _stats.periodic_damage_add * tower.get_level()\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_conduit.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: the \"Conduit Aura\" ability has exactly the same\n# logic as \"Evil Device\" ability of \"Soulflame Device\"\n# tower.\n\n\nvar aura_bt: BuffType\nvar unleash_bt: BuffType\nvar chanlightning_st: SpellType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/over_infinity.tres\")\n\taura_bt.add_event_on_create(aura_bt_on_create)\n\taura_bt.add_event_on_cleanup(aura_bt_on_cleanup)\n\taura_bt.add_periodic_event(aura_bt_periodic, 5)\n\taura_bt.set_buff_tooltip(tr(\"OYR4\"))\n\n\tunleash_bt = BuffType.new(\"unleash_bt\", 3, 0, false, self)\n\tvar unleash_bt_mod: Modifier = Modifier.new()\n\tunleash_bt_mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, 0.75, 0.03)\n\tunleash_bt.set_buff_modifier(unleash_bt_mod)\n\tunleash_bt.set_buff_icon(\"res://resources/icons/generic_icons/bat_mask.tres\")\n\tunleash_bt.set_buff_tooltip(tr(\"Z7S7\"))\n\n\tchanlightning_st = SpellType.new(SpellType.Name.CHAIN_LIGHTNING, 1.0, self)\n\tchanlightning_st.set_source_height(220)\n\tchanlightning_st.data.chain_lightning.damage = 1.0\n\tchanlightning_st.data.chain_lightning.damage_reduction = 0.25\n\tchanlightning_st.data.chain_lightning.chain_count = 1\n\n\nfunc on_damage(event: Event):\n\tvar absorb_energy_chance: float = 0.1 + 0.002 * tower.get_level()\n\n#\tNOTE: in original script, damage was set to 0 only when\n#\tcalc_chance() succeeded. Fixed this, now damage is 0\n#\talways.\n\tevent.damage = 0\n\n\tif !tower.calc_chance(absorb_energy_chance):\n\t\treturn\n\n\tvar target: Unit = event.get_target()\n\tvar mana: float = 50 + 1 * tower.get_level()\n\ttower.add_mana(mana)\n\ttarget.subtract_mana(mana, true)\n\n\tvar lightning_end_pos: Vector3 = Vector3(tower.get_x(), tower.get_y(), 180)\n\tvar interpolated_sprite: InterpolatedSprite = InterpolatedSprite.create_from_unit_to_point(InterpolatedSprite.LIGHTNING, target, lightning_end_pos)\n\tinterpolated_sprite.set_lifetime(0.5)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.TOWERS), tower, 350)\n\tvar cast_damage: float = (400 + 8 * tower.get_level()) * tower.get_player().get_team().get_level()\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tunleash_bt.apply(tower, next, tower.get_level())\n\n#\tNOTE: original script does a weird thing where it casts\n#\tchain lightning (which deals damage) and also deals\n#\tdamage using tower.doSpellDamage(). doSpellDamage() does\n#\tthe actual damage amount. chain lightning deals a small\n#\tamount (like 6) which looks confusing.\n# \n#\tChanged it to deal damage only once, via chain\n#\tlightning.\n\tchanlightning_st.target_cast_from_caster(tower, target, cast_damage, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: \"ashbringer_conduit_create()\" in original script\nfunc aura_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\n\tbuff.user_real = 0\n\tbuff.user_real2 = 0\n\tbuff.user_real3 = 0\n\tbuff.user_int = 0\n\tbuff.user_int2 = 0\n\n\tunleash_bt_update(buff)\n\n\n# NOTE: \"ashbringer_conduit_cleanup()\" in original script\nfunc aura_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\t\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, -buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, -buff.user_int2 / 1000.0)\n\n\n# NOTE: \"ashbringer_conduit_update()\" in original script\nfunc aura_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\t\n\tunleash_bt_update(buff)\n\n\nfunc unleash_bt_update(buff: Buff):\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar caster: Tower = buff.get_caster()\n\tvar caster_level: int = caster.get_level()\n\tvar caster_level_factor: float = 0.5 + 0.02 * caster_level\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, -buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, -buff.user_int2 / 1000.0)\n\n\tvar spell_crit_chance_innate: float = Constants.INNATE_MOD_SPELL_CRIT_CHANCE - caster_level * Constants.INNATE_MOD_SPELL_CRIT_CHANCE_LEVEL_ADD\n\tvar spell_crit_dmg_innate: float = Constants.INNATE_MOD_SPELL_CRIT_DAMAGE - caster_level * Constants.INNATE_MOD_SPELL_CRIT_DAMAGE_LEVEL_ADD\n#\tNOTE: 1.0 is 0.0 in original script. Changed it to 1.0\n#\tbecause in youtd2 get_attack_speed_modifier() is based\n#\taround 1.0.\n\tvar attack_speed_innate: float = 1.0 + caster_level * Constants.INNATE_MOD_ATTACKSPEED_LEVEL_ADD\n\n\tbuff.user_real = (caster.get_prop_spell_damage_dealt() - 1.0) * caster_level_factor\n\tbuff.user_real2 = (caster.get_spell_crit_chance() - spell_crit_chance_innate) * caster_level_factor\n\tbuff.user_real3 = (caster.get_spell_crit_damage() - spell_crit_dmg_innate) * caster_level_factor\n\tbuff.user_int = int((caster.get_attack_speed_modifier() - attack_speed_innate) * caster_level_factor * 1000.0)\n\tbuff.user_int2 = int((caster.get_prop_trigger_chances() - 1.0) * caster_level_factor * 1000.0)\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, buff.user_int2 / 1000.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_council_of_demons.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Original script has a bug where\n# the projectile created by aura deals 2 damage because\n# do_spell_damage() is called on tower instead of\n# projectile. It was intended that projectile stores damage\n# ratio and then deals damage using that ratio. Fixed bug by\n# not using damage ratio (not needed really) and storing\n# damage in user_real of projectile.\n\n\nvar aura_bt: BuffType\nvar demonic_mana_bt: BuffType\nvar maledict_bt: BuffType\nvar darkness_bt: BuffType\nvar missile_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tdarkness_bt = BuffType.new(\"darkness_bt\", 5, 0, false, self)\n\tvar dave_council_darkness_mod: Modifier = Modifier.new()\n\tdave_council_darkness_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.4, -0.006)\n\tdave_council_darkness_mod.add_modification(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, -0.95, 0.0)\n\tdarkness_bt.set_buff_modifier(dave_council_darkness_mod)\n\tdarkness_bt.set_buff_icon(\"res://resources/icons/generic_icons/fire_dash.tres\")\n\tdarkness_bt.add_periodic_event(dave_council_darkness_periodic, 1.0)\n\tdarkness_bt.add_event_on_damaged(dave_council_darkness_on_damaged)\n\tdarkness_bt.add_event_on_expire(dave_council_darkness_on_expire)\n\tdarkness_bt.set_buff_tooltip(tr(\"XJLT\"))\n\n\tmaledict_bt = BuffType.new(\"maledict_bt\", 5, 0, false, self)\n\tvar dave_council_maledict_mod: Modifier = Modifier.new()\n\tdave_council_maledict_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.2, 0.006)\n\tmaledict_bt.set_buff_modifier(dave_council_maledict_mod)\n\tmaledict_bt.set_buff_icon(\"res://resources/icons/generic_icons/fire_dash.tres\")\n\tmaledict_bt.add_event_on_spell_targeted(dave_council_maledict_on_spell_targeted)\n\tmaledict_bt.set_buff_tooltip(tr(\"Q488\"))\n\n\tdemonic_mana_bt = BuffType.new(\"demonic_mana_bt\", 3, 0, true, self)\n\tvar dave_council_mana_mod: Modifier = Modifier.new()\n\tdave_council_mana_mod.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, 1.0, 0.02)\n\tdemonic_mana_bt.set_buff_modifier(dave_council_mana_mod)\n\tdemonic_mana_bt.set_buff_icon(\"res://resources/icons/generic_icons/star_swirl.tres\")\n\tdemonic_mana_bt.set_buff_tooltip(tr(\"LN06\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/burning_meteor.tres\")\n\taura_bt.add_event_on_spell_casted(aura_bt_on_spell_casted)\n\taura_bt.set_buff_tooltip(tr(\"RTYZ\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 4, 1300, self)\n\tmissile_pt.enable_homing(missile_pt_on_hit, 0)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar maledict_chance: float = 0.2 + 0.004 * level\n\n\tif !tower.calc_chance(maledict_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Maledict\")\n\n\tmaledict_bt.apply(tower, creep, level)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tdarkness_bt.apply(tower, target, level)\n\n\nfunc aura_bt_on_spell_casted(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = event.get_target()\n\tvar caster: Tower = buff.get_buffed_unit()\n\tvar goldcost: float = caster.get_gold_cost()\n\tvar cd: float = event.get_autocast_type().get_cooldown()\n\tvar projectile_damage: float = 2 * goldcost * cd\n\n\tif !target is Creep:\n\t\treturn\n\t\n\tCombatLog.log_ability(tower, target, \"Demonic Edict on spell casted\")\n\t\n\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", target)\n\tvar p: Projectile = Projectile.create_from_unit_to_unit(missile_pt, tower, 1.0, 1.0, caster, target, true, false, true)\n\tp.user_real = projectile_damage\n\tdemonic_mana_bt.apply(tower, caster, tower.get_level())\n\n\nfunc missile_pt_on_hit(p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar projectile_damage: float = p.user_real\n\ttower.do_spell_damage(creep, projectile_damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc dave_council_maledict_on_spell_targeted(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = event.get_target()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar gold: float = caster.get_gold_cost()\n\tvar maledict_damage: float = 3 * gold\n\n\tif target.is_immune():\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Impenetrable Darkness periodic\")\n\t\n\ttower.do_spell_damage(target, maledict_damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/death_and_decay.tscn\", target)\n\tSFX.sfx_at_unit(SfxPaths.GHOST_EXHALE, target)\n\n\nfunc dave_council_darkness_periodic(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar damage: float = 1000 + 40 * level\n\n\tCombatLog.log_ability(tower, target, \"Maledict on spell targeted\")\n\t\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\nfunc dave_council_darkness_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar stored_damage: float = buff.user_real\n\tstored_damage += event.damage\n\tbuff.user_real = stored_damage\n\n\nfunc dave_council_darkness_on_expire(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar level: int = tower.get_level()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar stored_damage: float = buff.user_real\n\tvar damage_multiplier: float = 0.75 + 0.01 * level\n\tvar final_damage: float = stored_damage * damage_multiplier\n\n\tCombatLog.log_ability(tower, target, \"Impenetrable Darkness on expire\")\n\n\ttower.do_spell_damage(target, final_damage, 1)\n\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", target)\n\n\tvar floating_text: String = Utils.format_float(final_damage, 0)\n\ttower.get_player().display_floating_text(floating_text, target, Color8(50, 50, 50))\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_fire_lord.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: reworked original script. Origin script uses\n# Buff.addAbility() to add multishot temporarily. Can't do\n# that with Youtd2 engine so instead we use buff's\n# create/cleanup events and modify target count there.\n\n# NOTE: the multishot count is a bit confusing. Description\n# says tower \"gains a 5 target multishot\". This means that\n# bonus is +4 so that total is 5. Doesn't mean that bonus is\n# +5.\n\n\nvar hellfire_bt: BuffType\nvar liquid_fire_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tliquid_fire_bt = BuffType.new(\"liquid_fire_bt\", 5, 0.1, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.25, 0.004)\n\tmod.add_modification(ModificationType.enm.MOD_DMG_FROM_FIRE, 0.10, 0.004)\n\tliquid_fire_bt.set_buff_modifier(mod)\n\tliquid_fire_bt.add_periodic_event(liquid_fire_periodic, 1.0)\n\tliquid_fire_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tliquid_fire_bt.set_buff_tooltip(tr(\"WQDY\"))\n\n\thellfire_bt = BuffType.new(\"hellfire_bt\", 7.5, 0.2, true, self)\n\thellfire_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\thellfire_bt.add_event_on_create(hellfire_on_create)\n\thellfire_bt.add_event_on_cleanup(hellfire_on_cleanup)\n\thellfire_bt.set_buff_tooltip(tr(\"P569\"))\n\n\nfunc on_attack(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar hellfire_chance: float = 0.25 + 0.002 * level\n\n\tif !tower.calc_chance(hellfire_chance):\n\t\treturn\n\n\tvar tower_already_has_hellfire: bool = tower.get_buff_of_type(hellfire_bt) != null\n\n\tif tower_already_has_hellfire:\n\t\treturn\n\n\tCombatLog.log_ability(tower, null, \"Hellfire\")\n\n\thellfire_bt.apply(tower, tower, level)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tliquid_fire_bt.apply(tower, target, level)\n\n\nfunc liquid_fire_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar damage: float = 500 + 50 * buff.get_level()\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: it is important that we add and subtract from target\n# count. Setting target count to a value directly would be\n# incorrect because there are other buffs which also add to\n# target count and we need to take care to work well\n# together with them.\nfunc hellfire_on_create(event: Event):\n\tvar level: int = tower.get_level()\n\tvar buff: Buff = event.get_buff()\n\n\tvar target_count_bonus: int = 4\n\tif level >= 15:\n\t\ttarget_count_bonus += 1\n\tif level == 25:\n\t\ttarget_count_bonus += 1\n\n\tbuff.user_int = target_count_bonus\n\n\tvar current_target_count: int = tower.get_target_count()\n\tvar new_target_count: int = current_target_count + target_count_bonus\n\ttower.set_target_count(new_target_count)\n\n\nfunc hellfire_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target_count_bonus: int = buff.user_int\n\n\tvar current_target_count: int = tower.get_target_count()\n\tvar new_target_count: int = current_target_count - target_count_bonus\n\ttower.set_target_count(new_target_count)\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_frozen_wyrm.gd",
    "content": "extends TowerBehavior\n\n\nvar slow_bt: BuffType\nvar stun_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 1.5, 0.0, false, self)\n\n\tslow_bt = BuffType.new(\"slow_bt\", 4.0, 0.24, true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.27, -0.002)\n\tslow_bt.set_buff_modifier(mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/energy_breath.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"P26M\"))\n\n\nfunc on_damage(event: Event):\n\tvar level: int = tower.get_level()\n\tvar target: Creep = event.get_target()\n\tvar slow_chance: float = 0.25 + 0.01 * level\n\tvar stun_chance: float = 0.05 + 0.002 * level\n\n\tif tower.calc_chance(slow_chance):\n\t\tCombatLog.log_ability(tower, target, \"Freezing Breath slow\")\n\t\tslow_bt.apply(tower, target, level)\n\n\tif tower.calc_chance(stun_chance):\n\t\tCombatLog.log_ability(tower, target, \"Freezing Breath stun\")\n\t\tstun_bt.apply(tower, target, level)\n\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_furnace.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original script implements \"attacks random target\"\n# ability using aura. Changed implementation to use a\n# simpler method with same behavior.\n\n\nvar intense_heat_bt: BuffType\nvar aura_bt: BuffType\nvar lingering_flames_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/hammer_drop.tres\")\n\taura_bt.add_event_on_create(aura_bt_on_create)\n\taura_bt.add_periodic_event(aura_bt_periodic, 5.0)\n\taura_bt.add_event_on_cleanup(aura_bt_on_cleanup)\n\taura_bt.set_buff_tooltip(tr(\"C1M6\"))\n\n\tintense_heat_bt = BuffType.new(\"intense_heat_bt\", 4, 0, true, self)\n\tvar intense_heat_bt_mod: Modifier = Modifier.new()\n\tintense_heat_bt_mod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.0, 0.0005)\n\tintense_heat_bt_mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, 0.0, 0.0005)\n\tintense_heat_bt.set_buff_modifier(intense_heat_bt_mod)\n\tintense_heat_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tintense_heat_bt.set_buff_tooltip(tr(\"TTEZ\"))\n\n\tlingering_flames_bt = BuffType.new(\"lingering_flames_bt\", 10, 0, false, self)\n\tlingering_flames_bt.add_periodic_event(lingering_flames_bt_periodic, 1.0)\n\tlingering_flames_bt.set_buff_icon(\"res://resources/icons/generic_icons/flame.tres\")\n\tlingering_flames_bt.set_buff_tooltip(tr(\"G9ZF\"))\n\n\nfunc on_attack(_event: Event):\n\tvar iterator: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), tower.get_range())\n\tvar random_unit: Unit = iterator.next_random()\n\n\ttower.add_mana_perc(0.01)\n\n\ttower.issue_target_order(random_unit)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tashbringer_linger_apply(target)\n\n\nfunc on_kill(_event: Event):\n\ttower.modify_property(ModificationType.enm.MOD_MANA, 10)\n\ttower.add_mana_perc(0.04)\n\n\nfunc on_autocast(_event: Event):\n\tvar damagecast: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), tower, 1000)\n\tvar buffcast: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.TOWERS), tower, 350)\n\tvar tower_mana: float = tower.get_mana()\n\tvar fxscale: float = 0.8 + min(tower_mana, 3000) / 3000 * 0.9\n\n\tvar effect: int = Effect.create_scaled(\"res://src/effects/small_flame_spawn.tscn\", tower.get_position_wc3(), 270, fxscale)\n\tEffect.set_lifetime(effect, 6.6)\n\n\twhile true:\n\t\tvar next: Unit = damagecast.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tashbringer_linger_apply(next)\n\t\tvar damage: float = (7 + 0.2 * tower.get_level()) * tower_mana\n\t\ttower.do_spell_damage(next, damage, tower.calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit_attached(\"res://src/effects/small_flame_spawn.tscn\", next, Unit.BodyPart.ORIGIN)\n\n\twhile true:\n\t\tvar next: Unit = buffcast.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tintense_heat_bt.apply(tower, next, int(tower_mana / 15.0))\n\n\ttower.subtract_mana(tower_mana, true)\n\n\nfunc ashbringer_linger_apply(target: Unit):\n\tvar buff: Buff = target.get_buff_of_type(lingering_flames_bt)\n\t\n\tvar active_stacks: int\n\tif buff != null:\n\t\tactive_stacks = buff.user_int\n\telse:\n\t\tactive_stacks = 0\n\n\tvar new_stacks: int = active_stacks + 1\n\n\tbuff = lingering_flames_bt.apply(tower, target, 1)\n\tbuff.user_int = new_stacks\n\tbuff.set_displayed_stacks(new_stacks)\n\n\nfunc lingering_flames_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar target: Unit = buff.get_buffed_unit()\n\tvar stack_count: int = buff.user_int\n\tvar damage: float = (100 + 2 * tower.get_level()) * stack_count\n\tvar gain_mana_chance: float = 0.2 + 0.004 * tower.get_level()\n\n\ttower.do_spell_damage(target, damage, tower.calc_spell_crit_no_bonus())\n\n\tif tower.calc_chance(gain_mana_chance):\n\t\ttower.add_mana_perc(0.005 * stack_count)\n\n\nfunc aura_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tashbringer_heart_update(buff)\n\n\nfunc aura_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tashbringer_heart_update(buff)\n\n\nfunc ashbringer_heart_update(buff: Buff):\n\tvar caster: Tower = buff.get_caster()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\tvar caster_level: float = caster.get_level()\n\tvar caster_level_factor: float = 0.5 + 0.02 * caster_level\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, -buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, -buff.user_int2 / 1000.0)\n\n\tvar spell_crit_innate: float = Constants.INNATE_MOD_SPELL_CRIT_CHANCE - caster_level * Constants.INNATE_MOD_SPELL_CRIT_CHANCE_LEVEL_ADD\n\tvar spell_dmg_innate: float = Constants.INNATE_MOD_SPELL_CRIT_DAMAGE - caster_level * Constants.INNATE_MOD_SPELL_CRIT_DAMAGE_LEVEL_ADD\n#\tNOTE: 1.0 is 0.0 in original script. Changed it to 1.0\n#\tbecause in youtd2 get_attack_speed_modifier() is based\n#\taround 1.0.\n\tvar attack_speed_innate: float = 1.0 + caster_level * Constants.INNATE_MOD_ATTACKSPEED_LEVEL_ADD\n\tbuff.user_real = (caster.get_prop_spell_damage_dealt() - 1.0) * caster_level_factor\n\tbuff.user_real = (caster.get_spell_crit_chance() - spell_crit_innate) * caster_level_factor\n\tbuff.user_real = (caster.get_spell_crit_chance() - spell_dmg_innate) * caster_level_factor\n\tbuff.user_int = int((caster.get_attack_speed_modifier() - attack_speed_innate) * caster_level_factor * 1000)\n\tbuff.user_int2 = int((caster.get_prop_trigger_chances() - 1.0) * caster_level_factor * 1000)\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, buff.user_int2 / 1000.0)\n\n\nfunc aura_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Tower = buff.get_buffed_unit()\n\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -buff.user_real)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, -buff.user_real2)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_SPELL_CRIT_DAMAGE, -buff.user_real3)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -buff.user_int / 1000.0)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_TRIGGER_CHANCES, -buff.user_int2 / 1000.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_omnislasher.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: changed how the \"mirror image\" VFX is implemented by\n# a lot. Original script uses Effect with models and attack\n# animations. Don't have access to those things so used a\n# moving projectile instead with sprite of tower.\n\n\nvar omnislashed_bt: BuffType\nvar mirror_image_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\tomnislashed_bt = BuffType.new(\"omnislashed_bt\", -1, 0, false, self)\n\tomnislashed_bt.set_buff_icon(\"res://resources/icons/generic_icons/triple_scratches.tres\")\n\tomnislashed_bt.set_buff_tooltip(tr(\"Q9VE\"))\n\tomnislashed_bt.add_event_on_damaged(omnislashed_bt_on_damaged)\n\n\tmirror_image_pt = ProjectileType.create_interpolate(\"res://src/projectiles/projectile_visuals/omnislasher_mirror_image.tscn\", 1000.0, self)\n\tmirror_image_pt.set_event_on_interpolation_finished(mirror_image_pt_on_interpolation_finished)\n\tmirror_image_pt.disable_explode_on_hit()\n\n\n# NOTE: implemented this slightly differently than original\n# script. Using \"await\" instead of timer.\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar attack_count: int = 10 + 2 / 5 * tower.get_level()\n\tvar time_between_attacks: float = tower.get_current_attack_speed() / attack_count\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 1200)\n\n\tSFX.sfx_at_unit(SfxPaths.MAGIC_FIZZLE, tower)\n\t\n\ttower.set_sprite_color(Color8(255, 255, 255, 100))\n\n# \tNOTE: original script calls PauseUnit() here and after\n# \tthe end of the Omnislash ability. This means that the\n# \ttower never actually shoots the attack projectile.\n# \tReplicate this behavior by calling order_stop().\n\ttower.order_stop()\n\n\tvar fun_text: String\n\tvar fun_value: float = Globals.synced_rng.randf_range(0, 1.0)\n\tif fun_value < 0.03:\n\t\tvar faster_than_light_text: String = tr(\"ZWDX\")\n\t\tfun_text = faster_than_light_text\n\telif fun_value < 0.02:\n\t\tvar einstein_lies_text: String = tr(\"B0DP\")\n\t\tfun_text = einstein_lies_text\n\telif fun_value < 0.01:\n\t\tvar relativity_text: String = tr(\"M4CO\")\n\t\tfun_text = relativity_text\n\telse:\n\t\tfun_text = \"\"\n\n\tif !fun_text.is_empty():\n\t\ttower.get_player().display_floating_text_x(fun_text, tower, Color8(50, 150, 255, 255), 0.05, 2, 3)\n\n\tvar p: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(mirror_image_pt, tower, 0, 0, tower, target, 0.1, true)\n#\tNOTE: set a very high speed for first movement from tower to target so that projectile reaches the target on time\n\tp.set_speed(5000)\n\n\tfor i in range(0, attack_count):\n\t\tawait Utils.create_manual_timer(time_between_attacks, self).timeout\n\n\t\tif !Utils.unit_is_valid(tower):\n\t\t\tbreak\n\n\t\tif !Utils.unit_is_valid(target):\n\t\t\ttarget = it.next()\n\t\t\t\n\t\tif target == null:\n\t\t\tbreak\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/blood_splatter.tscn\", target)\n\n\t\tvar random_angle: float = deg_to_rad(Globals.synced_rng.randf_range(0, 360))\n\t\tvar random_offset: Vector2 = Vector2(80, 0).rotated(random_angle)\n\t\tvar projectile_pos: Vector3 = Vector3(\n\t\t\ttarget.get_x() + random_offset.x,\n\t\t\ttarget.get_y() + random_offset.y,\n\t\t\ttarget.get_z())\n\t\tp.start_interpolation_to_point(projectile_pos, 0.1)\n#\t\tNOTE: reduce speed to normal value for moves after first one\n\t\tp.set_speed(1000)\n\n\t\tdamage(target)\n\n\tp.remove_from_game()\n\ttower.set_sprite_color(Color8(255, 255, 255, 255))\n\n\nfunc damage(target: Unit):\n\tvar buff: Buff = target.get_buff_of_type(omnislashed_bt)\n\n\ttower.do_attack_damage(target, tower.get_current_attack_damage_with_bonus() / 10, tower.calc_attack_multicrit_no_bonus())\n\n\tif buff == null:\n\t\tbuff = omnislashed_bt.apply(tower, target, tower.get_level())\n\t\tvar damage_multiplier: float = 1.0\n\t\tbuff.user_real = damage_multiplier\n\telse:\n\t\tvar damage_multiplier: float = buff.user_real + 0.04\n\t\tbuff.user_real = damage_multiplier\n\n\nfunc omnislashed_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = event.get_target()\n\n\tif caster.get_attack_type() != AttackType.enm.PHYSICAL:\n\t\treturn\n\n\tif event.is_spell_damage():\n\t\treturn\n\n\tvar damage_multiplier: float = buff.user_real\n\tevent.damage *= damage_multiplier\n\n\nfunc mirror_image_pt_on_interpolation_finished(projectile: Projectile, _target: Unit):\n\tprojectile.avert_destruction()\n"
  },
  {
    "path": "src/towers/tower_behaviors/the_steam_engine.gd",
    "content": "extends TowerBehavior\n\n\nvar stun_bt: BuffType\nvar steam_bt: BuffType\nvar multiboard: MultiboardValues\nvar power_level: int = 0\nvar powered_tower_count: int = 0\nvar permanent_effect_id: int = 0\nvar current_mana_degen: float = 0.0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 1.0, 0, false, self)\n\n\tsteam_bt = BuffType.new(\"steam_bt\", 5, 0, true, self)\n\tsteam_bt.set_buff_icon(\"res://resources/icons/generic_icons/pokecog.tres\")\n\tsteam_bt.add_event_on_create(steam_bt_on_create)\n\tsteam_bt.add_event_on_attack(steam_bt_on_attack)\n\tsteam_bt.add_periodic_event(steam_bt_periodic, 1.0)\n\tsteam_bt.add_event_on_cleanup(steam_bt_on_cleanup)\n\tsteam_bt.set_buff_tooltip(tr(\"Z4JU\"))\n\n\tmultiboard = MultiboardValues.new(2)\n\tvar power_level_label: String = tr(\"MMIX\")\n\tvar towers_powered_label: String = tr(\"E78H\")\n\tmultiboard.set_key(0, power_level_label)\n\tmultiboard.set_key(1, towers_powered_label)\n\n\nfunc on_create(_preceding_tower: Tower):\n\tpermanent_effect_id = Effect.create_animated_scaled(\"res://src/effects/cloud_of_fog_cycle.tscn\", Vector3(tower.get_x(), tower.get_y(), tower.get_z() + 60), 0, 0.7)\n\tEffect.set_color(permanent_effect_id, Color8(150, 150, 150, 100))\n\tEffect.set_auto_destroy_enabled(permanent_effect_id, false)\n\n\nfunc on_destruct():\n\tEffect.destroy_effect(permanent_effect_id)\n\n\nfunc periodic(_event: Event):\n\tvar triggered_deactivate: bool = power_level > 0 &&  tower.get_mana() <= 1.0\n\n\tif !triggered_deactivate:\n\t\treturn\n\n\tCombatLog.log_ability(tower, tower, \"Deactivate\")\n\n\tpower_level = 0\n\tengine_update_mana_use()\n\tvar power_level_text: String = tr(\"UQAM\").format({POWER_LEVEL = 0})\n\ttower.get_player().display_floating_text(power_level_text, tower, Color8(50, 150, 100))\n\tstun_bt.apply_only_timed(tower, tower, 120)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tmultiboard.set_value(0, str(power_level))\n\tmultiboard.set_value(1, str(powered_tower_count))\n\n\treturn multiboard\n\n\n# Changes mana regen of tower based on current count of\n# towers affected by aura. Note that regen here can be\n# negative. More towers = more mana spent.\n# NOTE: engine_UpdateManaUse() in original script\nfunc engine_update_mana_use():\n\tvar new_mana_degen: float = power_level * sqrt(powered_tower_count) * 10 / 100.0\n\tvar degen_delta: float = current_mana_degen - new_mana_degen\n\ttower.modify_property(ModificationType.enm.MOD_MANA_REGEN_PERC, degen_delta)\n\tcurrent_mana_degen = new_mana_degen\n\n\n# NOTE: steam_buff_onCreate() in original script\nfunc steam_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\n\tvar mod_value: float = 0.06 * power_level\n\n\tbuff.user_real = mod_value\n\tpowered_tower_count += 1\n\tengine_update_mana_use()\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, mod_value)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, mod_value / 2.0)\n\n\n# NOTE: steam_buff_onAttack() in original script\nfunc steam_bt_on_attack(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\tvar lvl: int = caster.get_level()\n\tvar power_surge_chance: float = 0.01 * caster.get_base_attack_speed()\n\n\tif !caster.calc_chance(power_surge_chance):\n\t\treturn\n\n\tCombatLog.log_ability(caster, buffed_tower, \"Power Surge\")\n\tcaster.add_exp(1 + 0.04 * lvl)\n\tEffect.create_scaled(\"res://src/effects/frag_boom_spawn.tscn\", Vector3(caster.get_x() + 11, caster.get_y() + 56, caster.get_z()), 0, 2)\n\n\n# Update value of property mods based on current power level of Steam Engine\n# NOTE: steam_buff_periodic() in original script\nfunc steam_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\n\tvar current_mod_value: float = buff.user_real\n\tvar new_mod_value: float = 0.06 * power_level\n\tvar mod_value_delta: float = new_mod_value - current_mod_value\n\tbuff.user_real = new_mod_value\n\tbuff.set_displayed_stacks(power_level)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, mod_value_delta)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, mod_value_delta / 2.0)\n\n\n# NOTE: steam_buff_onCleanup() in original script\nfunc steam_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_tower: Unit = buff.get_buffed_unit()\n\tpowered_tower_count -= 1\n\t\n\tvar current_mod_value: float = buff.user_real\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -current_mod_value)\n\tbuffed_tower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -current_mod_value / 2.0)\n\n\nfunc on_autocast_speed_up(_event: Event):\n\tif power_level >= 50:\n\t\treturn\n\t\n\tpower_level += 1\n\tengine_update_mana_use()\n\n\tvar power_level_text: String = tr(\"UQAM\").format({POWER_LEVEL = power_level})\n\ttower.get_player().display_floating_text(power_level_text, tower, Color8(50 + 4 * power_level, 150 - 3 * power_level, 100 - 2 * power_level))\n\n\nfunc on_autocast_speed_down(_event: Event):\n\tif power_level <= 0:\n\t\treturn\n\n\tpower_level -= 1\n\tengine_update_mana_use()\n\n\tvar power_level_text: String = tr(\"UQAM\").format({POWER_LEVEL = power_level})\n\ttower.get_player().display_floating_text(power_level_text, tower, Color8(50 + 4 * power_level, 150 - 3 * power_level, 100 - 2 * power_level))\n"
  },
  {
    "path": "src/towers/tower_behaviors/thief_apprentice.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\nvar steal_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {gold = 0.3, gold_add = 0.012},\n\t\t2: {gold = 0.9, gold_add = 0.036},\n\t\t3: {gold = 2.7, gold_add = 0.108},\n\t\t4: {gold = 6.0, gold_add = 0.240},\n\t\t5: {gold = 12.0, gold_add = 0.480},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tsteal_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 1000, self)\n\tsteal_pt.set_event_on_interpolation_finished(steal)\n\t\n\tmultiboard = MultiboardValues.new(1)\n\tvar gold_stolen_label: String = tr(\"PZL1\")\n\tmultiboard.set_key(0, gold_stolen_label)\n\n\nfunc on_create(preceding_tower: Tower):\n\tif preceding_tower != null && preceding_tower.get_family() == tower.get_family():\n\t\ttower.user_real = preceding_tower.user_real\n\telse:\n\t\ttower.user_real = 0.0\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar gold_stolen_text: String = Utils.format_float(tower.user_real, 0)\n\tmultiboard.set_value(0, gold_stolen_text)\n\t\n\treturn multiboard\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(0.1 + tower.get_level() * 0.004):\n\t\treturn\n\t\n\tCombatLog.log_ability(tower, event.get_target(), \"Steal\")\n\n\tProjectile.create_linear_interpolation_from_unit_to_unit(steal_pt, tower, 0, 0, event.get_target(), tower, 0, true)\n\n\nfunc steal(_p: Projectile, _creep: Unit):\n\tvar level: int = tower.get_level()\n\tvar gold_granted: float = _stats.gold + _stats.gold_add * level\n\ttower.get_player().give_gold(gold_granted, tower, false, true)\n\ttower.user_real += gold_granted\n"
  },
  {
    "path": "src/towers/tower_behaviors/tidewater_stream.gd",
    "content": "extends TowerBehavior\n\n\nvar stun_bt: BuffType\nvar aura_bt: BuffType\nvar splash_bt: BuffType\nvar water_pt: ProjectileType\nvar stone_pt: ProjectileType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar cedi_tidewater_aura_mod: Modifier = Modifier.new()\n\tcedi_tidewater_aura_mod.add_modification(ModificationType.enm.MOD_SPELL_CRIT_CHANCE, 0.1, 0.004)\n\taura_bt.set_buff_modifier(cedi_tidewater_aura_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\taura_bt.set_buff_tooltip(tr(\"WPJN\"))\n\n\tsplash_bt = BuffType.new(\"splash_bt\", 6.0, 0, false, self)\n\tvar cedi_tidewater_splash_mod: Modifier = Modifier.new()\n\tcedi_tidewater_splash_mod.add_modification(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, 0.125, 0.005)\n\tsplash_bt.set_buff_modifier(cedi_tidewater_splash_mod)\n\tsplash_bt.set_buff_icon(\"res://resources/icons/generic_icons/atomic_slashes.tres\")\n\tsplash_bt.set_buff_tooltip(tr(\"ZD87\"))\n\n\twater_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 1200, 700, self)\n\twater_pt.enable_collision(water_pt_on_hit, 200, TargetType.new(TargetType.CREEPS), false)\n\twater_pt.enable_periodic(water_pt_periodic, 0.4)\n\twater_pt.disable_explode_on_expiration()\n\n\tstone_pt = ProjectileType.create_ranged(\"path_to_projectile_sprite\", 500, 800, self)\n\tstone_pt.enable_collision(stone_pt_on_hit, 64, TargetType.new(TargetType.CREEPS), true)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar facing: float = rad_to_deg(atan2(target.get_y() - tower.get_y(), target.get_x() - tower.get_x()))\n\tvar wave_chance: float = 0.15 + 0.006 * tower.get_level()\n\n\tif !tower.calc_chance(wave_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Spring Tide\")\n\n\tvar projectile: Projectile = Projectile.create_from_unit(water_pt, tower, tower, facing, 1.0, tower.calc_spell_crit_no_bonus())\n\tprojectile.set_projectile_scale(0.8)\n\n\nfunc on_damage(event: Event):\n\tvar lvl: int = tower.get_level()\n\tvar target: Unit = event.get_target()\n\tvar splash_chance: float = 0.20 + 0.004 * lvl\n\n\tif !tower.calc_chance(splash_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Splash\")\n\n\tvar effect: int = Effect.create_scaled(\"res://src/effects/naga_death.tscn\", Vector3(target.get_x(), target.get_y(), 0), 0, 3)\n\tEffect.set_lifetime(effect, 3.0)\n\tvar splash_damage: float = 4000 + 160 * lvl\n\ttower.do_spell_damage_aoe_unit(target, 175, splash_damage, tower.calc_spell_crit_no_bonus(), 0)\n\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 175)\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tsplash_bt.apply(tower, next, lvl)\n\n\nfunc water_pt_on_hit(p: Projectile, target: Unit):\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/crushing_wave.tscn\", target, Unit.BodyPart.CHEST)\n\tvar caster: Unit = p.get_caster()\n\tvar wave_damage: float = 2200 + 88 * caster.get_level()\n\tcaster.do_spell_damage(target, wave_damage, caster.calc_spell_crit_no_bonus())\n\n\nfunc water_pt_periodic(p: Projectile):\n\tvar caster: Unit = p.get_caster()\n\n\tvar stone_chance: float = 0.35\n\tif !caster.calc_chance(stone_chance):\n\t\treturn\n\t\t\n\tvar stone_x: float = p.get_x() + Globals.synced_rng.randf_range(-30, 30)\n\tvar stone_y: float = p.get_y() + Globals.synced_rng.randf_range(-30, 30)\n\tvar stone_facing: float = p.get_direction() + Globals.synced_rng.randf_range(-30, 30)\n\tvar stone_projectile: Projectile = Projectile.create(stone_pt, caster, 1.0, caster.calc_spell_crit_no_bonus(), Vector3(stone_x, stone_y, 0), stone_facing)\n\n\tEffect.add_special_effect(\"res://src/effects/impale_target_dust.tscn\", Vector2(stone_projectile.get_x(), stone_projectile.get_y()))\n\n\nfunc stone_pt_on_hit(p: Projectile, target: Unit):\n\tvar caster: Unit = p.get_caster()\n\tvar wave_damage: float = 2200 + 88 * caster.get_level()\n\tcaster.do_spell_damage(target, wave_damage, caster.calc_spell_crit_no_bonus())\n\tstun_bt.apply_only_timed(caster, target, 0.65)\n"
  },
  {
    "path": "src/towers/tower_behaviors/time_manipulator.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_BUG] Fixed error in original script\n# where \"Time Field\" buff was \"unfriendly\" even though it's\n# applied on a tower. Changed it to \"friendly\".\n\n\nvar aura_bt: BuffType\nvar time_field_bt: BuffType\nvar multiboard: MultiboardValues\nvar exp_exchanged: int\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_periodic_event(periodic, 10)\n\n\nfunc tower_init():\n\ttime_field_bt = BuffType.new(\"time_field_bt\", 10, 0, true, self)\n\ttime_field_bt.set_special_effect(\"res://src/effects/spell_aire.tscn\", 150, 1.0)\n\ttime_field_bt.add_periodic_event(time_field_bt_periodic, 1.0)\n\ttime_field_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\ttime_field_bt.set_buff_tooltip(tr(\"ZD87\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar aura_bt_mod: Modifier = Modifier.new()\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_EXP_RECEIVED, 0.1, 0.016)\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.1, 0.01)\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_MANA_REGEN_PERC, 0.05, 0.02)\n\taura_bt_mod.add_modification(ModificationType.enm.MOD_BUFF_DURATION, 0.125, 0.015)\n\taura_bt.set_buff_modifier(aura_bt_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\taura_bt.set_buff_tooltip(tr(\"WG04\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar exp_exchanged_label: String = tr(\"MOLD\")\n\tmultiboard.set_key(0, exp_exchanged_label)\n\n\nfunc on_create(_preceding: Tower):\n\texp_exchanged = 0\n\n\nfunc on_destruct():\n\ttower.add_exp_flat(exp_exchanged)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar exp_exchanged_string: String = str(exp_exchanged)\n\tmultiboard.set_value(0, exp_exchanged_string)\n\n\treturn multiboard\n\n\nfunc periodic(_event: Event):\n\tif tower.get_exp() >= 700:\n\t\ttower.remove_exp_flat(50)\n\t\texp_exchanged += 50\n\t\ttower.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, 0.05)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/charm_target.tscn\", tower, Unit.BodyPart.OVERHEAD)\n\telse:\n\t\ttower.add_exp(2)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/blink_target.tscn\", tower, Unit.BodyPart.CHEST)\n\n\nfunc on_autocast(_event: Event):\n\ttime_field_bt.apply(tower, tower, tower.get_level())\n\n\n# NOTE: \"MajFieldDamage()\" in original script\nfunc time_field_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar caster: Tower = buff.get_caster()\n\tvar damage: float = 1500 + 75 * buff.get_level()\n\n\tcaster.do_spell_damage_pb_aoe(950, damage, caster.calc_spell_crit_no_bonus(), 0.0)\n"
  },
  {
    "path": "src/towers/tower_behaviors/timevault.gd",
    "content": "extends TowerBehavior\n\n\nvar aura_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_TRIGGER_CHANCES, 0.30, 0.006)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/electric.tres\")\n\taura_bt.set_buff_tooltip(tr(\"CC46\"))\n\n\nfunc on_damage(event: Event):\n\tvar creep: Creep = event.get_target()\n\tvar target_is_boss: bool = creep.get_size() >= CreepSize.enm.BOSS\n\tvar chance_for_boss: float = 0.20 + 0.005 * tower.get_level()\n\n\tif target_is_boss && !tower.calc_chance(chance_for_boss):\n\t\treturn\n\n\tvar old_position: Vector2 = creep.get_position_wc3_2d()\n\tvar old_path_index: int = creep._current_path_index\n\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/mass_teleport_caster.tscn\", creep, Unit.BodyPart.ORIGIN)\n\tEffect.set_auto_destroy_enabled(effect, false)\n\n\tawait Utils.create_manual_timer(3.0, self).timeout\n\n\tEffect.destroy_effect(effect)\n\n#\tNOTE: need to also restore old path index because\n#\totherwise the creep would be teleported to old position\n#\tbut will go in a straight line towards some further path\n#\tpoint.\n\tif Utils.unit_is_valid(creep):\n\t\tcreep.set_position_wc3_2d(old_position)\n\t\tcreep._current_path_index = old_path_index\n\t\tEffect.create_simple_at_unit(\"res://src/effects/silence_area.tscn\", creep)\n"
  },
  {
    "path": "src/towers/tower_behaviors/tiny_storm_lantern.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: added more checks for validity of units\n\n\nvar ball: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {num_shots = 2},\n\t\t2: {num_shots = 3},\n\t\t3: {num_shots = 4},\n\t\t4: {num_shots = 5},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\n\nfunc hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\ttower.do_attack_damage(creep, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit(0, 0, 0))\n\n\nfunc new_attack(num_shots: int, creep: Creep):\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), creep, 300)\n\tvar next: Creep\n\n\tawait Utils.create_manual_timer(0.2, self).timeout\n\n\tnext = it.next_random()\n\n\twhile true:\n\t\tif next == null:\n\t\t\tif !Utils.unit_is_valid(tower) || !Utils.unit_is_valid(creep):\n\t\t\t\treturn\n\n\t\t\tProjectile.create_from_unit_to_unit(ball, tower, 1, 0, tower, creep, true, false, false).set_projectile_scale(0.5)\n\t\telse:\n\t\t\tProjectile.create_from_unit_to_unit(ball, tower, 1, 0, tower, next, true, false, false).set_projectile_scale(0.5)\n\t\t\tnext = it.next_random()\n\n\t\tnum_shots = num_shots - 1\n\n\t\tif num_shots == 0:\n\t\t\treturn\n\n\t\tawait Utils.create_manual_timer(0.2, self).timeout\n\n\nfunc tower_init():\n\tball = ProjectileType.create(\"path_to_projectile_sprite\", 4, 1000, self)\n\tball.enable_homing(hit, 0)\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(0.2 + 0.01 * tower.get_level()):\n\t\treturn\n\n\tvar creep: Creep = event.get_target()\n\tvar num_shots: int = _stats.num_shots\n\tvar twr_level: int = tower.get_level()\n\n\tCombatLog.log_ability(tower, creep, \"Burst Lightning\")\n\n\tif twr_level == 25:\n\t\tnum_shots = num_shots + 2\n\telif twr_level >= 15:\n\t\tnum_shots = num_shots + 1\n\n\tnew_attack(num_shots, creep)\n"
  },
  {
    "path": "src/towers/tower_behaviors/tombstone.gd",
    "content": "extends TowerBehavior\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {chance_base = 0.008, chance_add = 0.0015},\n\t\t2: {chance_base = 0.010, chance_add = 0.0017},\n\t\t3: {chance_base = 0.012, chance_add = 0.0020},\n\t\t4: {chance_base = 0.014, chance_add = 0.0022},\n\t\t5: {chance_base = 0.016, chance_add = 0.0024},\n\t\t6: {chance_base = 0.020, chance_add = 0.0025},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_event_on_damage(on_damage)\n\n\nfunc on_damage(event: Event):\n\tif !tower.calc_chance(_stats.chance_base + tower.get_level() * _stats.chance_add):\n\t\treturn\n\n\tvar creep: Unit = event.get_target()\n\tvar size: int = creep.get_size()\n\n\tif size < CreepSize.enm.CHAMPION:\n\t\tCombatLog.log_ability(tower, creep, \"Tomb's Curse\")\n\t\ttower.kill_instantly(creep)\n\t\tEffect.create_simple_at_unit(\"res://src/effects/death_coil.tscn\", creep)\n"
  },
  {
    "path": "src/towers/tower_behaviors/tundra_stalker.gd",
    "content": "extends TowerBehavior\n\n\nvar ice_claw_bt: BuffType\nvar frenzy_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {frenzy_max_bonus = 1.0, buff_level = 0, spell_damage = 50, spell_damage_add = 2},\n\t\t2: {frenzy_max_bonus = 1.125, buff_level = 1, spell_damage = 100, spell_damage_add = 4},\n\t\t3: {frenzy_max_bonus = 1.25, buff_level = 2, spell_damage = 200, spell_damage_add = 8},\n\t\t4: {frenzy_max_bonus = 1.375, buff_level = 3, spell_damage = 400, spell_damage_add = 16},\n\t\t5: {frenzy_max_bonus = 1.5, buff_level = 4, spell_damage = 600, spell_damage_add = 24},\n\t}\n\n\nfunc on_autocast(event: Event):\n\tif tower.user_real < _stats.frenzy_max_bonus:\n\t\ttower.user_real = tower.user_real + 0.005\n\t\ttower.user_int += 1\n\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, 0.005)\n\n\t\tvar frenzy_buff: Buff = tower.get_buff_of_type(frenzy_bt)\n\t\tvar stack_count: int = tower.user_int\n\t\tfrenzy_buff.set_displayed_stacks(stack_count)\n\n\tEffect.create_simple_at_unit(\"res://src/effects/frost_bolt_missile.tscn\", event.get_target())\n\tevent.get_target().set_sprite_color(Color8(100, 100, 255, 255))\n\tice_claw_bt.apply_custom_timed(tower, event.get_target(), _stats.buff_level, 5 + 0.2 * tower.get_level()).user_real = _stats.spell_damage + _stats.spell_damage_add * tower.get_level()\n\n\nfunc drol_f_tundraStalker(event: Event):\n\tvar b: Buff = event.get_buff()\n\tb.get_caster().do_spell_damage(b.get_buffed_unit(), b.user_real, b.get_caster().calc_spell_crit_no_bonus())\n\n\nfunc drol_fade_tundraStalker(event: Event):\n\tvar b: Buff = event.get_buff()\n\tb.get_buffed_unit().set_sprite_color(Color.WHITE)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.2, -0.05)\n\n\tice_claw_bt = BuffType.new(\"ice_claw_bt\", 5, 0.2, false, self)\n\tice_claw_bt.set_buff_modifier(m)\n\t\n\tice_claw_bt.set_buff_icon(\"res://resources/icons/generic_icons/triple_scratches.tres\")\n\tice_claw_bt.add_periodic_event(drol_f_tundraStalker, 1)\n\tice_claw_bt.add_event_on_cleanup(drol_fade_tundraStalker)\n\n\tice_claw_bt.set_buff_tooltip(tr(\"MEE0\"))\n\n\tfrenzy_bt = BuffType.new(\"frenzy_bt\", -1, 0, true, self)\n\tfrenzy_bt.set_buff_icon(\"res://resources/icons/generic_icons/alligator_clip.tres\")\n\tfrenzy_bt.set_buff_tooltip(tr(\"LGWY\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar speed_bonus_label: String = tr(\"U88K\")\n\tmultiboard.set_key(0, speed_bonus_label)\n\n\nfunc on_create(preceding: Tower):\n\tif preceding != null && preceding.get_family() == tower.get_family():\n\t\ttower.user_real = preceding.user_real\n\t\ttower.user_int = preceding.user_int\n\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, preceding.user_real)\n\telse:\n\t\ttower.user_real = 0\n\t\ttower.user_int = 0\n\n\tvar buff: Buff = frenzy_bt.apply_to_unit_permanent(tower, tower, 0)\n\tvar stack_count: int = tower.user_int\n\tbuff.set_displayed_stacks(stack_count)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar speed_bonus_text: String = Utils.format_percent(tower.user_real, 1)\n\tmultiboard.set_value(0, speed_bonus_text)\n\n\treturn multiboard\n"
  },
  {
    "path": "src/towers/tower_behaviors/undisturbed_crypt.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: reworked JASS script. Instead of storing buff\n# level in userInt I calculate it when it's needed. This\n# makes the incDmg function unnecessary. Changed periodic\n# function to attach to triggers buff type in\n# load_triggers() instead of to EventTypeList in\n# tower_init().\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Changed script to not make\n# corpse invisible when exploding coprses. It looks weird\n# because it can interrupt the death animation. Working\n# around this problem also caused desync issues so removed\n# work arounds.\n\n\nvar ball_pt: ProjectileType\nvar meat_pt: ProjectileType\nvar corpse_explosion_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {critical_mass_chance = 0.30, buff_level = 50, buff_level_add = 2},\n\t\t2: {critical_mass_chance = 0.33, buff_level = 80, buff_level_add = 3},\n\t\t3: {critical_mass_chance = 0.36, buff_level = 130, buff_level_add = 4},\n\t\t4: {critical_mass_chance = 0.39, buff_level = 200, buff_level_add = 6},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_periodic_event(periodic, 5)\n\n\nfunc burst_fire(chance: float, target: Creep):\n\tvar num_shots: int = 0\n\n\twhile true:\n\t\tvar p: Projectile = Projectile.create_from_unit_to_unit(ball_pt, tower, 1.0, 1.0, tower, target, true, false, false)\n\t\tp.set_projectile_scale(0.4)\n\t\tnum_shots = num_shots + 1\n\n\t\tif !tower.calc_chance(chance) || num_shots >= 14 || !Utils.unit_is_valid(target):\n\t\t\tbreak\n\n\tCombatLog.log_ability(tower, null, \"Critical Mass %d\" % num_shots)\n\n\nfunc ball_pt_on_hit(_p: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\ttower.do_attack_damage(creep, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit(0, 0, 0))\n\n\nfunc tower_init():\n\tball_pt = ProjectileType.create(\"path_to_projectile_sprite\", 5, 500, self)\n\tball_pt.enable_homing(ball_pt_on_hit, 0)\n\n\tmeat_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 400, self)\n\n\tvar m: Modifier = Modifier.new()\n\tm.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.001)\n\tm.add_modification(ModificationType.enm.MOD_DMG_FROM_DARKNESS, 0.0, 0.001)\n\n\tcorpse_explosion_bt = BuffType.new(\"corpse_explosion_bt\", 8, 0.25, false, self)\n\tcorpse_explosion_bt.set_buff_icon(\"res://resources/icons/generic_icons/mine_explosion.tres\")\n\tcorpse_explosion_bt.set_buff_modifier(m)\n\tcorpse_explosion_bt.set_buff_tooltip(tr(\"MX79\"))\n\n\nfunc on_attack(event: Event):\n\tif !tower.calc_chance(0.3 + 0.003 * tower.get_level()):\n\t\treturn\n\n\tvar chance: float = _stats.critical_mass_chance + 0.006 * tower.get_level()\n\tburst_fire(chance, event.get_target())\n\n\n# NOTE: this f-n is named \"fire()\" in JASS script\nfunc periodic(_event: Event):\n\tvar corpses_in_range: Iterate = Iterate.over_corpses_in_range(tower, Vector2(tower.get_x(), tower.get_y()), 1000)\n\n\tvar target_corpse: Unit = null\n\n\twhile true:\n\t\tvar corpse: Unit = corpses_in_range.next_corpse()\n\t\t\n\t\tif corpse == null:\n\t\t\tbreak\n\n\t\tvar creeps_in_range_of_corpse_it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(corpse.get_x(), corpse.get_y()), 500)\n\n\t\tif creeps_in_range_of_corpse_it.count() > 0:\n\t\t\ttarget_corpse = corpse\n\n\t\t\tbreak\n\n\tif target_corpse == null:\n\t\treturn\n\n\tvar tx: float = target_corpse.get_x()\n\tvar ty: float = target_corpse.get_y()\n\n\tEffect.add_special_effect(\"res://src/effects/starfall_target.tscn\", Vector2(tx, ty))\n\tEffect.create_scaled(\"res://src/effects/blood_splatter.tscn\", Vector3(tx, ty, 0), Globals.synced_rng.randf_range(0, 360), 2)\n\n\tvar corpse_explosion_it: Iterate = Iterate.over_units_in_range_of(tower, TargetType.new(TargetType.CREEPS), Vector2(tx, ty), 500)\n\n\tvar buff_level: int = _stats.buff_level + _stats.buff_level_add * tower.get_level()\n\n\twhile true:\n\t\tvar creep: Unit = corpse_explosion_it.next()\n\n\t\tif creep == null:\n\t\t\tbreak\n\n\t\tvar projectile: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(meat_pt, tower, 0, 0, tower, creep, 0, true)\n\t\tprojectile.set_projectile_scale(0.5)\n\n\t\tcorpse_explosion_bt.apply(tower, creep, buff_level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/valor.gd",
    "content": "extends TowerBehavior\n\n\nvar wewillnotfall_bt: BuffType\nvar valor_light_bt: BuffType\nvar lastline_real_bt: BuffType\nvar lastline_dummy_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 800, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n#\tDummy Buff, to count the times a unit entered\n\tlastline_dummy_bt = BuffType.new(\"lastline_dummy_bt\", -1.0, 0, false, self)\n\tlastline_dummy_bt.set_hidden()\n\n#\tReal buff, adding the damage bonus.\n\tlastline_real_bt = BuffType.new(\"lastline_real_bt\", -1.0, 0, false, self)\n\tlastline_real_bt.set_buff_icon(\"res://resources/icons/generic_icons/semi_closed_eye.tres\")\n\tlastline_real_bt.set_buff_tooltip(tr(\"ZCGI\"))\n\n\twewillnotfall_bt = BuffType.create_aura_effect_type(\"wewillnotfall_bt\", true, self)\n\twewillnotfall_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\twewillnotfall_bt.add_event_on_create(wewillnotfall_bt_on_create)\n\twewillnotfall_bt.add_periodic_event(wewillnotfall_bt_periodic, 15.0)\n\twewillnotfall_bt.add_event_on_cleanup(wewillnotfall_bt_on_cleanup)\n\twewillnotfall_bt.set_buff_tooltip(tr(\"I9KE\"))\n\n\tvalor_light_bt = BuffType.new(\"valor_light_bt\", 5.0, 0, false, self)\n\tvar cedi_valor_light_mod: Modifier = Modifier.new()\n\tcedi_valor_light_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, 0.0, -0.001)\n\tvalor_light_bt.set_buff_modifier(cedi_valor_light_mod)\n\tvalor_light_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tvalor_light_bt.add_periodic_event(valor_light_bt_periodic, 1.0)\n\tvalor_light_bt.set_buff_tooltip(tr(\"X9QW\"))\n\n\nfunc on_unit_in_range(event: Event):\n\tvar creep: Unit = event.get_target()\n\n\tvar valor_buff_level: int = 300 + 12 * tower.get_level()\n\tvar valor_buff: Buff = valor_light_bt.apply(tower, creep, valor_buff_level)\n\tvalor_buff.user_real = 2000 + 80 * tower.get_level()\n\tvalor_buff.user_int = 0\n\n#\tThis function is normally called from periodic event\n#\thandler of buff but call it here for the first time to\n#\tensure that the setup has already run.\n\tvalor_light_bt_adjust_effect(valor_buff)\n\n\tvar lastline_dummy_buff: Buff = creep.get_buff_of_type(lastline_dummy_bt)\n\n#\tSecond time walking past?\n\tif lastline_dummy_buff != null:\n\t\t# Yes!\n\t\tlastline_dummy_buff.remove_buff()\n\n\t\t# Apply the last line buff. (Only visuals, effect is permanent, no cleanup required)\n\t\tlastline_real_bt.apply(tower, creep, tower.get_level())\n\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 400)\n\n\t\t# Calculate the amount of additional damage they should take.\n\t\tvar amount: float = 0.0\n\t\twhile true:\n\t\t\tvar next: Tower = it.next()\n\n\t\t\tif next == null:\n\t\t\t\tbreak\n\n\t\t\tif next != tower:\n\t\t\t\tamount += min(next.get_gold_cost() / 2500.0, 1.0) * (0.01 + 0.0008 * tower.get_level())\n\n#\t\tModify the damage they take.\n\t\tcreep.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED, amount)\n\t\tcreep.modify_property(ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED, amount)\n\telse:\n#\t\tNo, check if it already has the last line buff\n\t\tvar lastline_real_buff: Buff = creep.get_buff_of_type(lastline_real_bt)\n\n\t\tif lastline_real_buff == null:\n#\t\t\tNo? Okay, let's add the dummy.\n\t\t\tlastline_dummy_bt.apply(tower, creep, 0)\n\n\nfunc wewillnotfall_bt_on_create(event: Event):\n\tvar buff: Buff = event.get_buff()\n\twewillnotfall_bt_adjust_effect(buff)\n\n\nfunc wewillnotfall_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\twewillnotfall_bt_adjust_effect(buff)\n\n\nfunc wewillnotfall_bt_adjust_effect(buff: Buff):\n\tvar caster: Unit = buff.get_caster()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar current_bonus: float = buff.user_real\n\tvar new_bonus: float = (100 - tower.get_player().get_team().get_lives_percent()) / 100.0 * (0.5 + 0.02 * caster.get_level())\n\tvar delta: float = new_bonus - current_bonus\n\n\tif delta != 0:\n\t\tbuffed_unit.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, delta)\n\t\tbuffed_unit.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, delta)\n\t\tbuff.user_real = new_bonus\n\n\nfunc wewillnotfall_bt_on_cleanup(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar current_bonus: float = buff.user_real\n\tbuffed_unit.modify_property(ModificationType.enm.MOD_SPELL_DAMAGE_DEALT, -current_bonus)\n\tbuffed_unit.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, -current_bonus)\n\n\nfunc valor_light_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvalor_light_bt_adjust_effect(buff)\n\n\nfunc valor_light_bt_adjust_effect(buff: Buff):\n\tvar caster: Unit = buff.get_caster()\n\tvar creep: Unit = buff.get_buffed_unit()\n\n\tif buff.user_int == 0:\n#\t\tFirst time, only slow, flag being first\n\t\tbuff.user_int = 1\n\telse:\n#\t\tAdditional times, decrease slow effect!\n\t\tbuff.set_level(buff.get_level() / 2)\n\n#\tDeal the right amount of damage\n\tcaster.do_spell_damage(creep, buff.user_real, caster.calc_spell_crit_no_bonus())\n#\tAdjust the amount of damage dealt.\n\tbuff.user_real *= 0.5\n\n#\tSome sfx to pretty it up\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/spell_aiil.tscn\", creep, Unit.BodyPart.CHEST)\n"
  },
  {
    "path": "src/towers/tower_behaviors/village_witch.gd",
    "content": "extends TowerBehavior\n\n\nvar love_bt: BuffType\nvar soul_split_bt: BuffType\nvar missile_pt: ProjectileType\nvar current_soul_split_stacks: int = 0\n\n\nconst POTION_DURATION: float = 7.0\nconst MOD_MOVESPEED_ADD: float = 0.00375\nconst MOD_ITEM_CHANCE_ADD: float = 0.003\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_movespeed = 0.25, mod_item_chance = 0.200, soul_chance = 30, soul_damage = 50, soul_damage_add = 2, soul_duration = 10, soul_chance_decrease = 10, mod_attack_speed = 0.10},\n\t\t2: {mod_movespeed = 0.32, mod_item_chance = 0.256, soul_chance = 36, soul_damage = 400, soul_damage_add = 16, soul_duration = 12, soul_chance_decrease = 9, mod_attack_speed = 0.15},\n\t\t3: {mod_movespeed = 0.36, mod_item_chance = 0.288, soul_chance = 39, soul_damage = 800, soul_damage_add = 32, soul_duration = 13, soul_chance_decrease = 8.5, mod_attack_speed = 0.20},\n\t\t4: {mod_movespeed = 0.42, mod_item_chance = 0.336, soul_chance = 42, soul_damage = 2000, soul_damage_add = 80, soul_duration = 15, soul_chance_decrease = 8, mod_attack_speed = 0.25},\n\t}\n\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc on_autocast(event: Event):\n\tvar target: Unit = event.get_target()\n\n\tProjectile.create_from_unit_to_unit(missile_pt, tower, 1.00, 1.0, tower, target, true, false, false)\n\n\n# NOTE: cedi_Love() in original script\nfunc missile_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar level: int = tower.get_level()\n\n\tlove_bt.apply(tower, target, level)\n\n\nfunc tower_init():\n\tlove_bt = BuffType.new(\"love_bt\", POTION_DURATION, 0, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH, _stats.mod_item_chance, MOD_ITEM_CHANCE_ADD)\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -_stats.mod_movespeed, -MOD_MOVESPEED_ADD)\n\tlove_bt.set_buff_modifier(mod)\n\tlove_bt.set_buff_icon(\"res://resources/icons/generic_icons/charm.tres\")\n\tlove_bt.set_buff_tooltip(tr(\"W4SL\"))\n\n#\tNOTE: this buff is needed to display the effect of the\n#\t\"Soul Split\" ability. The actual effect of the ability\n#\tis implemented via modify_property().\n\tsoul_split_bt = BuffType.new(\"soul_split_bt\", 10, 0, true, self)\n\tsoul_split_bt.set_buff_icon(\"res://resources/icons/generic_icons/rss.tres\")\n\tsoul_split_bt.set_buff_tooltip(tr(\"BNH6\"))\n\n\tmissile_pt = ProjectileType.create(\"path_to_projectile_sprite\", 999.99, 1100, self)\n\tmissile_pt.enable_homing(missile_pt_on_hit, 0.0)\n\n\nfunc on_damage(event: Event):\n\tvar multiplier: float = 1.00\n\n\tif tower.calc_chance(tower.user_real / 100.0):\n\t\tif event.get_target().get_buff_of_type(love_bt) != null:\n\t\t\tCombatLog.log_ability(tower, event.get_target(), \"Soul Split x2\")\n\t\t\t\n\t\t\tmultiplier = 2.0\n\t\t\ttower.get_player().display_floating_text_x(\"Double\", tower, Color8(255, 0, 0, 255), 64, 1, 2)\n\t\telse:\n\t\t\tCombatLog.log_ability(tower, event.get_target(), \"Soul Split\")\n\n\t\tEffect.create_simple_at_unit(\"res://src/effects/undead_dissipate.tscn\", tower)\n\t\ttower.do_spell_damage(event.get_target(), (_stats.soul_damage + _stats.soul_damage_add * tower.get_level()) * multiplier, tower.calc_spell_crit_no_bonus())\n\t\tvar soul_split_buff: Buff = soul_split_bt.apply_custom_timed(tower, tower, 1, _stats.soul_duration * multiplier)\n\t\ttower.user_real = tower.user_real - _stats.soul_chance_decrease\n\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, _stats.mod_attack_speed * multiplier)\n\t\tcurrent_soul_split_stacks += 1\n\n\t\tsoul_split_buff.set_displayed_stacks(current_soul_split_stacks)\n\n\t\tawait Utils.create_manual_timer(10.0 * multiplier, self).timeout\n\n\t\tif Utils.unit_is_valid(tower):\n\t\t\ttower.modify_property(ModificationType.enm.MOD_ATTACKSPEED, -_stats.mod_attack_speed * multiplier)\n\t\t\ttower.user_real = tower.user_real + _stats.soul_chance_decrease\n\t\t\tcurrent_soul_split_stacks -= 1\n\n\t\t\tsoul_split_buff = tower.get_buff_of_type(soul_split_bt)\n\t\t\tif soul_split_buff != null:\n\t\t\t\tsoul_split_buff.set_displayed_stacks(current_soul_split_stacks)\n\n\nfunc on_create(_preceding_tower: Tower):\n\ttower.user_real = _stats.soul_chance\n"
  },
  {
    "path": "src/towers/tower_behaviors/void_drake.gd",
    "content": "extends TowerBehavior\n\n\nvar silence_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {mod_damage_add = 0.12, silence_duration = 1.25, silence_duration_add = 0.07, boss_silence_multiplier = 0.33, void_exp_loss = 0.010, void_exp_loss_add = 0.0002},\n\t\t2: {mod_damage_add = 0.20, silence_duration = 1.75, silence_duration_add = 0.13, boss_silence_multiplier = 0.25, void_exp_loss = 0.015, void_exp_loss_add = 0.0003},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 1.0)\n\n\nfunc tower_init():\n\tsilence_bt = CbSilence.new(\"void_drake_silence\", 0, 0, false, self)\n\n\nfunc on_damage(event: Event):\n\tvar creep: Unit = event.get_target()\n\n\tvar silence_duration: float = _stats.silence_duration + _stats.silence_duration_add * tower.get_level()\n\tif creep.get_size() == CreepSize.enm.BOSS:\n\t\tsilence_duration = silence_duration * _stats.boss_silence_multiplier\n\n\tsilence_bt.apply_only_timed(tower, event.get_target(), silence_duration)\n\n\nfunc periodic(_event: Event):\n\tvar level: int = tower.get_level()\n\tvar current_exp: float = tower.get_exp()\n\tvar exp_for_level: int = Experience.get_exp_for_level(level)\n\tvar exp_before_level_down: float = current_exp - exp_for_level\n\tvar exp_removed: float = current_exp * (_stats.void_exp_loss + _stats.void_exp_loss_add * level)\n\n\tif exp_removed > exp_before_level_down:\n\t\texp_removed = exp_before_level_down\n\n\tif exp_removed >= 0.1 && level != 25:\n\t\ttower.remove_exp_flat(exp_removed)\n\n\nfunc on_create(preceding: Tower):\n\tif preceding == null:\n\t\treturn\n\t\n\tvar same_family: bool = tower.get_family() == preceding.get_family()\n\n\tif same_family:\n\t\tvar exp_loss: float = tower.get_exp() * (0.5 + 0.01 * tower.get_level())\n\t\ttower.remove_exp_flat(exp_loss)\n\telse:\n\t\tvar exp_loss: float = tower.get_exp()\n\t\ttower.remove_exp_flat(exp_loss)\n"
  },
  {
    "path": "src/towers/tower_behaviors/vulshok_the_berserker.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: this is the \"fizzbuzz tower\" ;)\n\n\n# NOTE: SCALE_MIN should match the value in tower sprite\n# scene\nconst SCALE_MIN: float = 0.7\nconst SCALE_MAX: float = 1.2\n\n\nvar slow_bt: BuffType\nvar grow_bt: BuffType\nvar multiboard: MultiboardValues\n\n\nvar attack_count: int = 0\nvar do_splash_next: bool = false\nvar growth_count: int = 0\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tmultiboard = MultiboardValues.new(4)\n\tvar attacks_to_crit_label: String = tr(\"HZU6\")\n\tvar attacks_to_damage_label: String = tr(\"NB2A\")\n\tvar attacks_to_splash_label: String = tr(\"HFOL\")\n\tvar attacks_to_grow_label: String = tr(\"LBKG\")\n\tmultiboard.set_key(0, attacks_to_crit_label)\n\tmultiboard.set_key(1, attacks_to_damage_label)\n\tmultiboard.set_key(2, attacks_to_splash_label)\n\tmultiboard.set_key(3, attacks_to_grow_label)\n\n\tslow_bt = BuffType.new(\"slow_bt\", 5, 0, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_MOVESPEED, -0.10, -0.001)\n\tslow_bt.set_buff_modifier(mod)\n\tslow_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\tslow_bt.set_buff_tooltip(tr(\"GLMC\"))\n\tslow_bt.add_periodic_event(slow_bt_periodic, 1.0)\n\n\tgrow_bt = BuffType.new(\"grow_bt\", -1, 0, true, self)\n\tgrow_bt.set_buff_icon(\"res://resources/icons/generic_icons/biceps.tres\")\n\tgrow_bt.set_buff_tooltip(tr(\"KQ64\"))\n\n\nfunc on_create(_preceding: Tower):\n\tvar grow_buff: Buff = grow_bt.apply_to_unit_permanent(tower, tower, 0)\n\tgrow_buff.set_displayed_stacks(growth_count)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar crit: int = 0\n\n\tattack_count += 1\n\n#\tCrit (every 3rd)\n\tif attack_count % 3 == 0:\n\t\tCombatLog.log_ability(tower, null, \"Crit\")\n\t\ttower.add_attack_crit()\n#\t\tSo the triggered attack damage can crit too!\n\t\tcrit = 1\n\n#\tBonus damage (every 7th)\n\tif attack_count % 7 == 0:\n\t\tCombatLog.log_ability(tower, null, \"Bonus Damage\")\n#\t\tSplashed bonus damage (every 84th)\n\t\tif attack_count % 12 == 0:\n\t\t\ttower.do_attack_damage_aoe_unit(target, 200, 3000 + 200 * level, tower.calc_attack_multicrit(0, 0, crit), 0)\n\t\t\tvar effect: int = Effect.create_scaled(\"res://src/effects/doom_death.tscn\", Vector3(target.get_x(), target.get_y(), 0), 0, 1)\n\t\t\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\t\telse:\n\t\t\ttower.do_attack_damage(target, 3000 + 200 * level, tower.calc_attack_multicrit(0, 0, crit), 0)\n\t\t\tvar effect: int = Effect.create_scaled(\"res://src/effects/doom_death.tscn\", Vector3(target.get_x(), target.get_y(), 0), 0, 1)\n\t\t\tEffect.set_z_index(effect, Effect.Z_INDEX_BELOW_CREEPS)\n\n#\tSplash (every 12th)\n\tif attack_count % 12 == 0:\n\t\tCombatLog.log_ability(tower, null, \"Splash\")\n\t\tdo_splash_next = true\n\n#\tGrowth (every 15th)\n\tif attack_count % 15 == 0:\n\t\tCombatLog.log_ability(tower, null, \"Growth\")\n\t\t\n\t\ttower.modify_property(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.005)\n\n#\t\tRare text has increased chance to show with increased triggerchances. ;]\n\t\tvar floating_text: String\n\t\tif tower.calc_chance(0.005):\n\t\t\tvar bathe_in_blood_text: String = tr(\"DQXT\")\n\t\t\tfloating_text = bathe_in_blood_text\n\t\telif tower.calc_chance(0.1):\n\t\t\tvar fear_me_text: String = tr(\"C08E\")\n\t\t\tfloating_text = fear_me_text\n\t\telif tower.calc_chance(0.4):\n\t\t\tvar grrr_text: String = tr(\"MRXN\")\n\t\t\tfloating_text = grrr_text\n\t\telse:\n\t\t\tvar roar_text: String = tr(\"JXN3\")\n\t\t\tfloating_text = roar_text\n\n\t\ttower.get_player().display_floating_text(floating_text, tower, Color8(255, 100, 100))\n\n#\t\tIncrease model size\n\t\tgrowth_count += 1\n\n\t\tvar grow_buff: Buff = tower.get_buff_of_type(grow_bt)\n\t\tgrow_buff.set_displayed_stacks(growth_count)\n\n\t\tvar tower_scale: float = Utils.get_scale_from_grows(SCALE_MIN, SCALE_MAX, growth_count, 1000)\n\t\ttower.set_unit_scale(tower_scale)\n\n\tif attack_count >= 420:\n\t\tattack_count = 0\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\n\tif do_splash_next:\n\t\tdo_splash_next = false\n\n#\t\t+1 multicrit count for the guaranteed crit every three attacks\n\t\ttower.do_attack_damage_aoe_unit(target, 200, tower.get_current_attack_damage_with_bonus(), tower.calc_attack_multicrit(0, 0, 1), 0.0)\n\n#\t\tCancel damage from regular attack\n\t\tevent.damage = 0\n\n#\t\tApply slow to all creeps hit\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), target, 200)\n\t\t\n\t\twhile true:\n\t\t\tvar creep: Creep = it.next()\n\n\t\t\tif creep == null:\n\t\t\t\tbreak\n\n\t\t\tif creep.get_buff_of_type(slow_bt) == null:\n\t\t\t\tslow_bt.apply(tower, creep, 0)\n\telse:\n\t\tif target.get_buff_of_type(slow_bt) == null:\n\t\t\tslow_bt.apply(tower, target, 0)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar attacks_to_crit: String = str(3 - attack_count % 3)\n\tvar attacks_to_damage: String = str(7 - attack_count % 7)\n\tvar attacks_to_splash: String = str(12 - attack_count % 12)\n\tvar attacks_to_grow: String = str(15 - attack_count % 15)\n\n\tmultiboard.set_value(0, attacks_to_crit)\n\tmultiboard.set_value(1, attacks_to_damage)\n\tmultiboard.set_value(2, attacks_to_splash)\n\tmultiboard.set_value(3, attacks_to_grow)\n\n\treturn multiboard\n\n\nfunc slow_bt_periodic(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar active_level: int = buff.get_level()\n\tvar slow_per_stack: float = 0.05 + 0.01 * tower.get_level()\n\tvar new_level: int = active_level + floori(slow_per_stack * 1000)\n\tbuff.set_level(new_level)\n"
  },
  {
    "path": "src/towers/tower_behaviors/warrior_of_light.gd",
    "content": "extends TowerBehavior\n\n\nvar shockwave_st: SpellType\nvar aura_bt: BuffType\n\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {shockwave_chance = 0.20, shockwave_chance_add = 0.005, shockwave_damage = 1000, shockwave_damage_add = 50, mod_dmg_to_undead = 0.15, mod_dmg_to_undead_add = 0.006},\n\t\t2: {shockwave_chance = 0.23, shockwave_chance_add = 0.007, shockwave_damage = 2000, shockwave_damage_add = 100, mod_dmg_to_undead = 0.20, mod_dmg_to_undead_add = 0.008},\n\t\t3: {shockwave_chance = 0.25, shockwave_chance_add = 0.010, shockwave_damage = 3000, shockwave_damage_add = 150, mod_dmg_to_undead = 0.25, mod_dmg_to_undead_add = 0.010},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_DMG_TO_UNDEAD, _stats.mod_dmg_to_undead, _stats.mod_dmg_to_undead_add)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/shiny_omega.tres\")\n\taura_bt.set_buff_tooltip(tr(\"HZID\"))\n\n#\tNOTE: original script and tooltip don't mention the\n#\tradius of swarm so made it the same as for \"Hell Bat\"\n#\ttower\n\tshockwave_st = SpellType.new(SpellType.Name.CARRION_SWARM, 1, self)\n\tshockwave_st.data.swarm.damage = 1.0\n\tshockwave_st.data.swarm.start_radius = 30\n\tshockwave_st.data.swarm.end_radius = 50\n\tshockwave_st.data.swarm.travel_distance = 500\n\tshockwave_st.data.swarm.effect_path = \"res://src/effects/shockwave_missile.tscn\"\n\n\nfunc on_attack(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar shockwave_chance: float = _stats.shockwave_chance + _stats.shockwave_chance_add * level\n\tvar shockwave_damage: float = _stats.shockwave_damage + _stats.shockwave_damage_add * level\n\tvar facing_deg: float = creep.get_unit_facing() - 180\n\tvar facing_rad: float = deg_to_rad(facing_deg)\n\tvar x: float = creep.get_x() + 50 * cos(facing_rad)\n\tvar y: float = creep.get_y() + 50 * sin(facing_rad)\n\n\tif !tower.calc_chance(shockwave_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Ain Soph Aur\")\n\n\tvar effect: int = Effect.create_simple_at_unit_attached(\"res://src/effects/holy_bolt.tscn\", creep, Unit.BodyPart.CHEST)\n\tEffect.set_color(effect, Color.GOLD)\n\tshockwave_st.point_cast_from_unit_on_point(tower, event.get_target(), Vector2(x, y), shockwave_damage, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/wild_warbeast.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Wild Kodo Beast\"=>\"Wild Warbeast\"\n\n\nvar aura_bt: BuffType\nvar devour_count: int = 1\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\n\nfunc tower_init():\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_CHANCE, 0.0, 0.0003)\n\tmod.add_modification(ModificationType.enm.MOD_ATK_CRIT_DAMAGE, 0.0, 0.0015)\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.0010)\n\tmod.add_modification(ModificationType.enm.MOD_DAMAGE_ADD_PERC, 0.0, 0.0010)\n\taura_bt.set_buff_modifier(mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/poison_gas.tres\")\n\taura_bt.add_event_on_refresh(aura_bt_on_refresh)\n\taura_bt.set_buff_tooltip(tr(\"V23V\"))\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar chance: float = 0.06 + 0.001 * level\n\tvar devour_damage: float = 5000 + 400 * level\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Devour\")\n\n\ttower.do_spell_damage(target, devour_damage, tower.calc_spell_crit_no_bonus())\n\tEffect.create_simple_at_unit(\"res://src/effects/devour.tscn\", target)\n\tdevour_count += 1\n\ttower.refresh_auras()\n\n\tvar devour_stack_duration: float = 6.0 * tower.get_prop_buff_duration()\n\n\tawait Utils.create_manual_timer(devour_stack_duration, self).timeout\n\n\tif !Utils.unit_is_valid(tower):\n\t\treturn\n\n\tdevour_count -= 1\n\ttower.refresh_auras()\n\n\nfunc aura_bt_on_refresh(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar new_level: int = (100 + 2 * tower.get_level()) * devour_count\n\tbuff.set_level(new_level)\n\tbuff.set_displayed_stacks(devour_count)\n"
  },
  {
    "path": "src/towers/tower_behaviors/witch_doctor.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] Renamed\n# \"Vol'jin the Witch Doctor\"=>\"Witch Doctor\"\n\n# NOTE: time constants in original script were divided by 25\n# to account for original Game.getGameTime() returning\n# seconds multiplied by 25. Don't need to divide by 25 in\n# youtd2.\n\n# NOTE: changed how wards are stored\n# Original script: hashtable with ints and reals\n# New script: list of wards\n\n\nclass Ward:\n\tvar position: Vector2 = Vector2.ZERO\n\tvar effect: int = 0\n\tvar duration: float = 0.0\n\tvar is_active: bool = false\n\n\nvar maledict_bt: BuffType\nvar voljin_pt: ProjectileType\nvar ward_list: Array[Ward]\nvar active_ward_count: int = 0\nvar tick_for_next_purify: int\nvar periodic_is_enabled: bool = true\nvar first_periodic_event: bool = false\nvar periodic_interval: float\n\nconst STACK_MALEDICT_FROM_WARD_CHANCE: float = 0.35\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 0.1)\n\n\nfunc tower_init():\n\tmaledict_bt = BuffType.new(\"maledict_bt\", 0, 0, false, self)\n\tmaledict_bt.set_buff_icon(\"res://resources/icons/generic_icons/omega.tres\")\n\tmaledict_bt.add_event_on_damaged(maledict_bt_on_damaged)\n\tmaledict_bt.add_event_on_expire(maledict_bt_on_expire)\n\tmaledict_bt.add_event_on_purge(maledict_bt_on_purge)\n\tmaledict_bt.set_buff_tooltip(tr(\"F1C0\"))\n\n\tvoljin_pt = ProjectileType.create(\"path_to_projectile_sprite\", 10, 1200, self)\n\tvoljin_pt.enable_homing(voljin_pt_on_hit, 0)\n\n\nfunc on_attack(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar ward_chance: float = 0.18 + 0.0028 * level\n\n\tif !tower.calc_chance(ward_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Serpent Ward\")\n\n\tvar max_wards: int\n\tif level == 25:\n\t\tmax_wards = 4\n\telif level >= 15:\n\t\tmax_wards = 3\n\telse:\n\t\tmax_wards = 2\n\n\tvar counter: int = 0\n\n\twhile true:\n#\t\tCheck whether all wards already exist, if not create one\n\t\tvar ward: Ward = ward_list[counter]\n\n\t\tif !ward.is_active:\n\t\t\tvar x: float = ward.position.x\n\t\t\tvar y: float = ward.position.y\n\t\t\tward.effect = Effect.create_animated(\"res://src/effects/witch_doctor_ward.tscn\", Vector3(x, y, tower.get_z() - 70), -(45.0 + 90.0 * counter / 4))\n\t\t\tEffect.set_auto_destroy_enabled(ward.effect, false)\n\t\t\tEffect.set_scale(ward.effect, 0.3)\n\t\t\tEffect.set_color(ward.effect, Color8(255, 255, 255, 200))\n\n\t\t\tward.is_active = true\n\t\t\tward.duration = (6.0 + 0.1 * tower.get_level()) * tower.get_prop_buff_duration()\n\n\t\t\tactive_ward_count += 1 # Save the amount of wards\n#\t\t\tThe first ward has been created => Start the Periodic Event\n\t\t\tif active_ward_count == 1:\n\t\t\t\tperiodic_is_enabled = true\n\t\t\t\tperiodic_interval = tower.get_current_attack_speed()\n\n#\t\t\tNOTE: break after successfully creating one wand\n#\t\t\tso that only one wand is created at a time\n\t\t\tbreak\n\n\t\tcounter += 1\n\t\tif counter > (max_wards - 1):\n\t\t\tbreak\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar purged_count: int = 0\n\tvar current_tick: int = Utils.get_current_tick()\n\tvar purify_is_on_cd: bool = tick_for_next_purify > current_tick\n\n\tif purify_is_on_cd:\n\t\treturn\n\n\tvar purify_cd: float = 4.0 - 0.04 * tower.get_level()\n\tvar purify_cd_ticks: int = Utils.time_to_ticks(purify_cd)\n\ttick_for_next_purify = current_tick + purify_cd_ticks\n\n#\tRemove buffs (positive and negative buffs) and count them\n\twhile true:\n\t\tvar purge_friendly: bool = target.purge_buff(true)\n\t\tif purge_friendly:\n\t\t\tpurged_count += 1\n\n\t\tvar purge_unfriendly: bool = target.purge_buff(false)\n\t\tif purge_unfriendly:\n\t\t\tpurged_count += 1\n\n\t\tvar purge_success: bool = purge_friendly || purge_unfriendly\n\n\t\tif !purge_success:\n\t\t\tbreak\n\n\tvar damage_multiplier: float = 1.0 + purged_count * (0.12 + 0.0016 * tower.get_level())\n\tevent.damage *= damage_multiplier\n\n\tif purged_count != 0:\n\t\tvar floating_text: String = Utils.format_float(event.damage, 0)\n\t\ttower.get_player().display_small_floating_text(floating_text, tower, Color8(255, 150, 255), 0)\n\n\nfunc on_create(_preceding: Tower):\n\tvar ward_offsets: Array = [\n\t\tVector2(38, -53),\n\t\tVector2(-43, -45),\n\t\tVector2(-33, 38),\n\t\tVector2(35, 38),\n\t]\n\n\tfor offset in ward_offsets:\n\t\tvar ward_pos: Vector2 = tower.get_position_wc3_2d() + offset\n\t\tvar ward: Ward = Ward.new()\n\t\tward.position = ward_pos\n\n\t\tward_list.append(ward)\n\n\tactive_ward_count = 0\n\ttick_for_next_purify = Utils.get_current_tick() - Utils.time_to_ticks(4)\n\tperiodic_interval = 0.0\n\n\nfunc on_destruct():\n\tfor ward in ward_list:\n\t\tvar effect: int = ward.effect\n\n\t\tif effect != 0:\n\t\t\tEffect.destroy_effect(effect)\n\n\n# NOTE: original script saves targets in a list. This is\n# unsafe. Used Iterate directly instead.\nfunc periodic(event: Event):\n\tif first_periodic_event:\n\t\tperiodic_is_enabled = false\n\n\t\treturn\n\n\tif !periodic_is_enabled:\n\t\treturn\n\n#\tNOTE: original script calls enable_advanced()\n#\tselectively in some spots. Call it always here to ensure\n#\tthat periodic interval always equals to attack speed.\n\tevent.enable_advanced(tower.get_current_attack_speed(), false)\n\t\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 800)\n\n\tvar counter: int = 0\n\n\twhile true:\n\t\tvar ward: Ward = ward_list[counter]\n\n\t\tif ward.is_active:\n\t\t\tvar random_target: Unit = it.next_random()\n\n\t\t\tvar duration: float = ward.duration - periodic_interval # Set duration to duration - periodic interval\n\n\t\t\tif duration > 0: # Is there duration remaining?\n\t\t\t\tif random_target != null: # Is there are unit which can be attacked ?\n\t\t\t\t\t# NOTE: here, original script makes the ward\n\t\t\t\t\t# model face the creep. This can be skipped\n\t\t\t\t\t# because youtd2 no ward model which can\n\t\t\t\t\t# rotate.\n\n\t\t\t\t\t# Shoot prohectile\n\t\t\t\t\tvar x: float = ward.position.x\n\t\t\t\t\tvar y: float = ward.position.y\n\t\t\t\t\tvar p: Projectile = Projectile.create_from_point_to_unit(voljin_pt, tower, 1.0, 1.0, Vector3(x, y, 147), random_target, true, false, false)\n\t\t\t\t\tp.set_projectile_scale(0.4)\n\n\t\t\t\t# Save the remaining duration\n\t\t\t\tward.duration = duration\n\t\t\telse: # No more duration\n\t\t\t\tCombatLog.log_ability(tower, null, \"Destroy Serpent Ward\")\n\t\t\t\tward.is_active = false\n\t\t\t\tEffect.destroy_effect(ward.effect)\n\t\t\t\tactive_ward_count -= 1\n\n\t\tcounter += 1\n#\t\tUp to 4 wards with each taking 1 index in the list starting at 0\n#\t\t=> 4 wards - 1\n\t\tif counter > ward_list.size() - 1:\n\t\t\tbreak\n\n#\tDisable the event\n\tperiodic_is_enabled = false\n\n#\tAre there any wards?\n\tif active_ward_count > 0:\n# \t\tActivate the event\n\t\tperiodic_is_enabled = true\n\t\tperiodic_interval = tower.get_current_attack_speed()\n\n\nfunc on_autocast(_event: Event):\n\tvar it: Iterate = Iterate.over_units_in_range_of_unit(tower, TargetType.new(TargetType.CREEPS), tower, 800)\n\n\twhile true:\n\t\tvar next: Unit = it.next()\n\n\t\tif next == null:\n\t\t\tbreak\n\n\t\tvar maledict_comes_from_ward: bool = false\n\t\tapply_maledict(tower, next, maledict_comes_from_ward)\n\n\n# NOTE: \"voljin_hit()\" in original script\nfunc voljin_pt_on_hit(_p: Projectile, target: Unit):\n\tif target == null:\n\t\treturn\n\n\tvar damage: float = tower.get_current_attack_damage_with_bonus() * (0.2 + 0.002 * tower.get_level())\n\n\ttower.do_attack_damage(target, damage, tower.calc_attack_multicrit_no_bonus())\n\t\n\tif tower.calc_chance(STACK_MALEDICT_FROM_WARD_CHANCE):\n\t\tvar maledict_comes_from_ward: bool = true\n\t\tapply_maledict(tower, target, maledict_comes_from_ward)\n\n\n# NOTE: tower can apply fresh Maledict and increase stacks.\n# Wards cannot apply fresh Maledict, they can only increase\n# stacks of existing Maledict and they also do it only 35%\n# of the time.\n# NOTE: \"ApplyMaledict()\" in original script\nfunc apply_maledict(caster: Tower, target: Unit, maledict_comes_from_ward: bool):\n\tvar buff: Buff = target.get_buff_of_type(maledict_bt)\n\tvar duration: float = 8.0 / caster.get_prop_buff_duration()\n\n\tvar active_stacks: int\n\tif buff != null:\n\t\tactive_stacks = buff.user_int\n\telse:\n\t\tactive_stacks = 0\n\n#\tNOTE: wards can only increase Maledict stacks, they\n#\tcannot apply fresh Maledict. Tower does that.\n\tif maledict_comes_from_ward && active_stacks == 0:\n\t\treturn\n\n\tvar new_stacks: int = active_stacks + 1\n\n\tbuff = maledict_bt.apply_custom_timed(caster, target, 1, duration)\n\tbuff.user_int = new_stacks\n\tbuff.set_displayed_stacks(new_stacks)\n\n\n# NOTE: \"damageEvent()\" in original script\nfunc maledict_bt_on_damaged(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tbuff.user_real += event.damage\n\n\n# NOTE: \"expireEvent()\" in original script\nfunc maledict_bt_on_expire(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar collected_damage: float = buff.user_real\n\tvar stack_count: float = buff.user_int\n\tvar multiplier_per_stack: float = 0.035 + 0.0014 * tower.get_level()\n\tvar damage_multiplier: float = 0.15 + multiplier_per_stack * stack_count\n\tvar damage: float = collected_damage * damage_multiplier\n\n\ttower.do_spell_damage(buffed_unit, damage, tower.calc_spell_crit_no_bonus())\n\n\n# NOTE: \"purgeEvent()\" in original script\nfunc maledict_bt_on_purge(event: Event):\n\tvar buff: Buff = event.get_buff()\n\tvar buffed_unit: Unit = buff.get_buffed_unit()\n\tvar collected_damage: float = buff.user_real\n\tvar stack_count: float = buff.user_int\n\tvar multiplier_per_stack: float = 0.07 + 0.0028 * tower.get_level()\n\tvar damage_multiplier: float = 0.3 + multiplier_per_stack * stack_count\n\tvar damage: float = collected_damage * damage_multiplier\n\n\ttower.do_spell_damage(buffed_unit, damage, tower.calc_spell_crit_no_bonus())\n"
  },
  {
    "path": "src/towers/tower_behaviors/wooden_trap.gd",
    "content": "extends TowerBehavior\n\n\nvar stun_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {cooldown = 15, base_damage = 70, damage_add = 3, stun_duration = 0.50, max_targets = 3},\n\t\t2: {cooldown = 14, base_damage = 270, damage_add = 15, stun_duration = 0.75, max_targets = 3},\n\t\t3: {cooldown = 13, base_damage = 650, damage_add = 33, stun_duration = 1.00, max_targets = 4},\n\t\t4: {cooldown = 12, base_damage = 1500, damage_add = 75, stun_duration = 1.25, max_targets = 4},\n\t\t5: {cooldown = 11, base_damage = 2000, damage_add = 100, stun_duration = 1.50, max_targets = 5},\n\t}\n\n\nfunc load_triggers(triggers_buff_type: BuffType):\n\ttriggers_buff_type.add_periodic_event(on_periodic, 2)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_periodic(event: Event):\n\tCombatLog.log_ability(tower, null, \"Activate Trap\")\n\n\ttrap(event, _stats.cooldown, _stats.base_damage, _stats.damage_add, _stats.stun_duration, _stats.max_targets)\n\n\nfunc trap(event: Event, cooldown: float, base_damage: float, damage_add: float, stun_duration: float, max_targets: int):\n\tvar lvl: int = tower.get_level()\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 950)\n\tvar next: Unit = it.next_random()\n\tvar num_targets: int = 0\n\n\twhile true:\n\t\tif next == null:\n\t\t\tbreak\n\t\tnum_targets = num_targets + 1\n\t\tstun_bt.apply_only_timed(tower, next, stun_duration)\n\t\ttower.do_spell_damage(next, base_damage + lvl * damage_add, tower.calc_spell_crit_no_bonus())\n\t\tEffect.create_simple_at_unit_attached(\"res://src/effects/shackle.tscn\", next, Unit.BodyPart.CHEST)\n\n\t\tif num_targets >= max_targets:\n\t\t\tbreak\n\n\t\tnext = it.next_random()\n\n\tif num_targets > 0:\n#\t\tTrapping successful; go into cooldown.\n\t\tevent.enable_advanced(cooldown - lvl * 0.2, false)\n\telse:\n#\t\tNothing trapped; go into a shorter cooldown.\n\t\tevent.enable_advanced(2, false)\n"
  },
  {
    "path": "src/towers/tower_behaviors/xeno_research_facility.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: made changes to original script but overall\n# it's the same logic.\n\n\n# NOTE: tower increases dmg against only one category at a\n# time (for other towers). This is intentional and works\n# like this in original game.\n\n\nvar aura_bt: BuffType\nvar undead_bt: BuffType\nvar magic_bt: BuffType\nvar nature_bt: BuffType\nvar orc_bt: BuffType\nvar humanoid_bt: BuffType\n\n\nvar bonus_levels_in_progress: bool = false\nvar force_show_research_message: bool = false\n# which creep type i attacked - that's the type i'll buff next\nvar current_creep_category: CreepCategory.enm = CreepCategory.enm.UNDEAD\n# memory of prev. attacked creep type\nvar prev_creep_category: CreepCategory.enm = CreepCategory.enm.UNDEAD\nvar bonus_map: Dictionary = {\n\tCreepCategory.enm.UNDEAD: 0,\n\tCreepCategory.enm.MAGIC: 0,\n\tCreepCategory.enm.NATURE: 0,\n\tCreepCategory.enm.ORC: 0,\n\tCreepCategory.enm.HUMANOID: 0,\n\tCreepCategory.enm.CHALLENGE: 0,\n}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_periodic_event(periodic, 6.0)\n\n\nfunc tower_init():\n\tundead_bt = BuffType.new(\"undead_bt\", 1, 0, true, self)\n\tvar palandu_xeno_undead_mod: Modifier = Modifier.new()\n\tpalandu_xeno_undead_mod.add_modification(ModificationType.enm.MOD_DMG_TO_UNDEAD, 0.0, 0.001)\n\tundead_bt.set_buff_modifier(palandu_xeno_undead_mod)\n\tundead_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\tundead_bt.set_buff_tooltip(tr(\"JRUK\"))\n\n\tmagic_bt = BuffType.new(\"magic_bt\", 1, 0, true, self)\n\tvar palandu_xeno_magic_mod: Modifier = Modifier.new()\n\tpalandu_xeno_magic_mod.add_modification(ModificationType.enm.MOD_DMG_TO_MAGIC, 0.0, 0.001)\n\tmagic_bt.set_buff_modifier(palandu_xeno_magic_mod)\n\tmagic_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\tmagic_bt.set_buff_tooltip(tr(\"O429\"))\n\n\tnature_bt = BuffType.new(\"nature_bt\", 1, 0, true, self)\n\tvar palandu_xeno_nature_mod: Modifier = Modifier.new()\n\tpalandu_xeno_nature_mod.add_modification(ModificationType.enm.MOD_DMG_TO_NATURE, 0.0, 0.001)\n\tnature_bt.set_buff_modifier(palandu_xeno_nature_mod)\n\tnature_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\tnature_bt.set_buff_tooltip(tr(\"V3LT\"))\n\n\torc_bt = BuffType.new(\"orc_bt\", 1, 0, true, self)\n\tvar palandu_xeno_orc_mod: Modifier = Modifier.new()\n\tpalandu_xeno_orc_mod.add_modification(ModificationType.enm.MOD_DMG_TO_ORC, 0.0, 0.001)\n\torc_bt.set_buff_modifier(palandu_xeno_orc_mod)\n\torc_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\torc_bt.set_buff_tooltip(tr(\"BZQR\"))\n\n\thumanoid_bt = BuffType.new(\"humanoid_bt\", 1, 0, true, self)\n\tvar palandu_xeno_humanoid_mod: Modifier = Modifier.new()\n\tpalandu_xeno_humanoid_mod.add_modification(ModificationType.enm.MOD_DMG_TO_HUMANOID, 0.0, 0.001)\n\thumanoid_bt.set_buff_modifier(palandu_xeno_humanoid_mod)\n\thumanoid_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\thumanoid_bt.set_buff_tooltip(tr(\"UELS\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/spell_book.tres\")\n\taura_bt.set_buff_tooltip(tr(\"QS5Q\"))\n\n\nfunc on_attack(event: Event):\n\tif bonus_levels_in_progress:\n\t\treturn\n\n\tvar creep: Creep = event.get_target()\n\tvar creep_category: CreepCategory.enm = creep.get_category()\n\n\tif creep.get_spawn_level() > Utils.get_max_level():\n\t\tbonus_levels_in_progress = true\n\n\tcurrent_creep_category = creep_category\n\n\tvar is_type_change: bool = current_creep_category != prev_creep_category\n\tif is_type_change:\n\t\txeno_buff_towers(true)\n\n\nfunc on_damage(event: Event):\n\tif bonus_levels_in_progress:\n\t\treturn\n\t\n\tvar creep: Creep = event.get_target()\n\tvar creep_category: CreepCategory.enm = creep.get_category()\n\tvar chance: float = 0.25 + 0.01 * tower.get_level()\n\n\tif !tower.calc_chance(chance):\n\t\treturn\n\n# \tNOTE: ignore challenge creeps\n\tif creep_category == CreepCategory.enm.CHALLENGE:\n\t\treturn\n\n\tvar bonus_max: int = 250 + 10 * tower.get_level()\n\tvar current_bonus: int = bonus_map[creep_category]\n\n\tif current_bonus >= bonus_max:\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Sample Collection\")\n\n\tvar sample_collected_text: String = tr(\"Q346\")\n\ttower.get_player().display_small_floating_text(sample_collected_text, creep, Color8(200, 200, 200), 40.0)\n\tvar new_bonus: int = min(current_bonus + 50, bonus_max)\n\tbonus_map[creep_category] = new_bonus\n\tforce_show_research_message = true\n\n\nfunc periodic(_event: Event):\n\tif !bonus_levels_in_progress:\n\t\txeno_buff_towers(current_creep_category != prev_creep_category)\n\n\nfunc xeno_manage_bonuses(is_type_change: bool, current_bonus: int):\n# \tNOTE: ignore challenge creeps\n\tif current_creep_category == CreepCategory.enm.CHALLENGE:\n\t\treturn\n\n\tif is_type_change:\n#\t\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\t\tvar sorted_category_keys: Array = bonus_map.keys()\n\t\tsorted_category_keys.sort()\n\t\tfor category in sorted_category_keys:\n\t\t\tbonus_map[category] = bonus_map[category] / 2\n#\t\tnow restore the correct one :P\n\t\tbonus_map[current_creep_category] = current_bonus\n\n#\tnow set the correct race bonuses for this tower\n#\tNOTE: sort keys to ensure deterministic iteration order for multiplayer sync\n\tvar sorted_bonus_keys: Array = bonus_map.keys()\n\tsorted_bonus_keys.sort()\n\tfor category in sorted_bonus_keys:\n\t\tvar ideal_bonus: float = 1.0 + bonus_map[category] / 1000.0\n\t\tvar current_race_bonus: float = tower.get_damage_to_category(category)\n\t\tvar mod_type: ModificationType.enm = CreepCategory.convert_to_mod_dmg_type(category)\n\n\t\tif ideal_bonus != current_race_bonus:\n\t\t\tvar delta: float = ideal_bonus - current_race_bonus\n\t\t\ttower.modify_property(mod_type, delta)\n\n\nfunc xeno_buff_towers(is_type_change: bool):\n# \tNOTE: ignore challenge creeps\n\tif current_creep_category == CreepCategory.enm.CHALLENGE:\n\t\treturn\n\n\tvar buff_level: int = bonus_map[current_creep_category]\n\tprev_creep_category = current_creep_category\n\n\tvar category_string = CreepCategory.get_display_string(current_creep_category)\n\tvar category_color: Color = CreepCategory.get_color(current_creep_category)\n\tvar research_published_text: String = tr(\"E2IZ\").format({CREEP_RACE = category_string})\n\n\tif (is_type_change && buff_level > 0) || force_show_research_message:\n\t\ttower.get_player().display_floating_text(research_published_text, tower, category_color)\n\t\tforce_show_research_message = false\n\n\tvar category_to_bt: Dictionary = {\n\t\tCreepCategory.enm.UNDEAD: undead_bt,\n\t\tCreepCategory.enm.MAGIC: magic_bt,\n\t\tCreepCategory.enm.NATURE: nature_bt,\n\t\tCreepCategory.enm.ORC: orc_bt,\n\t\tCreepCategory.enm.HUMANOID: humanoid_bt,\n\t\tCreepCategory.enm.CHALLENGE: humanoid_bt,\n\t}\n\tvar selected_buff: BuffType = category_to_bt[current_creep_category]\n\n\txeno_manage_bonuses(is_type_change, buff_level)\n\n\tif buff_level <= 0:\n\t\treturn\n\n#\tlarger AoE needed as aura centre seems to be diff + collision problems\n\tvar towers_in_aura: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 315)\n\n\twhile true:\n\t\tvar next_tower: Tower = towers_in_aura.next()\n\n\t\tif next_tower == null:\n\t\t\tbreak\n\n\t\tvar tower_is_self: bool = next_tower == tower\n\t\tif tower_is_self:\n\t\t\tcontinue\n\n\t\tvar tower_is_in_aura: bool = next_tower.get_buff_of_type(aura_bt) != null\n\n\t\tif tower_is_in_aura:\n#\t\t\tNOTE: divide by tower buff duration to force\n#\t\t\tduration to always be 6.5 seconds. (duration is\n#\t\t\tmultiplied by tower buff duration during\n#\t\t\tapply()).\n\t\t\tvar buff_duration: float = 6.5 / tower.get_prop_buff_duration()\n\t\t\tselected_buff.apply_custom_timed(tower, next_tower, buff_level, buff_duration)\n"
  },
  {
    "path": "src/towers/tower_behaviors/ymir.gd",
    "content": "extends TowerBehavior\n\n\nvar multiboard: MultiboardValues\nvar blood_bt: BuffType\nvar aura_bt: BuffType\nvar wrath_bt: BuffType\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_unit_comes_in_range(on_unit_in_range, 900, TargetType.new(TargetType.CREEPS))\n\n\nfunc tower_init():\n\tblood_bt = BuffType.new(\"blood_bt\", 6.0, 0.08, false, self)\n\tvar iaman_ymir_blood_mod: Modifier = Modifier.new()\n\tiaman_ymir_blood_mod.add_modification(ModificationType.enm.MOD_DMG_FROM_ICE, 0.25, 0.004)\n\tblood_bt.set_buff_modifier(iaman_ymir_blood_mod)\n\tblood_bt.set_buff_icon(\"res://resources/icons/generic_icons/round_potion.tres\")\n\tblood_bt.set_buff_tooltip(tr(\"MR2Y\"))\n\n\taura_bt = BuffType.create_aura_effect_type(\"aura_bt\", true, self)\n\tvar iaman_ymir_flesh_mod: Modifier = Modifier.new()\n\tiaman_ymir_flesh_mod.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, -0.25, -0.006)\n\taura_bt.set_buff_modifier(iaman_ymir_flesh_mod)\n\taura_bt.set_buff_icon(\"res://resources/icons/generic_icons/meat.tres\")\n\taura_bt.set_buff_tooltip(tr(\"LJ28\"))\n\n\twrath_bt = BuffType.new(\"wrath_bt\", 0, 0, false, self)\n\tvar iaman_ymir_wrath_mod: Modifier = Modifier.new()\n\tiaman_ymir_wrath_mod.add_modification(ModificationType.enm.MOD_MOVESPEED, -1.0, 0.001)\n\twrath_bt.set_buff_modifier(iaman_ymir_wrath_mod)\n\twrath_bt.set_buff_icon(\"res://resources/icons/generic_icons/foot_trip.tres\")\n\twrath_bt.set_buff_tooltip(tr(\"SCJ8\"))\n\n\tmultiboard = MultiboardValues.new(1)\n\tvar wrath_damage_label: String = tr(\"OEII\")\n\tmultiboard.set_key(0, wrath_damage_label)\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar wrath_chance: float = 0.20 + 0.004 * tower.get_level()\n\n\tif !tower.calc_chance(wrath_chance):\n\t\treturn\n\n\tCombatLog.log_ability(tower, target, \"Wrath of Ymir\")\n\n#\tslow becomes less powerful with every cast\n\tvar slow_power: int = 1000 - int(target.get_health_ratio() * 1000)\n\tvar wrath_damage: float = get_wrath_damage()\n\n\ttower.do_spell_damage(target, wrath_damage, tower.calc_spell_crit_no_bonus())\n\twrath_bt.apply_custom_timed(tower, target, slow_power, 2.0)\n\tEffect.create_simple_at_unit(\"res://src/effects/ziggurat_frost_missile.tscn\", target)\n\n\nfunc on_tower_details() -> MultiboardValues:\n\tvar wrath_damage: float = get_wrath_damage()\n\tvar wrath_damage_string: String = Utils.format_float(wrath_damage, 0)\n\tmultiboard.set_value(0, wrath_damage_string)\n\n\treturn multiboard\n\n\nfunc on_unit_in_range(event: Event):\n\tvar target: Unit = event.get_target()\n\tblood_bt.apply(tower, target, tower.get_level())\n\n\nfunc get_wrath_damage() -> float:\n\tvar wrath_damage: float = tower.get_current_attack_damage_with_bonus() * (0.10 + 0.006 * tower.get_level())\n\n\treturn wrath_damage\n"
  },
  {
    "path": "src/towers/tower_behaviors/young_northern_troll.gd",
    "content": "extends TowerBehavior\n\nvar stun_bt: BuffType\nvar fatigue_bt: BuffType\nvar axe_pt: ProjectileType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {smashing_axe_dmg = 0.20, smashing_axe_dmg_add = 0.004, coated_axes_dmg = 0.0060, coated_axes_dmg_add = 0.00020},\n\t\t2: {smashing_axe_dmg = 0.25, smashing_axe_dmg_add = 0.005, coated_axes_dmg = 0.0065, coated_axes_dmg_add = 0.00025},\n\t\t3: {smashing_axe_dmg = 0.30, smashing_axe_dmg_add = 0.006, coated_axes_dmg = 0.0070, coated_axes_dmg_add = 0.00030},\n\t}\n\nconst ON_ATTACK_CHANCE: float = 0.15\nconst STUN_DURATION: float = 1.5\nconst STUN_DURATION_FOR_BOSSES: float = 0.75\nconst MOD_ATTACKSPEED: float = 0.30\nconst MOD_ATTACKSPEED_ADD: float = 0.004\nconst FATIGUE_DURATION: float = 3\nconst PURGE_COUNT_FOR_STUN: float = 5\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_attack(on_attack)\n\ttriggers.add_event_on_damage(on_damage)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\t\n\tfatigue_bt = BuffType.new(\"fatigue_bt\", FATIGUE_DURATION, 0, false, self)\n\tvar mod: Modifier = Modifier.new()\n\tmod.add_modification(ModificationType.enm.MOD_ATTACKSPEED, -MOD_ATTACKSPEED, MOD_ATTACKSPEED_ADD)\n\tfatigue_bt.set_buff_modifier(mod)\n\tfatigue_bt.set_buff_icon(\"res://resources/icons/generic_icons/animal_skull.tres\")\n\tfatigue_bt.set_buff_tooltip(tr(\"NU0J\"))\n\n\taxe_pt = ProjectileType.create_interpolate(\"path_to_projectile_sprite\", 900, self)\n\taxe_pt.set_event_on_interpolation_finished(on_projectile_hit)\n\n\nfunc on_attack(event: Event):\n\tvar creep: Unit = event.get_target()\n\tvar level: int = tower.get_level()\n\n\tif !tower.calc_chance(ON_ATTACK_CHANCE):\n\t\treturn\n\n\tCombatLog.log_ability(tower, creep, \"Ice Smashing Axe\")\n\n\tvar projectile: Projectile = Projectile.create_linear_interpolation_from_unit_to_unit(axe_pt, tower, 1, 1, tower, creep, 0.2, true)\n\tvar dmg_per_purge: float = _stats.smashing_axe_dmg + _stats.smashing_axe_dmg_add * level\n\tprojectile.user_real = dmg_per_purge\n\tprojectile.set_projectile_scale(1.5)\n\tfatigue_bt.apply(tower, tower, tower.get_level())\n\n\nfunc on_damage(event: Event):\n\tvar creep: Creep = event.get_target()\n\tvar level: int = tower.get_level()\n\tvar base_speed: float = creep.get_base_movespeed()\n\tvar current_speed: float = creep.get_current_movespeed()\n\n\tif current_speed < base_speed:\n\t\tvar slow_percent: float = (base_speed - current_speed) / base_speed * 100\n\t\tvar dmg_ratio: float = max(0.0, slow_percent * (_stats.coated_axes_dmg + _stats.coated_axes_dmg_add * level))\n\t\tvar bonus_damage: float = event.damage * dmg_ratio\n\t\tevent.damage += bonus_damage\n\t\ttower.get_player().display_small_floating_text(\"+\" + str(int(bonus_damage)), creep, Color8(100, 100, 255), 0)\n\n\nfunc on_projectile_hit(projectile: Projectile, creep: Unit):\n\tif creep == null:\n\t\treturn\n\n\tvar purged_count: int = 0\n\tvar damage: float = tower.get_current_attack_damage_with_bonus()\n\n\tvar stun_duration: float\n\tif creep.get_size() < CreepSize.enm.BOSS:\n\t\tstun_duration = STUN_DURATION\n\telse:\n\t\tstun_duration = STUN_DURATION_FOR_BOSSES\n\n\twhile true:\n\t\tvar purge_friendly_success: bool = creep.purge_buff(true)\n\t\tvar purge_unfriendly_success: bool = creep.purge_buff(false)\n\n\t\tif !purge_friendly_success && !purge_unfriendly_success:\n\t\t\tbreak\n\n\t\tpurged_count += 1 \n\n\tif purged_count != 0:\n\t\tvar dmg_per_purge: float = projectile.user_real\n\t\tvar damage_from_purges: float = damage * (dmg_per_purge * purged_count)\n\t\ttower.do_attack_damage(creep, damage_from_purges, tower.calc_attack_multicrit_no_bonus())\n\n\t\tif purged_count > PURGE_COUNT_FOR_STUN:\n\t\t\tstun_bt.apply_only_timed(tower, creep, stun_duration)\n\n\tEffect.create_simple_at_unit_attached(\"res://src/effects/frost_armor_damage.tscn\", creep)\n"
  },
  {
    "path": "src/towers/tower_behaviors/zealot.gd",
    "content": "extends TowerBehavior\n\n\nvar zeal_bt: BuffType\nvar wound_bt: BuffType\nvar drain_bt: BuffType\nvar shield_bt: BuffType\n\n\nfunc get_tier_stats() -> Dictionary:\n\treturn {\n\t\t1: {affected_gold_cost = 200, shield_power = 400, wound_power = 0.02, wound_power_add = 0.0008, leech_power_base = 105, leech_power_add = 5},\n\t\t2: {affected_gold_cost = 460, shield_power = 650, wound_power = 0.04, wound_power_add = 0.0016, leech_power_base = 210, leech_power_add = 10},\n\t\t3: {affected_gold_cost = 750, shield_power = 800, wound_power = 0.06, wound_power_add = 0.0024, leech_power_base = 315, leech_power_add = 15},\n\t\t4: {affected_gold_cost = 1200, shield_power = 1000, wound_power = 0.08, wound_power_add = 0.0032, leech_power_base = 420, leech_power_add = 20},\n\t}\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_attack(on_attack)\n\n\n\nfunc shield_bt_cleanup(event: Event):\n\tvar b: Buff = event.get_buff()\n\n\tif b.user_int2 != 0:\n\t\tEffect.destroy_effect(b.user_int2)\n\n\nfunc tower_init():\n\tvar m: Modifier = Modifier.new()\n\tvar n: Modifier = Modifier.new()\n\tvar o: Modifier = Modifier.new()\n\n\tm.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, 0.0001)\n\tn.add_modification(ModificationType.enm.MOD_ATTACKSPEED, 0.0, -0.0001)\n\to.add_modification(ModificationType.enm.MOD_DEBUFF_DURATION, 0.0, -0.0001)\n\n\tzeal_bt = BuffType.new(\"zeal_bt\", 2.5, 0, true, self)\n\twound_bt = BuffType.new(\"wound_bt\", 200, 0, false, self)\n\tdrain_bt = BuffType.new(\"drain_bt\", 2.5, 0, true, self)\n\tshield_bt = BuffType.new(\"shield_bt\", 2.5, 0, true, self)\n\n\tzeal_bt.set_buff_modifier(m)\n\tdrain_bt.set_buff_modifier(n)\n\tshield_bt.set_buff_modifier(o)\n\n\tzeal_bt.set_buff_icon(\"res://resources/icons/generic_icons/mighty_force.tres\")\n\twound_bt.set_buff_icon(\"res://resources/icons/generic_icons/open_wound.tres\")\n\tdrain_bt.set_buff_icon(\"res://resources/icons/generic_icons/energy_breath.tres\")\n\tshield_bt.set_buff_icon(\"res://resources/icons/generic_icons/turtle_shell.tres\")\n\n\tzeal_bt.set_buff_tooltip(tr(\"Q8Y1\"))\n\twound_bt.set_buff_tooltip(tr(\"G2AM\"))\n\tdrain_bt.set_buff_tooltip(tr(\"X4ZO\"))\n\tshield_bt.set_buff_tooltip(tr(\"XI2Z\"))\n\n\tshield_bt.add_event_on_cleanup(shield_bt_cleanup)\n\n\nfunc on_attack(_event: Event):\n\tvar b: Buff\n\tvar u: Tower\n\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 175.0)\n\tvar leech_counter: int = 0\n\tvar leech_power: int\n\tvar max_stacks: int = 5 + tower.get_level() / 5\n\n\twhile true:\n\t\tu = it.next()\n\n\t\tif u == null:\n\t\t\tbreak\n\n\t\tif u != tower && u.get_gold_cost() >= _stats.affected_gold_cost:\n\t\t\tleech_counter = leech_counter + 1\n\n\tif leech_counter == 0:\n\t\treturn\n\n# \t1% leech per tower with 1 tower, 0.65% per tower with 8 \n\tleech_power = _stats.leech_power_base - _stats.leech_power_add * leech_counter\n\n\tit = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.TOWERS), 175.0)\n\n# \tSlows all towers in 175 range\n\twhile true:\n\t\tu = it.next()\n\n\t\tif u == null:\n\t\t\tbreak\n\n\t\tif u != tower && u.get_gold_cost() >= _stats.affected_gold_cost:\n\t\t\tb = u.get_buff_of_type(drain_bt)\n\n\t\t\tvar active_stacks_for_drain: int\n\t\t\tif b != null:\n\t\t\t\tactive_stacks_for_drain = b.user_int\n\t\t\telse:\n\t\t\t\tactive_stacks_for_drain = 0\n\n\t\t\tvar new_stacks_for_drain: int = min(active_stacks_for_drain + 1, max_stacks)\n\t\t\tvar new_buff_level_for_drain: int = leech_power * new_stacks_for_drain\n\n\t\t\tb = drain_bt.apply(tower, u, new_buff_level_for_drain)\n\t\t\tb.user_int = new_stacks_for_drain\n\t\t\tb.set_displayed_stacks(new_stacks_for_drain)\n\n#\tin a way, that's the per stack base\n\tleech_power = leech_power * leech_counter\n\tb = tower.get_buff_of_type(zeal_bt)\n\n\tvar active_stacks_for_zeal: int\n\tif b != null:\n\t\tactive_stacks_for_zeal = b.user_int\n\telse:\n\t\tactive_stacks_for_zeal = 0\n\n\tvar new_stacks_for_zeal: int = min(active_stacks_for_zeal + 1, max_stacks)\n\tvar new_buff_level_for_zeal: int = leech_power * new_stacks_for_zeal\n\n#\tnow apply zeal\n\tb = zeal_bt.apply(tower, tower, new_buff_level_for_zeal)\n\tb.user_int = new_stacks_for_zeal\n\tb.set_displayed_stacks(new_stacks_for_zeal)\n\t\n\tb = tower.get_buff_of_type(shield_bt)\n\n\tif b != null:\n\t\tif b.user_int < max_stacks:\n\t\t\tb.user_int = b.user_int + 1\n\n\t\t\tif b.user_int == max_stacks:\n\t\t\t\tif b.user_int2 == 0:\n\t\t\t\t\tb.user_int2 = Effect.create_simple_at_unit(\"res://src/effects/mana_shield_cycle.tscn\", tower)\n\t\t\t\t\tEffect.set_auto_destroy_enabled(b.user_int2, false)\n\n\t\tshield_bt.apply(tower, tower, _stats.shield_power * b.user_int)\n\telse:\n\t\tb = shield_bt.apply(tower, tower, _stats.shield_power)\n\t\tb.user_int = 1\n\t\tb.user_int2 = 0\n\n\nfunc on_damage(event: Event):\n\tvar target: Creep = event.get_target()\n\tvar phase_wound: Buff = target.get_buff_of_type(wound_bt)\n\tvar damage_base: float = event.damage\n\tvar total_armor_pierce: float\n\tvar temp: float = AttackType.get_damage_against(AttackType.enm.PHYSICAL, target.get_armor_type())\n\n\tif event.is_spell_damage() || !event.is_main_target():\n\t\treturn\n\n#\tfirst check + upgrade the wound level\n\tif phase_wound == null:\n\t\tphase_wound = wound_bt.apply(tower, target, 1)\n#\t\tstack counter\n\t\tphase_wound.user_int = 1\n\t\tphase_wound.user_int2 = tower.get_instance_id()\n\telse:\n#\t\tmultiple zealots + family member check. If another zealot attacks, no armor pierce for him\n#\t\tonly the guy who put the first wound gets armor pierce\n#\t\tperfection would need hashtables storing wound level for every tower,creep pair. Not worth it i think.\n\t\tif phase_wound.user_int2 != tower.get_instance_id():\n\t\t\treturn\n\n\t\tphase_wound.user_int = min(5, phase_wound.user_int + 1)\n\t\tphase_wound.refresh_duration()\n\n\tif phase_wound != null:\n\t\tphase_wound.set_displayed_stacks(phase_wound.user_int)\n\n#\tignoring armor type \"resistance\" not weakness :P\n\tif temp > 0.001 && temp < 1.0:\n\t\tdamage_base = damage_base / temp\n\n\ttemp = 1 - target.get_current_armor_damage_reduction()\n\n\tif temp > 0.001 && temp < 1.0:\n\t\tdamage_base = damage_base / temp\n\n\ttotal_armor_pierce = (_stats.wound_power + _stats.wound_power_add * tower.get_level()) * phase_wound.user_int\n\n\tif event.damage < damage_base:\n\t\tevent.damage = damage_base * total_armor_pierce + event.damage * (1.0 - total_armor_pierce)\n"
  },
  {
    "path": "src/towers/tower_behaviors/zeus.gd",
    "content": "extends TowerBehavior\n\n\n# NOTE: original script did thunder by enabling periodic\n# event. Changed to use a bool flag instead.\n\n\nvar stun_bt: BuffType\n\n\nvar bolt_count: int = 0\nvar thunder_effect: int = 0\nvar thunder_is_enabled: bool = false\n\n\nfunc load_triggers(triggers: BuffType):\n\ttriggers.add_event_on_damage(on_damage)\n\ttriggers.add_event_on_kill(on_kill)\n\ttriggers.add_periodic_event(periodic, 0.2)\n\n\nfunc tower_init():\n\tstun_bt = CbStun.new(\"stun_bt\", 0, 0, false, self)\n\n\nfunc on_damage(event: Event):\n\tvar target: Unit = event.get_target()\n\tvar damage: float = 500 + 20 * tower.get_level()\n\n\tif event.is_main_target():\n\t\ttower.do_spell_damage_aoe_unit(target, 175, damage, tower.calc_spell_crit_no_bonus(), 0.0)\n\n\nfunc on_kill(_event: Event):\n\ttower.add_mana_perc(0.05)\n\n\nfunc on_destruct():\n\tif thunder_effect != 0:\n\t\tEffect.destroy_effect(thunder_effect)\n\t\tthunder_effect = 0\n\n\nfunc periodic(_event: Event):\n\tvar bolt_damage: float = 2500 + 125 * tower.get_level()\n\n\tif !thunder_is_enabled:\n\t\treturn\n\n\tif bolt_count > 0:\n\t\tvar it: Iterate = Iterate.over_units_in_range_of_caster(tower, TargetType.new(TargetType.CREEPS), 1200)\n\t\tvar bolt_target: Creep = it.next_random()\n\n\t\tif bolt_target != null:\n\t\t\ttower.do_spell_damage(bolt_target, bolt_damage, tower.calc_spell_crit_no_bonus())\n\n\t\t\tvar do_stun: bool\n\t\t\tif bolt_target.get_size() >= CreepSize.enm.BOSS:\n\t\t\t\tdo_stun = tower.calc_chance(0.20)\n\t\t\telse:\n\t\t\t\tdo_stun = true\n\n\t\t\tif do_stun:\n\t\t\t\tstun_bt.apply_only_timed(tower, bolt_target, 0.5)\n\n\t\t\tEffect.create_simple_at_unit(\"res://src/effects/monsoon_bolt.tscn\", bolt_target)\n\n\t\tbolt_count -= 1\n\telse:\n\t\tif thunder_effect != 0:\n\t\t\tEffect.destroy_effect(thunder_effect)\n\t\t\tthunder_effect = 0\n\n\nfunc on_autocast(_event: Event):\n\tbolt_count = 20 + int(0.2 * tower.get_level())\n\n\tif thunder_effect == 0:\n\t\tthunder_effect = Effect.create_simple_at_unit(\"res://src/effects/purge_buff_target.tscn\", tower)\n\t\tEffect.set_auto_destroy_enabled(thunder_effect, false)\n\n\tthunder_is_enabled = true\n\n"
  },
  {
    "path": "src/towers/tower_preview.gd",
    "content": "class_name TowerPreview\nextends Node2D\n\n\n@export var _build_space: BuildSpace\n\n\nconst opaque_red := Color(1, 0, 0, 0.5)\nconst opaque_green := Color(0, 1, 0, 0.5)\nconst opaque_blue := Color(0, 0, 1, 0.5)\n\nvar _tower_id: int = 0\nvar _tower_sprite: Node2D = null\n\n@export var _pedestal_up: Polygon2D\n@export var _pedestal_right: Polygon2D\n@export var _pedestal_down: Polygon2D\n@export var _pedestal_left: Polygon2D\n@export var _range_indicator_container: Node2D\n@export var _transform_label: RichTextLabel\n@export var _sprite_parent: Node2D\n\n\nfunc set_tower(tower_id: int):\n\tif _tower_sprite != null:\n\t\t_sprite_parent.remove_child(_tower_sprite)\n\t\t_tower_sprite.queue_free()\n\t\t_tower_sprite = null\n\t\t\n\tfor old_range_indicator in _range_indicator_container.get_children():\n\t\told_range_indicator.queue_free()\n\t\n\t_tower_id = tower_id\n\t\n\t_tower_sprite = TowerSprites.get_sprite(tower_id)\n\t_sprite_parent.add_child(_tower_sprite)\n\t\n\tvar range_data_list: Array[RangeData] = TowerProperties.get_range_data_list(tower_id)\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tUtils.setup_range_indicators(range_data_list, _range_indicator_container, local_player)\n\n\nfunc set_range_manual(radius: int, friendly: bool, is_attack: bool = false):\n\tfor old_range_indicator in _range_indicator_container.get_children():\n\t\told_range_indicator.queue_free()\n\n\tvar target_type: TargetType\n\tif friendly:\n\t\ttarget_type = TargetType.new(TargetType.TOWERS)\n\telse:\n\t\ttarget_type = TargetType.new(TargetType.CREEPS)\n\n\tvar range_data: RangeData = RangeData.new(\"\", radius, target_type, is_attack)\n\tvar range_data_list: Array[RangeData] = [range_data]\n\t\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tUtils.setup_range_indicators(range_data_list, _range_indicator_container, local_player)\n\n\nfunc get_tower_id() -> int:\n\treturn _tower_id\n\n\nfunc _process(_delta: float):\n\tif !visible || _tower_sprite == null:\n\t\treturn\n\t\n\tvar mouse_pos: Vector2 = get_global_mouse_position()\n\n# \tShow tower preview under map normally, but make it stick\n# \tto tile position when mouse is hovered over a buildable\n# \ttile.\n\tvar new_position: Vector2 = VectorUtils.snap_canvas_pos_to_buildable_pos(mouse_pos)\n\tposition = new_position\n\n\tvar can_transform: bool = _build_space.can_transform_at_pos(mouse_pos)\n\n\tif can_transform:\n\t\t_sprite_parent.modulate = opaque_blue\n\telse:\n\t\t_sprite_parent.modulate = Color.WHITE\n\t\n\t_transform_label.visible = can_transform\n\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar build_info: Array = _build_space.get_build_info_for_pos(local_player, mouse_pos)\n\tvar polygon_list: Array = [\n\t\t_pedestal_up,\n\t\t_pedestal_right,\n\t\t_pedestal_down,\n\t\t_pedestal_left,\n\t]\n\n\tfor i in range(0, 4):\n\t\tvar quarter_tile_is_ok: bool = build_info[i]\n\t\tvar pedestal: Polygon2D = polygon_list[i]\n\n\t\tif can_transform:\n\t\t\tpedestal.color = opaque_blue\n\t\telif quarter_tile_is_ok:\n\t\t\tpedestal.color = Color(Color.GREEN, 0.5)\n\t\telse:\n\t\t\tpedestal.color = Color(Color.RED, 0.5)\n"
  },
  {
    "path": "src/towers/tower_preview.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://db0630tccvc2i\"]\n\n[ext_resource type=\"Script\" path=\"res://src/towers/tower_preview.gd\" id=\"1\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_xnufi\"]\n\n[node name=\"TowerPreview\" type=\"Node2D\" node_paths=PackedStringArray(\"_pedestal_up\", \"_pedestal_right\", \"_pedestal_down\", \"_pedestal_left\", \"_range_indicator_container\", \"_transform_label\", \"_sprite_parent\")]\nscript = ExtResource(\"1\")\n_pedestal_up = NodePath(\"Pedestal/PedestalUp\")\n_pedestal_right = NodePath(\"Pedestal/PedestalRight\")\n_pedestal_down = NodePath(\"Pedestal/PedestalDown\")\n_pedestal_left = NodePath(\"Pedestal/PedestalLeft\")\n_range_indicator_container = NodePath(\"RangeIndicatorContainer\")\n_transform_label = NodePath(\"MarginContainer/TransformLabel\")\n_sprite_parent = NodePath(\"SpriteParent\")\n\n[node name=\"Pedestal\" type=\"Node2D\" parent=\".\"]\n\n[node name=\"PedestalUp\" type=\"Polygon2D\" parent=\"Pedestal\"]\ncolor = Color(1, 0, 0, 1)\npolygon = PackedVector2Array(0, 0, -64, -32, 0, -64, 64, -32)\n\n[node name=\"PedestalRight\" type=\"Polygon2D\" parent=\"Pedestal\"]\ncolor = Color(0, 1, 0, 1)\npolygon = PackedVector2Array(0, 0, 64, -32, 128, 0, 64, 32)\n\n[node name=\"PedestalDown\" type=\"Polygon2D\" parent=\"Pedestal\"]\ncolor = Color(0, 0, 1, 1)\npolygon = PackedVector2Array(0, 0, 64, 32, 0, 64, -64, 32)\n\n[node name=\"PedestalLeft\" type=\"Polygon2D\" parent=\"Pedestal\"]\ncolor = Color(1, 1, 0, 1)\npolygon = PackedVector2Array(0, 0, -64, 32, -128, 0, -64, -32)\n\n[node name=\"RangeIndicatorContainer\" type=\"Node2D\" parent=\".\"]\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(300, 0)\nanchors_preset = 5\nanchor_left = 0.5\nanchor_right = 0.5\noffset_left = -84.5\noffset_right = 84.5\noffset_bottom = 40.0\ngrow_horizontal = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = 40\n\n[node name=\"TransformLabel\" type=\"RichTextLabel\" parent=\"MarginContainer\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme = ExtResource(\"2_xnufi\")\ntheme_type_variation = &\"MessageLabel\"\nbbcode_enabled = true\ntext = \"[center][color=CORNFLOWER_BLUE]Transform Tower[/color][/center]\"\nfit_content = true\nscroll_active = false\n\n[node name=\"SpriteParent\" type=\"Node2D\" parent=\".\"]\n"
  },
  {
    "path": "src/towers/tower_sprites/abandoned_pit_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dmhldtxy8kcxb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_tkfbj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mr3l7\"]\natlas = ExtResource(\"1_tkfbj\")\nregion = Rect2(54, 69, 143, 133)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_mr3l7\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/abandoned_pit_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://xgy488riucmp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_8vidd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8vidd\")\nregion = Rect2(54, 69, 143, 133)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/abandoned_pit_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://duffbnfslfcjb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_6st3d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6st3d\")\nregion = Rect2(286, 47, 200, 185)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/abandoned_pit_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cl2wyo6gj55sn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_dj46d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_dj46d\")\nregion = Rect2(286, 47, 200, 185)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/abandoned_pit_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://4ikn4gvhefc4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_y4d1u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_y4d1u\")\nregion = Rect2(537, 39, 208, 188)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/abominable_snowman_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b7h8jdkdwhf51\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_i1b6y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_i1b6y\")\nregion = Rect2(45, 549, 151, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-15, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/abominable_snowman_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b6u76i5rke1su\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_bb702\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_bb702\")\nregion = Rect2(45, 549, 151, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-15, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/abominable_snowman_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://e8fnotm5tkml\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_dpafa\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_dpafa\")\nregion = Rect2(294, 527, 162, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/abominable_snowman_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c7jgb40dwwvga\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_d4ni5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_d4ni5\")\nregion = Rect2(294, 527, 162, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/abominable_snowman_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://pptlv1mdldhe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_wtwvm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_wtwvm\")\nregion = Rect2(530, 537, 208, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/afflicted_obelisk_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://mcjq42wyycw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_ya0gh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ya0gh\")\nregion = Rect2(573, 33, 140, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/afflicted_obelisk_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dskyi66wmps0g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_36u3w\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_36u3w\")\nregion = Rect2(573, 33, 140, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/afflicted_obelisk_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d3655fwvj04k3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_cvjpt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_cvjpt\")\nregion = Rect2(810, 21, 168, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/afflicted_obelisk_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cdspvfclt0ku\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_j6dn6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_j6dn6\")\nregion = Rect2(810, 21, 168, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/ancient_energy_converter_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bnotir7wlb8h0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_wk4x5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_wk4x5\")\nregion = Rect2(555, 306, 177, 151)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/annoyed_tree_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://6oy30n46xtot\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_8paw2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8paw2\")\nregion = Rect2(806, 532, 175, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/annoyed_tree_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://sfgq2gnbdr7s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_80yua\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_80yua\")\nregion = Rect2(806, 532, 175, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/annoyed_tree_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://uitxtvg6peyw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_ov0yd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ov0yd\")\nregion = Rect2(37, 800, 180, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/annoyed_tree_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://wg6e8xx526ws\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_d7abi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_d7abi\")\nregion = Rect2(37, 800, 180, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/arcane_storm_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dxsrr4rmmor2g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_u0ovf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5qgbj\"]\natlas = ExtResource(\"1_u0ovf\")\nregion = Rect2(31, 773, 206, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_5qgbj\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/area_roaster_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cctuhq6fpciil\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_8cdw4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8cdw4\")\nregion = Rect2(47, 19, 176, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/area_roaster_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://x45noienvfk4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_hl1gk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hl1gk\")\nregion = Rect2(47, 19, 176, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/area_roaster_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dgv6qy4q5vq4w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_a1fj5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_a1fj5\")\nregion = Rect2(321, 6, 151, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/ash_geyser_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ugj5i3defmi4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_3fejv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_3fejv\")\nregion = Rect2(813, 788, 152, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ash_geyser_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dd2fpdjk6611i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_me2s2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_me2s2\")\nregion = Rect2(813, 788, 152, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ash_geyser_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dyyw3u6yvsmdb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_6wcea\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6wcea\")\nregion = Rect2(61, 1037, 131, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ash_geyser_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cp1ocqdos2l7k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_0tnry\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0tnry\")\nregion = Rect2(61, 1037, 131, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ash_geyser_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://br4lupf5ufoax\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_3pbru\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_3pbru\")\nregion = Rect2(298, 1033, 169, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/astral_lantern_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://chwqg617pdrr4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_06mcv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_06mcv\")\nregion = Rect2(821, 21, 149, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/astral_lantern_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b23mamsph7m8b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_a4vyk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_a4vyk\")\nregion = Rect2(821, 21, 149, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/astral_lantern_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bhik36i2e3ceo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_e3v40\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_e3v40\")\nregion = Rect2(54, 270, 169, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/astral_lantern_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b1h5ibhevhw0j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_v4bk6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_v4bk6\")\nregion = Rect2(54, 270, 169, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/astral_rift_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0sna04rev6n4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_4dn6g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_bok7r\"]\natlas = ExtResource(\"1_4dn6g\")\nregion = Rect2(560, 65, 175, 133)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_bok7r\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_plant_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://begswdyxi40yh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_jik1m\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jik1m\")\nregion = Rect2(292, 575, 180, 162)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nposition = Vector2(0, -10)\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_plant_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bhqqrmjk0w0jf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_2yt1i\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2yt1i\")\nregion = Rect2(292, 575, 180, 162)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nposition = Vector2(0, -10)\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_plant_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cocirrquo1lv3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_dkq85\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_dkq85\")\nregion = Rect2(539, 555, 211, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_plant_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cb3llbhg8kexh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_ojh1n\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ojh1n\")\nregion = Rect2(539, 555, 211, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_plant_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://by8v3j82xt8hh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_8xgwd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8xgwd\")\nregion = Rect2(796, 545, 199, 199)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_plant_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bs2wjfa4gi2s1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_kvo1k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_kvo1k\")\nregion = Rect2(796, 545, 199, 199)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_tuskin_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cu06kip6x0r3m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_rfbqa\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rfbqa\")\nregion = Rect2(46, 280, 180, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_tuskin_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://hoq65tf3jnly\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_o5nbp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_o5nbp\")\nregion = Rect2(46, 280, 180, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/baby_tuskin_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dy7lka0xctvo6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_3p4vp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_3p4vp\")\nregion = Rect2(264, 266, 215, 235)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-28, -84)\n"
  },
  {
    "path": "src/towers/tower_sprites/ball_lightning_accelerator_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ll5yi1a1gjej\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_pr8qm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_pr8qm\")\nregion = Rect2(537, 60, 190, 176)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/ball_lightning_accelerator_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://crm0mxm2ya8um\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_xv22d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xv22d\")\nregion = Rect2(537, 60, 190, 176)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/basic_knowledge_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dv6l6ro2hfynv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_ahil1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ahil1\")\nregion = Rect2(555, 829, 172, 134)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/basic_knowledge_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cimkw3o0mx42o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_gslxf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_gslxf\")\nregion = Rect2(555, 829, 172, 134)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/basic_knowledge_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://g1ftpwx725ww\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_buxsg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_buxsg\")\nregion = Rect2(791, 789, 222, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/basic_knowledge_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dnkawbmprjblw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_8m88g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8m88g\")\nregion = Rect2(791, 789, 222, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/basic_knowledge_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0mxdhany5vsr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_0cpue\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0cpue\")\nregion = Rect2(26, 1087, 202, 172)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/black_dragon_roost_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://da7bx6gkhmj52\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_57gub\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nlri5\"]\natlas = ExtResource(\"1_57gub\")\nregion = Rect2(785, 30, 224, 194)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_nlri5\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/black_rock_totem_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://tk5if84ob1l2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_v7nb5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1at1v\"]\natlas = ExtResource(\"1_v7nb5\")\nregion = Rect2(60, 17, 157, 230)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_1at1v\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/bomb_turret_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfdfjg4ltjpjt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_2s0pg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2s0pg\")\nregion = Rect2(293, 276, 173, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/bomb_turret_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dccp0gjt2apf1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_ep211\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ep211\")\nregion = Rect2(293, 276, 173, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/bone_shrine_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://sxw2ijk4dygm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_0ftyt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0ftyt\")\nregion = Rect2(37, 266, 210, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/bone_shrine_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://beobycdns0r3e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_nq0os\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_nq0os\")\nregion = Rect2(37, 266, 210, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/bone_shrine_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dym6a3fexliwb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_uvkp0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_uvkp0\")\nregion = Rect2(290, 271, 196, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/bonk_the_living_mountain_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://j1ciji7828ex\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_uq0om\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mf40d\"]\natlas = ExtResource(\"1_uq0om\")\nregion = Rect2(534, 14, 200, 230)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.5, 0.5)\ntexture = SubResource(\"AtlasTexture_mf40d\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_cage_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bri0igq3xrapp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_lqb4k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_lqb4k\")\nregion = Rect2(830, 804, 138, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_cage_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b5y8cot2r3ycy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_jfdx5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jfdx5\")\nregion = Rect2(830, 804, 138, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_cage_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://w0slcjnyguwi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_abt01\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_abt01\")\nregion = Rect2(58, 1039, 172, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_cage_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bsfl1iigg6lap\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_ult0q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ult0q\")\nregion = Rect2(58, 1039, 172, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_cage_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://2gv1b4fo3fdr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_hha2e\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hha2e\")\nregion = Rect2(301, 1044, 194, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_circle_of_wind_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://pcil7nd30tb0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_kw2n7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_kw2n7\")\nregion = Rect2(828, 561, 125, 153)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_circle_of_wind_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bl0r03xpaki5e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_qvghv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_qvghv\")\nregion = Rect2(828, 561, 125, 153)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_circle_of_wind_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://drj301nbtswf1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_8mk4q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8mk4q\")\nregion = Rect2(37, 812, 185, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_circle_of_wind_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bqjbo0pqwflsa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_7fhww\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7fhww\")\nregion = Rect2(37, 812, 185, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_circle_of_wind_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://x538qt8vc4nr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_i158s\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_i158s\")\nregion = Rect2(285, 806, 177, 173)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_fire_pit_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dabe153mkx5gs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_34k5a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_34k5a\")\nregion = Rect2(316, 598, 142, 116)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_fire_pit_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dhr6ed6y136s1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_hnsft\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hnsft\")\nregion = Rect2(316, 598, 142, 116)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_fire_pit_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dhtb5bdhch31e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_suukc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_suukc\")\nregion = Rect2(546, 562, 179, 165)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_fire_pit_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://didpklufavd5u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_vdq7u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vdq7u\")\nregion = Rect2(546, 562, 179, 165)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -10)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_fire_pit_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dqau7qlsni14v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_y777k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_y777k\")\nregion = Rect2(810, 542, 195, 168)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_lightning_rod_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cl1naq76234p1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_4j7ia\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_4j7ia\")\nregion = Rect2(57, 40, 132, 175)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_lightning_rod_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bye3ycuukmjql\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_j8tq7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_j8tq7\")\nregion = Rect2(57, 40, 132, 175)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_lightning_rod_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c7s4igedl646i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_08ngg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_08ngg\")\nregion = Rect2(309, 35, 122, 198)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_lightning_rod_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dyov81bag2xpt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_kgvct\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_kgvct\")\nregion = Rect2(309, 35, 122, 198)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/broken_lightning_rod_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d3f8n1se0fk1f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_mmpvs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_mmpvs\")\nregion = Rect2(541, 37, 171, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/bronze_dragon_roost_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cp618dl6mmm6v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_46tik\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wfouq\"]\natlas = ExtResource(\"1_46tik\")\nregion = Rect2(291, 11, 191, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_wfouq\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/buried_soul_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c1pqjd2bosxqi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_s3qu4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_s3qu4\")\nregion = Rect2(538, 803, 190, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/buried_soul_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjphea6c8qjmr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_fso2e\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_fso2e\")\nregion = Rect2(538, 803, 190, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/buried_soul_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://44b6ek5ne03d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_frdj7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_frdj7\")\nregion = Rect2(794, 791, 189, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/buried_soul_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dj4t66o4k00y3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_l5swf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_l5swf\")\nregion = Rect2(794, 791, 189, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/burning_watchtower_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dlewnavhv4bda\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_ln4mq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ln4mq\")\nregion = Rect2(582, 1044, 106, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/burning_watchtower_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bltrqfs8tn3uu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_v2fk4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_v2fk4\")\nregion = Rect2(582, 1044, 106, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/burning_watchtower_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cctu4ss1iy0t1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_r4mvx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_r4mvx\")\nregion = Rect2(843, 1050, 128, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/burning_watchtower_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dc43iy5v2f4lu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_nt8dp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_nt8dp\")\nregion = Rect2(843, 1050, 128, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/burrow_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dyqch4hbpnd5x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_nckub\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_nckub\")\nregion = Rect2(569, 36, 149, 161)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/burrow_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cqdwct2p441jb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_7mwa0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7mwa0\")\nregion = Rect2(569, 36, 149, 161)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/burrow_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjy5sn3e2lxeu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_xnuii\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xnuii\")\nregion = Rect2(803, 7, 196, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/burrow_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0dnx3qijey12\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_mvp01\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_mvp01\")\nregion = Rect2(803, 7, 196, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/caged_fire_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvxa831ktnjaw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_dwlk8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_dwlk8\")\nregion = Rect2(546, 28, 183, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/caged_fire_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://clcfklna0btbo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_0tteg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_0tteg\")\nregion = Rect2(546, 28, 183, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cenarion_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dishn5seksmb2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_atuy6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3v3bd\"]\natlas = ExtResource(\"1_atuy6\")\nregion = Rect2(787, 10, 195, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_3v3bd\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/chaining_storm_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ckcf4t8h5drf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_ky2fs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vqb55\"]\natlas = ExtResource(\"1_ky2fs\")\nregion = Rect2(61, 545, 155, 178)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_vqb55\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/chaos_warlock_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c1m80i6vob67i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_v6ukw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_pn1x1\"]\natlas = ExtResource(\"1_v6ukw\")\nregion = Rect2(266, 7, 240, 235)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_pn1x1\")\noffset = Vector2(-40, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/chaos_warlock_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://drcshpx2hbb44\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_kuv8j\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_los0u\"]\natlas = ExtResource(\"1_kuv8j\")\nregion = Rect2(266, 7, 240, 235)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_los0u\")\noffset = Vector2(-40, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/charged_obelisk_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bkgrp2le24wea\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_rr6fh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tbv16\"]\natlas = ExtResource(\"1_rr6fh\")\nregion = Rect2(297, 77, 185, 118)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_tbv16\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/chilled_spire_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d01jqs25c5w6m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_nc0bd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_nc0bd\")\nregion = Rect2(542, 257, 187, 250)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-2, -66)\n"
  },
  {
    "path": "src/towers/tower_sprites/chilled_spire_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cs6bo2ikvudbx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_ybjwi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ybjwi\")\nregion = Rect2(552, 270, 168, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-2, -66)\n"
  },
  {
    "path": "src/towers/tower_sprites/cloud_warrior_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dokb5ms5rgs7k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_g2w41\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_g2w41\")\nregion = Rect2(52, 555, 156, 167)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/cloud_warrior_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bpmblch4qe5dh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_v4xvv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_v4xvv\")\nregion = Rect2(52, 555, 156, 167)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/cloud_warrior_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://baqcikjrraave\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_7d1ku\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7d1ku\")\nregion = Rect2(303, 536, 164, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/cloud_warrior_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://y7mfp0oqsytj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_c8dux\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_c8dux\")\nregion = Rect2(303, 536, 164, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/cloud_warrior_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbmkeprn4h1a2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_luik3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_luik3\")\nregion = Rect2(541, 529, 220, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/cloudy_temple_of_absorption_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://lwypx86rsxbe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_k74py\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nx5vi\"]\natlas = ExtResource(\"1_k74py\")\nregion = Rect2(35, 23, 206, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_nx5vi\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/coconut_sapling_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ujsptj3rk60e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_skrwf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_skrwf\")\nregion = Rect2(45, 529, 185, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/coconut_sapling_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://mukqfcimjqku\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_txhui\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_txhui\")\nregion = Rect2(45, 529, 185, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/coin_machine_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b3fm300nnujgr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_c4as4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_c4as4\")\nregion = Rect2(71, 541, 141, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/coin_machine_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c2d2gbt1fvxer\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_l44dj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_l44dj\")\nregion = Rect2(71, 541, 141, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_obelisk_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ba71hglh0f4mj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_7r1rj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7r1rj\")\nregion = Rect2(815, 539, 163, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_obelisk_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bkfblncf1faiu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_2xf00\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2xf00\")\nregion = Rect2(815, 539, 163, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_obelisk_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://utgv8w7o5ki8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_qt5hx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_qt5hx\")\nregion = Rect2(32, 776, 190, 239)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_troll_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dybwpcqeh8jr1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_a1n2w\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_a1n2w\")\nregion = Rect2(308, 548, 144, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_troll_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dahh11vtgrjmt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_dy1wk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_dy1wk\")\nregion = Rect2(308, 548, 144, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_troll_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cgcb1emkhafgn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_ryetg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ryetg\")\nregion = Rect2(550, 520, 180, 241)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/cold_troll_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://clvtbs3e5rcdf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_yi34k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_yi34k\")\nregion = Rect2(550, 520, 180, 241)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/contraption_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cpua72gnt6gvy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_mc7k1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_83glq\"]\natlas = ExtResource(\"1_mc7k1\")\nregion = Rect2(33, 288, 202, 220)\n\n[node name=\"contraption_1\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_83glq\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/contraption_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1mj618kpmr6m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_px4us\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1hhp3\"]\natlas = ExtResource(\"1_px4us\")\nregion = Rect2(33, 288, 202, 220)\n\n[node name=\"contraption_2\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_1hhp3\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/contraption_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cva7qfa81sqb0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_240gw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_e4etq\"]\natlas = ExtResource(\"1_240gw\")\nregion = Rect2(33, 288, 202, 220)\n\n[node name=\"contraption_3\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_e4etq\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/contraption_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bnuny6ulnf7g3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_wqy7o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_do6fq\"]\natlas = ExtResource(\"1_wqy7o\")\nregion = Rect2(33, 288, 202, 220)\n\n[node name=\"contraption_4\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_do6fq\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/crimson_wyrm_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bh7t88vjl6dfc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_igd8r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_dknvc\"]\natlas = ExtResource(\"1_igd8r\")\nregion = Rect2(268, 27, 244, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_dknvc\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/cruel_fire_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dnhyqld0673k2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_dmoff\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jmwf3\"]\natlas = ExtResource(\"1_dmoff\")\nregion = Rect2(61, 825, 178, 150)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_jmwf3\")\noffset = Vector2(10, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cruel_fire_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dj3k8hnjl7jv3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_0mi7p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jmwf3\"]\natlas = ExtResource(\"1_0mi7p\")\nregion = Rect2(61, 825, 178, 150)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_jmwf3\")\noffset = Vector2(10, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cruel_fire_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b3mkbskca6wjg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_y8w4r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jmwf3\"]\natlas = ExtResource(\"1_y8w4r\")\nregion = Rect2(282, 798, 193, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_jmwf3\")\noffset = Vector2(-10, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cursed_grounds_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0ruhiy0nhjjs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_8okxf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_8okxf\")\nregion = Rect2(44, 525, 189, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/cursed_grounds_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dc25mqlsf4n4j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_2emrj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_2emrj\")\nregion = Rect2(44, 525, 189, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/cursed_grounds_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cy37rgiey6i52\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_nwt7p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_nwt7p\")\nregion = Rect2(297, 523, 180, 228)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/cute_small_spider_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dyqtymv8sfwc7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_255lr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_255lr\")\nregion = Rect2(26, 45, 199, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cute_small_spider_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d0tbebtq10b24\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_abf8p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_abf8p\")\nregion = Rect2(26, 45, 199, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cute_small_spider_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c6sbbbypuuy2d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_1olao\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_1olao\")\nregion = Rect2(277, 34, 213, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/cute_small_spider_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://lefhepbc6asa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_vut0a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vut0a\")\nregion = Rect2(277, 34, 213, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_battery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bruu0i75ymwtl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_hviey\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p2ksm\"]\natlas = ExtResource(\"1_hviey\")\nregion = Rect2(549, 291, 189, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"AtlasTexture_p2ksm\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_battery_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://vc8nl05wwyy7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_3s2t4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p2ksm\"]\natlas = ExtResource(\"1_3s2t4\")\nregion = Rect2(549, 291, 189, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_p2ksm\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_battery_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://h2gvrpx54opo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_n5h8v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_p2ksm\"]\natlas = ExtResource(\"1_n5h8v\")\nregion = Rect2(789, 278, 199, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_p2ksm\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_fire_pit_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cairlk5bf3p32\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_acgxh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_acgxh\")\nregion = Rect2(53, 73, 142, 116)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_fire_pit_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://r011cobuqqbh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_fclqn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_fclqn\")\nregion = Rect2(53, 73, 142, 116)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_fire_pit_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://brqlcrr4dgsag\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_xybvi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_xybvi\")\nregion = Rect2(294, 54, 179, 165)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_fire_pit_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cauycb0ih4wnx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_83082\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_83082\")\nregion = Rect2(294, 54, 179, 165)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/dark_fire_pit_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dbdafn75wlqbk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_v2w2f\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_v2w2f\")\nregion = Rect2(534, 40, 219, 189)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/death_knight_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c4bmigtq35ov7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_tus8p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7kmao\"]\natlas = ExtResource(\"1_tus8p\")\nregion = Rect2(797, 261, 196, 242)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_7kmao\")\noffset = Vector2(-10, -75)\n"
  },
  {
    "path": "src/towers/tower_sprites/dimensional_flux_collector_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c7ox7hs48c74l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_o5fuu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yowwo\"]\natlas = ExtResource(\"1_o5fuu\")\nregion = Rect2(291, 535, 183, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_yowwo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/dragon_sorcerer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://imwjjn7t13wg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_wywem\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xkfpf\"]\natlas = ExtResource(\"1_wywem\")\nregion = Rect2(16, 538, 198, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_xkfpf\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/drake_whisperer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://4qcmeugkryan\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_ahtq6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b6iv8\"]\natlas = ExtResource(\"1_ahtq6\")\nregion = Rect2(772, 294, 237, 189)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_b6iv8\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/dreadlord_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bhycgtdvf2pqq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_6bsyp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_3d2oi\"]\natlas = ExtResource(\"1_6bsyp\")\nregion = Rect2(518, 798, 248, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_3d2oi\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/dutchmans_grave_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bidci6dqflif0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_qg8dm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ipkbc\"]\natlas = ExtResource(\"1_qg8dm\")\nregion = Rect2(20, 532, 221, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_ipkbc\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/dwarven_forgery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://coo4ybhcblata\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_c3a8l\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cgkxt\"]\natlas = ExtResource(\"1_c3a8l\")\nregion = Rect2(529, 536, 210, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_cgkxt\")\noffset = Vector2(-10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/ebonfrost_crystal_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://batpvupgogo76\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_e6f4y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8ovuo\"]\natlas = ExtResource(\"1_e6f4y\")\nregion = Rect2(564, 257, 152, 254)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_8ovuo\")\noffset = Vector2(0, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/embershell_turtle_hatchling_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dsr3aetp4kc30\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_jagx2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jagx2\")\nregion = Rect2(35, 819, 175, 152)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/embershell_turtle_hatchling_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b0ftx7rgle3ji\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_cb01h\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_cb01h\")\nregion = Rect2(35, 819, 175, 152)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/embershell_turtle_hatchling_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c5hb4j6ec3hmd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_ccyx8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ccyx8\")\nregion = Rect2(285, 813, 198, 174)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/embershell_turtle_hatchling_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://gie0vat3aih1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_o8p7r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_o8p7r\")\nregion = Rect2(285, 813, 198, 174)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/embershell_turtle_hatchling_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dq2v05kojhk1y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_rwjrv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rwjrv\")\nregion = Rect2(540, 813, 215, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/energy_junction_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dfcnhucfocgeg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_8hiiy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8hiiy\")\nregion = Rect2(57, 32, 147, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/energy_junction_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dwf5l0q5xgg8k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_kxpur\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_kxpur\")\nregion = Rect2(57, 32, 147, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/energy_junction_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://gvf48iou7qe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_wt017\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_wt017\")\nregion = Rect2(307, 28, 175, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/essence_of_fury_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://boq3c52bkwo3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_6yvlm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6yvlm\")\nregion = Rect2(796, 535, 211, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/essence_of_fury_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bsiwjiunjj575\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_d6i2t\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_d6i2t\")\nregion = Rect2(796, 535, 211, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/essence_of_fury_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://jhs85dttml7e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_yyjav\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_yyjav\")\nregion = Rect2(47, 792, 173, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/essence_of_fury_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ps3w0qpqw41i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_85iws\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_85iws\")\nregion = Rect2(47, 792, 173, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/essence_of_fury_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cbdmbg62moynq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_o4t1f\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_o4t1f\")\nregion = Rect2(284, 799, 207, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/felweed_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dybcj8oj3t8va\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_8gylw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_8gylw\")\nregion = Rect2(565, 293, 127, 181)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/felweed_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cvujepqwstivg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_8ue5x\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_8ue5x\")\nregion = Rect2(565, 293, 127, 181)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/felweed_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dsre5f2qx4wam\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_ysxns\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ysxns\")\nregion = Rect2(791, 271, 215, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/felweed_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cyjpd4cp3brqu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_5hd5p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5hd5p\")\nregion = Rect2(791, 271, 215, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/felweed_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://beeuyjs2vnoq1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_7usna\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_7usna\")\nregion = Rect2(29, 530, 203, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/felweed_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cpnw5n0h4ydp6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_do61g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_do61g\")\nregion = Rect2(29, 530, 203, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fenced_flames_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dfnwa7g6pir35\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_m2wyu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6rswi\"]\natlas = ExtResource(\"1_m2wyu\")\nregion = Rect2(75, 1313, 135, 202)\n\n[node name=\"fenced_flames_1\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_6rswi\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/fenced_flames_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dck0q1bxf80i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_8vsvd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6rswi\"]\natlas = ExtResource(\"1_8vsvd\")\nregion = Rect2(75, 1313, 135, 202)\n\n[node name=\"fenced_flames_2\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_6rswi\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/fenced_flames_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ct1n5ipgkpmr4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_omrde\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6rswi\"]\natlas = ExtResource(\"1_omrde\")\nregion = Rect2(314, 1313, 147, 207)\n\n[node name=\"fenced_flames_3\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_6rswi\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/fenced_flames_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ddlw22iul1wfq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_xxclj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6rswi\"]\natlas = ExtResource(\"1_xxclj\")\nregion = Rect2(314, 1313, 147, 207)\n\n[node name=\"fenced_flames_4\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_6rswi\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_dog_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ra4efn1t776o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_yvwl3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_yvwl3\")\nregion = Rect2(546, 57, 203, 177)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_dog_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjj0ts6om38p0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_yhi72\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_yhi72\")\nregion = Rect2(546, 57, 203, 177)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_dog_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d37q48qk2i0fd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_0xq44\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0xq44\")\nregion = Rect2(779, 57, 228, 165)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_dog_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c78u7scv87q0o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_3jbem\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_3jbem\")\nregion = Rect2(779, 57, 228, 165)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_dog_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3wb55iabg7w0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_q3f41\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_q3f41\")\nregion = Rect2(18, 291, 204, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_pebble_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dpgd5wr78hg1j\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_3den1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_3den1\")\nregion = Rect2(59, 818, 148, 161)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_pebble_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3pd51n0t45tq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_r15he\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_r15he\")\nregion = Rect2(59, 818, 148, 161)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_pebble_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://btx5bi8py05kn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_3ujue\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_3ujue\")\nregion = Rect2(297, 785, 173, 188)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_pebble_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7lisichp53qu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_hg8iy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_hg8iy\")\nregion = Rect2(297, 785, 173, 188)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_pebble_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cc5j4mghnqdnt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_hnuil\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_hnuil\")\nregion = Rect2(533, 784, 217, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fiery_pebble_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://mhocbrc8w4xs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_ulac0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ulac0\")\nregion = Rect2(533, 784, 217, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fire_battery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b4782gby1b1ui\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_bkxe1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jmwf3\"]\natlas = ExtResource(\"1_bkxe1\")\nregion = Rect2(54, 565, 148, 153)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_jmwf3\")\noffset = Vector2(0, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/fire_battery_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cqn3xf0xm0d4v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_5m0v4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jmwf3\"]\natlas = ExtResource(\"1_5m0v4\")\nregion = Rect2(54, 565, 148, 153)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_jmwf3\")\noffset = Vector2(0, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/fire_battery_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://rj1md5f2m1km\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_hqlu5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_jmwf3\"]\natlas = ExtResource(\"1_hqlu5\")\nregion = Rect2(291, 553, 190, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_jmwf3\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fire_star_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://f8g2ap0pfa0b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_ww6cn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_m0553\"]\natlas = ExtResource(\"1_ww6cn\")\nregion = Rect2(278, 281, 222, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_m0553\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/firestorm_cell_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cp33hds7vro5a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_b6xco\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_b6xco\")\nregion = Rect2(557, 527, 171, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/firestorm_cell_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bi337bfeyls0f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_h6783\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_h6783\")\nregion = Rect2(557, 527, 171, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/firestorm_cell_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ccy3oh8pv1jg8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_oue00\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_oue00\")\nregion = Rect2(787, 529, 206, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/firestorm_cell_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b5v6xi4b23bqi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_orask\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_orask\")\nregion = Rect2(787, 529, 206, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/fisherman_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0iqbbjy1ctsw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_hg0a7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_40j2h\"]\natlas = ExtResource(\"1_hg0a7\")\nregion = Rect2(789, 32, 228, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_40j2h\")\noffset = Vector2(-50, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_archer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cp0k22swueuo5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_uubvd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_uubvd\")\nregion = Rect2(289, 780, 163, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_archer_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cy754u5xfvfun\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_1utga\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_1utga\")\nregion = Rect2(289, 780, 163, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_archer_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://txcrh5g4tj08\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_p5ul3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_p5ul3\")\nregion = Rect2(538, 792, 175, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_protectress_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://degcmpsw0hvl6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_7nd1r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_kkkcc\"]\natlas = ExtResource(\"1_7nd1r\")\nregion = Rect2(569, 269, 170, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_kkkcc\")\noffset = Vector2(5, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_troll_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://beagptgya82sa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_o5vfp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_o5vfp\")\nregion = Rect2(42, 270, 204, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_troll_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cp6kh4vgr0rha\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_cgh6v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_cgh6v\")\nregion = Rect2(42, 270, 204, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/forest_troll_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b1wyn6j0numcf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_5ovio\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_5ovio\")\nregion = Rect2(278, 264, 208, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/frost_root_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cw8277utkrl8b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_tkrij\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_tkrij\")\nregion = Rect2(31, 19, 191, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/frost_root_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://qv20h4yo37fw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_8rrpi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_8rrpi\")\nregion = Rect2(31, 19, 191, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/frost_root_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bli11njyc0mbs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_3f8x8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_3f8x8\")\nregion = Rect2(268, 17, 222, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"2\")\noffset = Vector2(-10, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/frost_root_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjylwv2pk68ja\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_v2wmq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_v2wmq\")\nregion = Rect2(268, 17, 222, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(-10, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/frost_root_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cn78wktf2dnlx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_rue4y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_rue4y\")\nregion = Rect2(544, 13, 201, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/frost_root_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://61yhkqjpdwla\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_7aa0y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_7aa0y\")\nregion = Rect2(544, 13, 201, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/frosty_rock_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://2abpsvxauc3o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_nsi2p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_nsi2p\")\nregion = Rect2(836, 794, 123, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/frosty_rock_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7iax85sm3asn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_nhorb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_nhorb\")\nregion = Rect2(836, 794, 123, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/frosty_rock_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bn0w3sl02klmt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_6vx0p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6vx0p\")\nregion = Rect2(57, 1034, 149, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/frosty_rock_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ddsg4djupbg0s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_j1wxi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_j1wxi\")\nregion = Rect2(57, 1034, 149, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/frozen_well_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bq8rblnxs80pj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_wt534\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1b1om\"]\natlas = ExtResource(\"1_wt534\")\nregion = Rect2(41, 48, 178, 159)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nposition = Vector2(-1, -81)\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_1b1om\")\noffset = Vector2(0, 60)\n"
  },
  {
    "path": "src/towers/tower_sprites/garden_of_eden_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dr87sy3gdolfn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_yvuke\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_av1fm\"]\natlas = ExtResource(\"1_yvuke\")\nregion = Rect2(280, 517, 200, 226)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_av1fm\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/gatling_gun_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cesi1cpi0sgu7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_bco86\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1qpiv\"]\natlas = ExtResource(\"1_bco86\")\nregion = Rect2(788, 10, 227, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_1qpiv\")\noffset = Vector2(-20, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/genis_sage_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://l647hnp5e7wf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_cl5b3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lunjb\"]\natlas = ExtResource(\"1_cl5b3\")\nregion = Rect2(531, 9, 196, 245)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_lunjb\")\noffset = Vector2(-10, -100)\n"
  },
  {
    "path": "src/towers/tower_sprites/geothermal_extractor_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://jnoi4tga7xcs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_rvj1n\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hcvfx\"]\natlas = ExtResource(\"1_rvj1n\")\nregion = Rect2(788, 43, 209, 169)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_hcvfx\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/geothermal_extractor_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d0ca5dsvba6w1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_50nhu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_sntxq\"]\natlas = ExtResource(\"1_50nhu\")\nregion = Rect2(788, 43, 209, 169)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_sntxq\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/glaive_master_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bl0r65c1oqtpc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_km5xl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cyn0x\"]\natlas = ExtResource(\"1_km5xl\")\nregion = Rect2(275, 528, 226, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_cyn0x\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/glowing_solar_orb_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbuv6sry1soa3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_5gxdl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5gxdl\")\nregion = Rect2(320, 581, 130, 123)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/glowing_solar_orb_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://eqxnab20bnau\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_plgek\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_plgek\")\nregion = Rect2(320, 581, 130, 123)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/glowing_solar_orb_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b6xegxxm4uo6o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_pgr4q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_pgr4q\")\nregion = Rect2(554, 559, 164, 164)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/glowing_solar_orb_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bdaqxmo1d85b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_fihrs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_fihrs\")\nregion = Rect2(554, 559, 164, 164)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/glowing_solar_orb_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dd53h1he1ovn7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_sk2nv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_sk2nv\")\nregion = Rect2(799, 552, 203, 190)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/gnoll_thunder_mage_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://r2kackqyla7f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_qvgo8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_qvgo8\")\nregion = Rect2(322, 265, 151, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/gnoll_thunder_mage_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://coyptix0e5a06\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_t1qoy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_t1qoy\")\nregion = Rect2(322, 265, 151, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/gnoll_thunder_mage_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dsnb3ridb0cft\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_si1vr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_si1vr\")\nregion = Rect2(552, 282, 160, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/goblin_stronghold_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bnyosfcfjxueo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_86wos\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_msns3\"]\natlas = ExtResource(\"1_86wos\")\nregion = Rect2(541, 286, 199, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_msns3\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/grab-o-bot_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cv8d3j6nutacj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_ffqj5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_geje6\"]\natlas = ExtResource(\"1_ffqj5\")\nregion = Rect2(19, 31, 215, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_geje6\")\noffset = Vector2(-30, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/green_dragon_roost_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bcxps81d07xyw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_dhjis\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_owjfg\"]\natlas = ExtResource(\"1_dhjis\")\nregion = Rect2(824, 277, 148, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_owjfg\")\noffset = Vector2(-5, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/green_lightning_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bufpy2455a0lb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_i2eln\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_i2eln\")\nregion = Rect2(799, 262, 176, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/green_lightning_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bsrtu2g85y0od\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_u73a4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_u73a4\")\nregion = Rect2(799, 262, 176, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/green_lightning_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dvjf7holn5mrb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_866vb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_866vb\")\nregion = Rect2(32, 525, 208, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/green_lightning_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cdjfy5u6ayaya\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_r8iwu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_r8iwu\")\nregion = Rect2(32, 525, 208, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/greyfang_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cohvvjatutbx5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_0yrpl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vvsf3\"]\natlas = ExtResource(\"1_0yrpl\")\nregion = Rect2(552, 576, 203, 177)\n\n[node name=\"greyfang_1\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_vvsf3\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/gryphon_rider_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0pnfa6qkk4d0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_sa8kl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ignd6\"]\natlas = ExtResource(\"1_sa8kl\")\nregion = Rect2(815, 33, 201, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_ignd6\")\noffset = Vector2(20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/hall_of_souls_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dabhhcbahghqb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_vfksp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_vfksp\")\nregion = Rect2(528, 547, 225, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/hall_of_souls_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dehbfvvluejvm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_uj3sx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_uj3sx\")\nregion = Rect2(528, 547, 225, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/hall_of_souls_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0ymxclmnfi6m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_m15av\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_m15av\")\nregion = Rect2(780, 532, 237, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nposition = Vector2(10, -60)\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\n"
  },
  {
    "path": "src/towers/tower_sprites/harby_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://csjfbhj4ffhie\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_hmtrh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_tmxfd\"]\natlas = ExtResource(\"1_hmtrh\")\nregion = Rect2(284, 273, 200, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_tmxfd\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/harpy_witch_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cih1ygdxswk6s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_0uc7n\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0uc7n\")\nregion = Rect2(323, 25, 159, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/harpy_witch_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c6akigisipcgx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_rkft8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rkft8\")\nregion = Rect2(323, 25, 159, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.86, 0.86)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/haunted_rubble_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cyhd16ex5pp20\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_akmr4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_akmr4\")\nregion = Rect2(813, 71, 151, 166)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/haunted_rubble_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://djxr7rtkntdod\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_46xsx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_46xsx\")\nregion = Rect2(813, 71, 151, 166)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/haunted_rubble_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://crdnj1wf6e548\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_vxjqk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_vxjqk\")\nregion = Rect2(39, 275, 196, 230)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/haunted_rubble_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c7o1vhxbnjmsn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_vdwxa\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_vdwxa\")\nregion = Rect2(39, 275, 196, 230)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/haunted_rubble_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dasqkwtgpi30f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_dfsk2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_dfsk2\")\nregion = Rect2(269, 273, 203, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/healing_obelisk_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b0w8tgtlqlhyv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_2sfuq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2sfuq\")\nregion = Rect2(329, 1039, 130, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/healing_obelisk_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://lfpb342u0kks\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_vpbcx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vpbcx\")\nregion = Rect2(329, 1039, 130, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/healing_obelisk_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://g1i3qvkcxscy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_jbxpd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jbxpd\")\nregion = Rect2(550, 1040, 198, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/healing_obelisk_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8yj6hf2wswgo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_d3thk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_d3thk\")\nregion = Rect2(550, 1040, 198, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/helicopter_zone_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://soq2prqadk4l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_kaxf4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5ravj\"]\natlas = ExtResource(\"1_kaxf4\")\nregion = Rect2(28, 572, 195, 154)\n\n[node name=\"helicopter_zone\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_5ravj\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/hell_bat_1.tscn",
    "content": "[gd_scene format=3 uid=\"uid://de843yrbkpf7x\"]\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\n"
  },
  {
    "path": "src/towers/tower_sprites/hell_bat_2.tscn",
    "content": "[gd_scene format=3 uid=\"uid://du0wprvwquce4\"]\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\n"
  },
  {
    "path": "src/towers/tower_sprites/hell_bat_3.tscn",
    "content": "[gd_scene format=3 uid=\"uid://bb8a7l12lrqbg\"]\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\n"
  },
  {
    "path": "src/towers/tower_sprites/holy_energy_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c755jb2ip70ok\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_wd5mo\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_wd5mo\")\nregion = Rect2(295, 280, 183, 199)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/ice_battery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bdnt4q070oqlh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_spgdl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_spgdl\")\nregion = Rect2(298, 552, 176, 177)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/ice_battery_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7jf5oxeiqc25\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_v4u68\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_v4u68\")\nregion = Rect2(298, 552, 176, 177)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/ice_battery_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://teh115tnnn5b\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_knuc5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_knuc5\")\nregion = Rect2(551, 541, 192, 199)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_core_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bo6d1i8nmo1od\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_ictxf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ictxf\")\nregion = Rect2(796, 526, 206, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(3, -67)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_core_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cwgimypoanp1n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_0orrm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0orrm\")\nregion = Rect2(796, 526, 206, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(3, -67)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_skulls_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfe0qy7nfmr8t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_5i367\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_5i367\")\nregion = Rect2(811, 50, 172, 175)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_skulls_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://e375bxp5ktam\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_24fwq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_24fwq\")\nregion = Rect2(811, 50, 172, 175)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_skulls_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cw83hdc8qvgfo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_7r2vu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_7r2vu\")\nregion = Rect2(28, 280, 191, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_skulls_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctjam7ai1u7y7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_6qg4a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_6qg4a\")\nregion = Rect2(28, 280, 191, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -65)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_spirit_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b4rges5u35v1a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_h20rj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_h20rj\")\nregion = Rect2(803, 271, 168, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_spirit_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dl61sjdqfxndx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_8qi50\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8qi50\")\nregion = Rect2(803, 271, 168, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/icy_spirit_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cg2sxwf3onlxw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_uh2iw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_uh2iw\")\nregion = Rect2(44, 527, 208, 226)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/igloo_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c51dkylypt10i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_38lxj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_38lxj\")\nregion = Rect2(24, 40, 216, 185)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-7, -35)\n"
  },
  {
    "path": "src/towers/tower_sprites/igloo_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dcar8rax2uf57\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_5ur2j\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_5ur2j\")\nregion = Rect2(24, 40, 216, 185)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-7, -35)\n"
  },
  {
    "path": "src/towers/tower_sprites/igloo_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c78lftrv2grku\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_v1koy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_v1koy\")\nregion = Rect2(265, 18, 226, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-7, -35)\n"
  },
  {
    "path": "src/towers/tower_sprites/inexperienced_huntress_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://devnhvbolj2f6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_ckj2j\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_ckj2j\")\nregion = Rect2(531, 26, 216, 201)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/inexperienced_huntress_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dse1y2kajabhb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_bs0me\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_bs0me\")\nregion = Rect2(531, 26, 216, 201)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/inexperienced_huntress_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://u2vv2bg5jbc2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_3lfkb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_3lfkb\")\nregion = Rect2(817, 26, 155, 208)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/inflamed_stone_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bn3g0yskrumnw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_p007y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_p007y\")\nregion = Rect2(38, 266, 185, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/inflamed_stone_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dpvj6s5jvow81\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_xktem\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_xktem\")\nregion = Rect2(38, 266, 185, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/inflamed_stone_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b11j661qsrcv8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_a6ifd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_a6ifd\")\nregion = Rect2(294, 283, 192, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/initiate_elementalist_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://xu70jn6dehwi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_q0ie6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_q0ie6\")\nregion = Rect2(42, 294, 171, 198)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/initiate_elementalist_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://u2cehdydjstd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_fgsuq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_fgsuq\")\nregion = Rect2(42, 294, 171, 198)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/initiate_elementalist_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c612q51osdro0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_qi4x8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_qi4x8\")\nregion = Rect2(283, 283, 200, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/initiate_elementalist_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://djrisxcq2ofid\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_bwud4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_bwud4\")\nregion = Rect2(283, 283, 200, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/it_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://s7oqpufbnph4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_dcvsv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_h55gq\"]\natlas = ExtResource(\"1_dcvsv\")\nregion = Rect2(540, 14, 218, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_h55gq\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/jungle_stalker_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://daiou3r8xe8xy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_3o4le\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_3o4le\")\nregion = Rect2(285, 533, 207, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/jungle_stalker_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dux7ta5e7um8a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_edefq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_edefq\")\nregion = Rect2(285, 533, 207, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/jungle_stalker_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b4hhq8mpglcco\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_aqf02\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_aqf02\")\nregion = Rect2(534, 527, 203, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/kraken_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cwjmredxije14\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_a56ob\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0eji7\"]\natlas = ExtResource(\"1_a56ob\")\nregion = Rect2(519, 532, 246, 223)\n\n[node name=\"Kraken\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_0eji7\")\noffset = Vector2(-5, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_astral_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ddn2svn8aciko\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_bnopx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_bnopx\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_astral_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c8c4elajjbqvu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_twypl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_twypl\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_astral_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://qq1wt6kadra\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_sy55m\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_sy55m\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_astral_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://uilnytj0xfjt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_uj68o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_uj68o\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_astral_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bpypcy7b1fgnd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_tl75t\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_tl75t\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_dark_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bg8mmlmrug2xp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_m0xas\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_m0xas\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_dark_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://chrlto3cvup52\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_81kd8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ujwyh\"]\natlas = ExtResource(\"1_81kd8\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ujwyh\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_dark_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://t0lohbtss8sq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_okp08\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_okp08\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_dark_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d10tlfqm1xuhe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_eumdu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_eumdu\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_dark_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://sapk74mwsun1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_ja7qw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ja7qw\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_elemental_ghost_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dvlewwc3gkwym\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_7fxu7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7fxu7\")\nregion = Rect2(301, 283, 137, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_elemental_ghost_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dg4tum4xri5le\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_w7oyp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_w7oyp\")\nregion = Rect2(301, 283, 137, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_elemental_ghost_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://5b7xkakimbkh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_c14xc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_c14xc\")\nregion = Rect2(554, 274, 162, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_elemental_ghost_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbt4l8nhmtojt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_jh2ni\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jh2ni\")\nregion = Rect2(554, 274, 162, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_elemental_ghost_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://de04n66pug6qk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_2a87a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2a87a\")\nregion = Rect2(795, 290, 199, 199)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-40, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_flamy_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3ps3xq7avbs2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_kmomd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_kmomd\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_flamy_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cm1nxaj2wlrwq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_geqci\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ujwyh\"]\natlas = ExtResource(\"1_geqci\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ujwyh\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_flamy_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7w07fyy4iphw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_l45nj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_l45nj\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_flamy_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dct2nt77o2r64\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_8xsc1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_8xsc1\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_flamy_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://6mrd7102syik\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_ainu8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ainu8\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_ice_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://de7nfgpx8klmn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_r6vri\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_r6vri\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_ice_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://extxxikwd46o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_hvlpp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ujwyh\"]\natlas = ExtResource(\"1_hvlpp\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ujwyh\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_ice_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cgjque08le1k6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_qg4xj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_qg4xj\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_ice_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bm7gmj0ag3b4g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_k6iyv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_k6iyv\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_ice_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://davwtwsvuc7nd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_2dbfr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_2dbfr\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_iron_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dmpcaanl5dwjn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_nspmj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_nspmj\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_iron_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c33yqdrbqg6c4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_8ac37\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ujwyh\"]\natlas = ExtResource(\"1_8ac37\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ujwyh\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_iron_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ct0vlwf28ikfb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_ukt5a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ukt5a\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_iron_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://h2mr85boefub\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_qy351\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_qy351\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_iron_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvibhsmggksba\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_y0wks\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_y0wks\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_natural_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bqp3gfftpc5qa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_7c2rb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_7c2rb\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_natural_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://j3jg7fqixqyn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_rrvs4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ujwyh\"]\natlas = ExtResource(\"1_rrvs4\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ujwyh\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_natural_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://3a6lt31cwq36\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_du42u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_du42u\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_natural_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cy8077ac2kxh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_5r2w1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5r2w1\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_natural_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d2jolv11afwmi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_23lys\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_23lys\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_priest_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bf77iugacuce8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_elf5q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_elf5q\")\nregion = Rect2(818, 1041, 112, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_priest_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dxackthshmss2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_oiwam\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_oiwam\")\nregion = Rect2(818, 1041, 112, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_priest_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://02m0y2qr8xvl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_lnejb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_lnejb\")\nregion = Rect2(66, 1296, 154, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_priest_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://wr4la4dq8von\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_pdydq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_pdydq\")\nregion = Rect2(66, 1296, 154, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_priest_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cgjo6uk2rhd57\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_w0skq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_w0skq\")\nregion = Rect2(280, 1295, 174, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_skeletal_mage_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c2uml0ey511jj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_1d773\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_1d773\")\nregion = Rect2(35, 1063, 170, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_skeletal_mage_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dm76fg6iuhx70\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_i2ibe\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_i2ibe\")\nregion = Rect2(35, 1063, 170, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_skeletal_mage_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d2nlveincij65\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_r8nxy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_r8nxy\")\nregion = Rect2(269, 1054, 218, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-35, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_skeletal_mage_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cb3af43w6l2f1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_hocu1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hocu1\")\nregion = Rect2(269, 1054, 218, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-35, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_storm_defender_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cyqnrbcnn35ce\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_3m4ol\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_3m4ol\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_storm_defender_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://nt0hxpiv37os\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_7mxgo\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ujwyh\"]\natlas = ExtResource(\"1_7mxgo\")\nregion = Rect2(833, 815, 140, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ujwyh\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_storm_defender_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ckds7nxkpkxhh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_2b7tr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_2b7tr\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_storm_defender_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3d1x3lhjiyvl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_u5wvv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_u5wvv\")\nregion = Rect2(64, 1053, 125, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_storm_defender_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjq6232hli0h8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_an57q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_an57q\")\nregion = Rect2(305, 1053, 147, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_wolves_den_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://540ls6l6ytw4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_ycnus\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_ycnus\")\nregion = Rect2(566, 280, 165, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_wolves_den_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://denwd477jhiwv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_2wtjk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_2wtjk\")\nregion = Rect2(566, 280, 165, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lesser_wolves_den_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://su8kmhkvcsp4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_gredw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_gredw\")\nregion = Rect2(800, 272, 173, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -75)\n"
  },
  {
    "path": "src/towers/tower_sprites/library_of_alexandria_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bfe8rusund3ow\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_di3vh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2761b\"]\natlas = ExtResource(\"1_di3vh\")\nregion = Rect2(20, 548, 231, 184)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_2761b\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lich_king_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8bf5fdq4hd20\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_7soo3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_4hliw\"]\natlas = ExtResource(\"1_7soo3\")\nregion = Rect2(47, 525, 165, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_4hliw\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_eye_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cirxcwhdqledj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_wb782\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_utrfi\"]\natlas = ExtResource(\"1_wb782\")\nregion = Rect2(41, 302, 187, 169)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_utrfi\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_generator_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cksgqo2bldvww\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_cbvut\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_cbvut\")\nregion = Rect2(563, 811, 170, 170)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_generator_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cmj54h0s1q6l6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_8nqml\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8nqml\")\nregion = Rect2(563, 811, 170, 170)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_generator_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bdhurmvodj6v6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_rqnjn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rqnjn\")\nregion = Rect2(807, 795, 179, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_generator_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjk335idsj2tr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_h1gny\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_h1gny\")\nregion = Rect2(807, 795, 179, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_totem_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://md7s7ywe8uh6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_iero2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_iero2\")\nregion = Rect2(25, 784, 201, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_totem_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctj21qijskf4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_1p1ld\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_1p1ld\")\nregion = Rect2(25, 784, 201, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lightning_totem_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://hhi2kosu0y5d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_qny6o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_qny6o\")\nregion = Rect2(290, 770, 204, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/little_phoenix_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cibu8gl2oqe3g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_byllg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_byllg\")\nregion = Rect2(34, 25, 217, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/little_phoenix_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d14vre1vlwkgd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_mt5eu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_mt5eu\")\nregion = Rect2(34, 25, 217, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/little_phoenix_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bmwecv041d06e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_g3hsu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_g3hsu\")\nregion = Rect2(275, 21, 227, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/living_volcano_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://v2ag2q1wd0qg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_2wrln\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ny6fu\"]\natlas = ExtResource(\"1_2wrln\")\nregion = Rect2(803, 291, 196, 201)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_ny6fu\")\noffset = Vector2(-10, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lunar_emitter_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://j8lh61po4hfi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_xkckl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_xkckl\")\nregion = Rect2(71, 282, 131, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lunar_emitter_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ca18rm5lrc0aa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_1fogk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_1fogk\")\nregion = Rect2(71, 282, 131, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/lunar_sentinel_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3wam4ih3r46a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_0gaag\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0gaag\")\nregion = Rect2(35, 44, 178, 164)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lunar_sentinel_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0jusqwegj30r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_bmk16\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_bmk16\")\nregion = Rect2(35, 44, 178, 164)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lunar_sentinel_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1hioy3nl2hx4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_mc2iy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_mc2iy\")\nregion = Rect2(282, 33, 216, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/lunar_sentinel_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ba3a3lwmtwrn4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_l52n2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_l52n2\")\nregion = Rect2(282, 33, 216, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/magic_battery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dkplf3gbpw5du\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_6ecyd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6ecyd\")\nregion = Rect2(566, 318, 150, 148)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/magic_battery_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctanmy8mosw3a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_etcwk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_etcwk\")\nregion = Rect2(566, 318, 150, 148)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/magic_battery_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bpgkpakavfoyg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_2x02e\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2x02e\")\nregion = Rect2(812, 298, 184, 172)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/magic_mushroom_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://3eoktm7g5xut\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_uthhj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yx1qg\"]\natlas = ExtResource(\"1_uthhj\")\nregion = Rect2(291, 276, 186, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_yx1qg\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/magna_warrior_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjv70mkt1h0w3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_1veq4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_1veq4\")\nregion = Rect2(545, 299, 191, 176)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/magna_warrior_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bx0fsv6657hb0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_ego5e\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ego5e\")\nregion = Rect2(545, 299, 191, 176)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/magna_warrior_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://w6swj6pinfsb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_iool8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_iool8\")\nregion = Rect2(782, 266, 226, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/magna_warrior_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://x7mlde8jn8pi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_u3t0u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_u3t0u\")\nregion = Rect2(782, 266, 226, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/magna_warrior_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://mtt6ynfplljc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_pkxfh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_pkxfh\")\nregion = Rect2(8, 544, 238, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -45)\n"
  },
  {
    "path": "src/towers/tower_sprites/mana-touched_drake_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://lw67ldfmlusw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_qgsow\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_avq1f\"]\natlas = ExtResource(\"1_qgsow\")\nregion = Rect2(39, 25, 212, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_avq1f\")\noffset = Vector2(15, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/mana-touched_drake_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://beqh28fhs35pm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_fkvnd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_fkvnd\")\nregion = Rect2(39, 25, 212, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(15, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/mana-touched_drake_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d33tshjd1t4ok\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_5umua\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_5umua\")\nregion = Rect2(285, 9, 205, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(15, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/mana-touched_drake_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bhusuajn541kc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_qpv6n\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_qpv6n\")\nregion = Rect2(285, 9, 205, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(15, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/marine_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bhb1gxdxuty8x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_kc5w5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_kc5w5\")\nregion = Rect2(32, 278, 192, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/marine_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbqxxcff0a8fd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_gy2un\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_gy2un\")\nregion = Rect2(32, 278, 192, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/meteor_totem_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctximbkrkpefh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_rysbh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_mycre\"]\natlas = ExtResource(\"1_rysbh\")\nregion = Rect2(555, 527, 179, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_mycre\")\noffset = Vector2(10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/militia_watchtower_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbp6i8va2b353\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_6tujt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6tujt\")\nregion = Rect2(830, 522, 128, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/militia_watchtower_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://n8r0gujp1ug1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_05446\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_05446\")\nregion = Rect2(830, 522, 128, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/militia_watchtower_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7xktynlbna6w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_0rq0t\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0rq0t\")\nregion = Rect2(55, 775, 159, 241)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/militia_watchtower_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://liv0ipebcryt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_1rh20\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_1rh20\")\nregion = Rect2(55, 775, 159, 241)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/miner_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://3f2rmuw1in0o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_p7i33\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_p7i33\")\nregion = Rect2(297, 538, 169, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/miner_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dwaqq7pb63occ\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_38t7a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_38t7a\")\nregion = Rect2(297, 538, 169, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/miner_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://chv3alc5dg28c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_6qmsu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6qmsu\")\nregion = Rect2(540, 532, 205, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/minor_magic_ruin_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cu6hbedtmvwhf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_pepco\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_pepco\")\nregion = Rect2(54, 24, 143, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/minor_magic_ruin_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvdjdpnbc27h4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_keijk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_keijk\")\nregion = Rect2(54, 24, 143, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/minor_magic_ruin_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b76g0ioi5lhpo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_gcjeh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_gcjeh\")\nregion = Rect2(311, 15, 152, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/minor_magic_ruin_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3oa7aa7rl1og\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_pcwrn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_pcwrn\")\nregion = Rect2(311, 15, 152, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/minor_magic_ruin_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://df81ub7c7wvjf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_5vckx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5vckx\")\nregion = Rect2(546, 15, 190, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/minor_magic_ruin_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://1ilvnb8d2nd0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_p40v6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_p40v6\")\nregion = Rect2(546, 15, 190, 225)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/mister_fireflies_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://rygkuu0blr7y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_qh6gu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7f35u\"]\natlas = ExtResource(\"1_qh6gu\")\nregion = Rect2(17, 805, 207, 206)\n\n[node name=\"mister_fireflies_1\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_7f35u\")\noffset = Vector2(-15, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/mister_fireflies_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bp24yi6xeqovd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_2os7k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7f35u\"]\natlas = ExtResource(\"1_2os7k\")\nregion = Rect2(17, 805, 207, 206)\n\n[node name=\"mister_fireflies_2\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_7f35u\")\noffset = Vector2(-15, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/mister_fireflies_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8mqmqee6s3h8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_c7b7c\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_xs15a\"]\natlas = ExtResource(\"1_c7b7c\")\nregion = Rect2(17, 805, 207, 206)\n\n[node name=\"mister_fireflies_3\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_xs15a\")\noffset = Vector2(-15, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/monolith_of_chaos_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://celgsu1wcgqqc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_vyyfw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_n41d6\"]\natlas = ExtResource(\"1_vyyfw\")\nregion = Rect2(45, 20, 201, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_n41d6\")\noffset = Vector2(15, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/morphling_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctel28ratkutm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_y5v13\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fviqq\"]\natlas = ExtResource(\"1_y5v13\")\nregion = Rect2(19, 299, 220, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_fviqq\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/mossy_acid_sprayer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cu3fiuf85yhnq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_l448i\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_l448i\")\nregion = Rect2(831, 78, 119, 130)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/mossy_acid_sprayer_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ukvlrbrke4no\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_wuy8y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_wuy8y\")\nregion = Rect2(831, 78, 119, 130)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/mossy_acid_sprayer_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cgyavpxpvv344\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_c5qjx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_c5qjx\")\nregion = Rect2(40, 287, 173, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/mossy_acid_sprayer_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bcnqw5rpwxhvl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_4skfv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_4skfv\")\nregion = Rect2(40, 287, 173, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/mossy_acid_sprayer_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://brubdwhjfrnct\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_5grpo\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5grpo\")\nregion = Rect2(320, 280, 143, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/mud_golem_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://chjgadsu4gtpj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_ja14r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d1cuk\"]\natlas = ExtResource(\"1_ja14r\")\nregion = Rect2(42, 27, 182, 226)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_d1cuk\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/nature_sprites_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfb7esffdpvjm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_88fn4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_88fn4\")\nregion = Rect2(277, 550, 215, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/nature_sprites_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c8mn8a5oekb4o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_xtibm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xtibm\")\nregion = Rect2(277, 550, 215, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/nature_sprites_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bwymmc2mhhli1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_n5w7s\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_n5w7s\")\nregion = Rect2(561, 533, 166, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(15, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/necromantic_altar_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://vd804yty1cgf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_4okea\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_4okea\")\nregion = Rect2(39, 41, 187, 182)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/necromantic_altar_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfjufgtbplyvu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_0321u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0321u\")\nregion = Rect2(39, 41, 187, 182)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/necromantic_altar_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://tpqn5ddjcsgw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_wy81r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_wy81r\")\nregion = Rect2(288, 15, 173, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/necromantic_altar_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dagbw6wvo7nwh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_vel8n\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vel8n\")\nregion = Rect2(288, 15, 173, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/nortrom_the_silencer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ct8yebhuh1i2k\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_e28tl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_nqo7n\"]\natlas = ExtResource(\"1_e28tl\")\nregion = Rect2(839, 23, 138, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_nqo7n\")\noffset = Vector2(10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/nuclear_missile_launcher_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0tutvvm3tykn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_e8a1f\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qwshi\"]\natlas = ExtResource(\"1_e8a1f\")\nregion = Rect2(835, 525, 152, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(1.2, 1.2)\ntexture = SubResource(\"AtlasTexture_qwshi\")\noffset = Vector2(5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/obelisk_of_fortuity_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://duy81togpip0s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_o01eu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_o01eu\")\nregion = Rect2(595, 287, 108, 189)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/obelisk_of_fortuity_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dcekia5xuyjer\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_u21pm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_u21pm\")\nregion = Rect2(595, 287, 108, 189)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/obelisk_of_fortuity_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://blhpt85e4qquc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_d7s6q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_d7s6q\")\nregion = Rect2(818, 272, 138, 209)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/obelisk_of_fortuity_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dnegqgk7ctv3m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_tseqt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_tseqt\")\nregion = Rect2(818, 272, 138, 209)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/obelisk_of_fortuity_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bo05djddy4d8s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_hnf1y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_hnf1y\")\nregion = Rect2(76, 530, 132, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/owl_of_wisdom_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://iebbinbu13ak\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_oxfws\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fb4y6\"]\natlas = ExtResource(\"1_oxfws\")\nregion = Rect2(524, 288, 221, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_fb4y6\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/owl_of_wisdom_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c6hbdl0stb5ex\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_bweq4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6gbi5\"]\natlas = ExtResource(\"1_bweq4\")\nregion = Rect2(524, 288, 221, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_6gbi5\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/particle_accelerator_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c2ghtpfa2ftob\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_k23qt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_k23qt\")\nregion = Rect2(554, 271, 167, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/particle_accelerator_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cb3dt2r1vkoow\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_6gwsb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_6gwsb\")\nregion = Rect2(554, 271, 167, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/particle_accelerator_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://by5sdmjw51d8d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_d6jg6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_d6jg6\")\nregion = Rect2(808, 269, 164, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/phantom_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://diptdwme0qnu5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_fd30r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_fd30r\")\nregion = Rect2(81, 53, 109, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/phantom_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3o7ia2sradq3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_75586\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_75586\")\nregion = Rect2(81, 53, 109, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/phantom_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dj8ekcmm5yxb2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_mwxpg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_mwxpg\")\nregion = Rect2(296, 25, 168, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/phantom_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d2bqiftwpn4rg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_xbrk6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xbrk6\")\nregion = Rect2(296, 25, 168, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/phantom_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://durmdxvobu142\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_kvs36\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lndfb\"]\natlas = ExtResource(\"1_kvs36\")\nregion = Rect2(555, 29, 170, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lndfb\")\noffset = Vector2(-10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/plagued_crypt_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ea10r60784fj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_8j8x4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qfyr0\"]\natlas = ExtResource(\"1_8j8x4\")\nregion = Rect2(272, 782, 226, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_qfyr0\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/planar_gate_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://1om1t21b0x0x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_n6bfg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_13n4m\"]\natlas = ExtResource(\"1_n6bfg\")\nregion = Rect2(285, 541, 211, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_13n4m\")\noffset = Vector2(10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/poison_battery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://6rkrbm5adq5v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_ylnvm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_ylnvm\")\nregion = Rect2(41, 295, 176, 179)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/poison_battery_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjlp8bhvuu8xd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_vbkxf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_vbkxf\")\nregion = Rect2(41, 295, 176, 179)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/poison_battery_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0ufcusntal4y\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_uy21w\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_uy21w\")\nregion = Rect2(271, 277, 240, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/polar_bear_cub_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dgsng3a07rh2f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_niom2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_niom2\")\nregion = Rect2(299, 807, 163, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/polar_bear_cub_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bcwhwwwukont1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_a1g6v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_a1g6v\")\nregion = Rect2(299, 807, 163, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/polar_bear_cub_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bttsutgajsjdj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_80lu0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_80lu0\")\nregion = Rect2(529, 780, 209, 241)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/portal_to_swine_purgatory_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dxwxgok08npty\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_b1w7i\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_btv8m\"]\natlas = ExtResource(\"1_b1w7i\")\nregion = Rect2(577, 307, 125, 153)\n\n[node name=\"portal_to_swine_purgatory_1\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_btv8m\")\noffset = Vector2(-10, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/portal_to_swine_purgatory_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d3iiv0urhfoac\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_5s4q7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_btv8m\"]\natlas = ExtResource(\"1_5s4q7\")\nregion = Rect2(577, 307, 125, 153)\n\n[node name=\"portal_to_swine_purgatory_2\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_btv8m\")\noffset = Vector2(-10, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/portal_to_swine_purgatory_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bscmhkihrsuv4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_p3tqp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_btv8m\"]\natlas = ExtResource(\"1_p3tqp\")\nregion = Rect2(799, 310, 177, 173)\n\n[node name=\"portal_to_swine_purgatory_3\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_btv8m\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/prince_of_lightning_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cgs44jihq2aeq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_4w6m7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_c4f7i\"]\natlas = ExtResource(\"1_4w6m7\")\nregion = Rect2(779, 525, 213, 236)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_c4f7i\")\noffset = Vector2(-25, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/prince_of_lightning_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bguwayqb0bksu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_bmm64\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_gqdnd\"]\natlas = ExtResource(\"1_bmm64\")\nregion = Rect2(779, 525, 213, 236)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_gqdnd\")\noffset = Vector2(-25, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/princess_of_light_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://mvdvkyj2e6xp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_2vr1k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ucupt\"]\natlas = ExtResource(\"1_2vr1k\")\nregion = Rect2(38, 540, 196, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_ucupt\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/princess_of_light_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8cpw21mikdhq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_7ne3p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7ne3p\")\nregion = Rect2(38, 540, 196, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/razorboar_thornweaver_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bkb2kdf71b6w5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_k4lj5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_k4lj5\")\nregion = Rect2(43, 42, 185, 171)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/razorboar_thornweaver_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0t0oeglyuvvf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_rpfs5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_rpfs5\")\nregion = Rect2(43, 42, 185, 171)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/razorboar_thornweaver_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://brv2rer7nymqb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_sf4au\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_sf4au\")\nregion = Rect2(276, 29, 223, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/red_ball_lightning_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bl06osb7juw3i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_0giwq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_0giwq\")\nregion = Rect2(46, 283, 161, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/red_ball_lightning_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbd75dpp3xhbr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_ct1rg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_ct1rg\")\nregion = Rect2(46, 283, 161, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/regenerating_well_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dvg6g4q4k1cko\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_jbesv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_jbesv\")\nregion = Rect2(807, 542, 176, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/regenerating_well_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dbtkh6bqwr34n\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_p4s0y\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_p4s0y\")\nregion = Rect2(807, 542, 176, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/regenerating_well_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://lohfwc2hrgt7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c2ipgujbe63mi\" path=\"res://assets/tower_sprites/nature_rare.png\" id=\"1_rr46e\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_rr46e\")\nregion = Rect2(31, 804, 195, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rooted_chasm_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://38xjks7oni5x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_v61uf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_v61uf\")\nregion = Rect2(277, 804, 200, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/rooted_chasm_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://tolcl3acmh4h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_vr352\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vr352\")\nregion = Rect2(277, 804, 200, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/rooted_chasm_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://jl0rkln7f5tj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_mqbas\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_mqbas\")\nregion = Rect2(540, 793, 191, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rooted_chasm_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cvmokl52sftnb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_ceaek\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ceaek\")\nregion = Rect2(540, 793, 191, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rotted_flashing_grave_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ivbmal1at731\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_louij\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_louij\")\nregion = Rect2(329, 565, 124, 172)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rotted_flashing_grave_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://byla8suqtet7p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_t65lc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_t65lc\")\nregion = Rect2(329, 565, 124, 172)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rotted_flashing_grave_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfpb2aiehpwu3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_y6uvy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_y6uvy\")\nregion = Rect2(567, 543, 158, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rotted_flashing_grave_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dl038bjj8n4js\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_gq81o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_gq81o\")\nregion = Rect2(567, 543, 158, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rotted_flashing_grave_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://be3l35r3rjpwe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_4ei3b\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_4ei3b\")\nregion = Rect2(814, 535, 156, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rotted_flashing_grave_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b4ttti8rb18c3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_h3sui\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_h3sui\")\nregion = Rect2(814, 535, 156, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rowing_boat_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://f4a7oyi0ohbd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_jh421\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jh421\")\nregion = Rect2(303, 809, 168, 163)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/rowing_boat_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://biskfe1yrfn1q\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_0lsxv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0lsxv\")\nregion = Rect2(303, 809, 168, 163)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/rowing_boat_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://suglbxsy70sy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_31ya1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_31ya1\")\nregion = Rect2(518, 812, 232, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rowing_boat_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b72tf2njp6dle\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_86tl3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_86tl3\")\nregion = Rect2(518, 812, 232, 187)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_monolith_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c4c63xex7y3vn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_v84tf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_v84tf\")\nregion = Rect2(585, 324, 133, 136)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_monolith_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bmayduml5cj1u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_4mkhq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_4mkhq\")\nregion = Rect2(585, 324, 133, 136)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_monolith_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://mo10wqdahxnx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_50myq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_50myq\")\nregion = Rect2(817, 300, 171, 194)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_monolith_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ddjrym82ctc1l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_gsdot\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_gsdot\")\nregion = Rect2(817, 300, 171, 194)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_monolith_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://70s7vokupimq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_utti1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_utti1\")\nregion = Rect2(45, 542, 178, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_monolith_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cv1xb6eo40kld\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_d7w85\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_d7w85\")\nregion = Rect2(45, 542, 178, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_storm_cap_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbo74x3cqbla4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_3bcc2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_3bcc2\")\nregion = Rect2(811, 42, 161, 177)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_storm_cap_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dxshh0c5rn7u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_nwhk0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_nwhk0\")\nregion = Rect2(811, 42, 161, 177)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_storm_cap_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dya34ilqqv3v2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_byad3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_byad3\")\nregion = Rect2(35, 274, 206, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_storm_cap_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dcjf6hjg5q50f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_cy46k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_cy46k\")\nregion = Rect2(35, 274, 206, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_storm_cap_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://k4f45jxsj4dc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_0kkwi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_0kkwi\")\nregion = Rect2(298, 270, 177, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_storm_cap_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0ub2prcijibm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dbjvvdlpstmju\" path=\"res://assets/tower_sprites/storm_common.png\" id=\"1_ulubs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_ulubs\")\nregion = Rect2(298, 270, 177, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b1ssw3mx2n8rx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_fyyf2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_fyyf2\")\nregion = Rect2(303, 300, 149, 176)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://chltkju3nqs6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_kgagu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_kgagu\")\nregion = Rect2(303, 300, 149, 176)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cqfddk6st18ik\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_rq65r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_rq65r\")\nregion = Rect2(536, 283, 175, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjoemb3cx0vqs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_0o5tk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_0o5tk\")\nregion = Rect2(536, 283, 175, 196)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b1eony62ni5l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_vqgf6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_vqgf6\")\nregion = Rect2(805, 280, 192, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ua7w5clkfwin\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_agoyy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_agoyy\")\nregion = Rect2(805, 280, 192, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_sun_pedestal_7.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cia40diw0toth\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dv1stv65yi6ch\" path=\"res://assets/tower_sprites/astral_common.png\" id=\"1_qbye4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"1\"]\natlas = ExtResource(\"1_qbye4\")\nregion = Rect2(53, 532, 157, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_wind_tower_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d2rf4n2bmvein\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_qciap\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_qciap\")\nregion = Rect2(822, 68, 152, 146)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_wind_tower_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvvhc4dg1jxcf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_p3jij\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_p3jij\")\nregion = Rect2(822, 68, 152, 146)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_wind_tower_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvubc27e1skfg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_41jq5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_41jq5\")\nregion = Rect2(34, 304, 195, 154)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/ruined_wind_tower_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bn2mmq643ha16\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_0jptg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0jptg\")\nregion = Rect2(34, 304, 195, 154)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/rundown_iron_sentry_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bo7jkxeq2ex0e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_rd41r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rd41r\")\nregion = Rect2(52, 32, 169, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rundown_iron_sentry_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bubt0srgj0jgq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_yx273\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_yx273\")\nregion = Rect2(52, 32, 169, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/rundown_iron_sentry_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cci885jklwkla\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_56lc3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_56lc3\")\nregion = Rect2(304, 34, 168, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/sacred_altar_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cetpjdi5w1261\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_e2l27\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_aupxo\"]\natlas = ExtResource(\"1_e2l27\")\nregion = Rect2(28, 549, 192, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_aupxo\")\noffset = Vector2(-10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/sacrificial_lamb_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://n4aj3ly8tutq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_ol12h\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_ol12h\")\nregion = Rect2(302, 269, 188, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(15, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/sacrificial_lamb_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bxo2mw5rk68ef\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_n5tgk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_n5tgk\")\nregion = Rect2(302, 269, 188, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(15, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/safirons_cold_grave_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bint4yvtgt31c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_et87a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_yix0u\"]\natlas = ExtResource(\"1_et87a\")\nregion = Rect2(814, 261, 174, 245)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_yix0u\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/scales_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjhgqiusg6jia\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_6keha\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_enh03\"]\natlas = ExtResource(\"1_6keha\")\nregion = Rect2(788, 287, 198, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_enh03\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/sea_turtle_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b22dywfjcfdew\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_f1ft3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_f1ft3\")\nregion = Rect2(19, 296, 223, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/sea_turtle_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctrmsve0j5qcn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_eb3ky\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_eb3ky\")\nregion = Rect2(19, 296, 223, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/sea_turtle_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://csnas8tcju5sj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_326yq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_326yq\")\nregion = Rect2(269, 291, 235, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/servant_of_the_twin_flames_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://siwf1n8vwgcr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_36cve\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ifxpq\"]\natlas = ExtResource(\"1_36cve\")\nregion = Rect2(832, 27, 130, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_ifxpq\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/servant_of_the_twin_flames_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://daoptyp5cmjvd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_vf7lp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_8mnk0\"]\natlas = ExtResource(\"1_vf7lp\")\nregion = Rect2(832, 27, 130, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_8mnk0\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/sewer_connection_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bqcgpjqbmh3jq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_y72e4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_y72e4\")\nregion = Rect2(822, 823, 151, 178)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/sewer_connection_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ceqruwb12uenq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_ccn8h\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ccn8h\")\nregion = Rect2(822, 823, 151, 178)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/sewer_connection_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bn206uofkee2d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_5egci\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_5egci\")\nregion = Rect2(19, 1074, 209, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/sewer_connection_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bwocc2eglpmuk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_t6n2j\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_t6n2j\")\nregion = Rect2(19, 1074, 209, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-5, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/shadow_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bj5rg16f51slt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_anwom\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1t8nb\"]\natlas = ExtResource(\"1_anwom\")\nregion = Rect2(19, 279, 231, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_1t8nb\")\noffset = Vector2(-10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/shaman_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b3x4sah8oms5u\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_qnt50\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_qnt50\")\nregion = Rect2(537, 517, 190, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/shaman_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://v6vx74ls0qp4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_g5v1k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_g5v1k\")\nregion = Rect2(537, 517, 190, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/shaman_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c5wi5uhseb40x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cylhbe3f41e1a\" path=\"res://assets/tower_sprites/fire_rare.png\" id=\"1_p4u7d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_p4u7d\")\nregion = Rect2(792, 527, 204, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/shard_of_souls_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ci5jtyec0oqsq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_dj0sh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_dj0sh\")\nregion = Rect2(821, 25, 156, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/shard_of_souls_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0dpst335c35\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_nsap7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_nsap7\")\nregion = Rect2(821, 25, 156, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/silver_knight_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bejlmv6ers4n8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_b6w0g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_b6w0g\")\nregion = Rect2(542, 16, 182, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/silver_knight_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cnodhqpe3u8vb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_dnm8a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_dnm8a\")\nregion = Rect2(542, 16, 182, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/skink_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dqio2l7h4dkte\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_hsk3h\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hsk3h\")\nregion = Rect2(541, 295, 196, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/skink_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://wit3lfs3r4qn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_bcnf7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_bcnf7\")\nregion = Rect2(541, 295, 196, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/skink_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c05cuv2gr3fm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_o3nsd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_o3nsd\")\nregion = Rect2(810, 305, 155, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/skink_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dk0iu43f1xd8v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_8n4ai\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8n4ai\")\nregion = Rect2(810, 305, 155, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/skink_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dhnay5ykgmv0x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bm1dfh8a2haq1\" path=\"res://assets/tower_sprites/nature_uncommon.png\" id=\"1_ebc65\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ebc65\")\nregion = Rect2(41, 578, 178, 174)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_brazier_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b00dk0106w5oy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_n0k51\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_n0k51\")\nregion = Rect2(79, 525, 115, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_brazier_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cafrlmjxe1xho\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_0wxsb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0wxsb\")\nregion = Rect2(79, 525, 115, 200)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_brazier_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dnhkpqoxebpab\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_r3mpc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_r3mpc\")\nregion = Rect2(318, 529, 150, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_brazier_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bxymq0swi4ap8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://d17ej65dobacn\" path=\"res://assets/tower_sprites/fire_uncommon.png\" id=\"1_8cbai\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8cbai\")\nregion = Rect2(318, 529, 150, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_bug_nest_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cqfnlxq4iv6lu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_karx4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_karx4\")\nregion = Rect2(563, 20, 158, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_bug_nest_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c8y1tdbtqfy88\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_upyvy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_upyvy\")\nregion = Rect2(563, 20, 158, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_bug_nest_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://j083moreb5q7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_s35xg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_s35xg\")\nregion = Rect2(805, 27, 168, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_bug_nest_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjao3w7rj74y7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_xk3mj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xk3mj\")\nregion = Rect2(805, 27, 168, 216)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_cactus_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://2kdg03t8n4o2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_idm2o\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_idm2o\")\nregion = Rect2(835, 46, 141, 168)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_cactus_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dwcicmjaqru4x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_cqtkx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_cqtkx\")\nregion = Rect2(835, 46, 141, 168)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_cactus_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b85h7sh3738c3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_o5w1k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_o5w1k\")\nregion = Rect2(31, 280, 186, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_cactus_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cj6jnqiwwft1p\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_ncmro\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ncmro\")\nregion = Rect2(31, 280, 186, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_cactus_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dtgyegdhr2e0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_f3omg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_f3omg\")\nregion = Rect2(289, 272, 217, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_cactus_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dpavuji5hgcg2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_xpqhy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_xpqhy\")\nregion = Rect2(289, 272, 217, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_fire_sprayer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dud7m7tg8ancq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_0qs78\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_0qs78\")\nregion = Rect2(66, 48, 152, 166)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_fire_sprayer_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dib4b6knq5s8w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_lkfqx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_lkfqx\")\nregion = Rect2(66, 48, 152, 166)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_fire_sprayer_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://004d21nfcvb7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_iyps2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_iyps2\")\nregion = Rect2(265, 16, 210, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(-10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_fire_sprayer_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7sx7af1qjfk3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_5h5je\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5h5je\")\nregion = Rect2(265, 16, 210, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(-10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_fire_sprayer_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://xgew82dof5bx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_tyyn1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_tyyn1\")\nregion = Rect2(555, 7, 190, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_fire_sprayer_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dsqv5px3trfvl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_k81ks\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_k81ks\")\nregion = Rect2(555, 7, 190, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frost_fire_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://jg1eby1nw507\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_2jysi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_2jysi\")\nregion = Rect2(58, 807, 145, 168)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frost_fire_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b2droh068plc7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_5y0nh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5y0nh\")\nregion = Rect2(58, 807, 145, 168)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frost_fire_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://q02n371koxnw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_f3jky\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_f3jky\")\nregion = Rect2(296, 794, 182, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frost_fire_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dc16stvli8n03\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_0mlfs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_0mlfs\")\nregion = Rect2(296, 794, 182, 213)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frost_fire_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cawi8ekbw8jjl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_u73my\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_u73my\")\nregion = Rect2(533, 787, 195, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(-5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frozen_mushroom_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bik5deg14thrt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_32noq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_32noq\")\nregion = Rect2(810, 545, 169, 184)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frozen_mushroom_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://eaw55yiov7aw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_b6fda\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_b6fda\")\nregion = Rect2(810, 545, 169, 184)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frozen_mushroom_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://brykoavqu1l36\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_gryly\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_gryly\")\nregion = Rect2(19, 784, 219, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frozen_mushroom_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bko87hqmpyrwj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_s3xfo\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_s3xfo\")\nregion = Rect2(19, 784, 219, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_frozen_mushroom_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjxcbfmnlfn5h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_fwxyq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_fwxyq\")\nregion = Rect2(266, 781, 239, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ice_mine_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b47d4c7w00p1f\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_pivcv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_pivcv\")\nregion = Rect2(50, 40, 168, 171)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ice_mine_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bq0sxxhl3ux80\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_aso4v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_aso4v\")\nregion = Rect2(50, 40, 168, 171)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ice_mine_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7yt34em3y6g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_gopfx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_gopfx\")\nregion = Rect2(302, 11, 178, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ice_mine_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjf3cel76ccum\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_uvvkd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_uvvkd\")\nregion = Rect2(302, 11, 178, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -55)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_light_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://djax68iy2w6u4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_eey0v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_eey0v\")\nregion = Rect2(580, 284, 132, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_light_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://4lun1cb30bms\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_f6j61\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_f6j61\")\nregion = Rect2(580, 284, 132, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_light_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://nqbvw0nfi2kg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_3y22m\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_3y22m\")\nregion = Rect2(816, 273, 158, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_light_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3t65vmb1cjk7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_wq37d\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_wq37d\")\nregion = Rect2(816, 273, 158, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_light_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://rwahrij8vqsg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_w6aor\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_w6aor\")\nregion = Rect2(39, 538, 179, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_pocket_rocket_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dnxx5nth646d2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_ed77f\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ed77f\")\nregion = Rect2(52, 801, 162, 181)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_pocket_rocket_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bbnle7bgxltq8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_3ycfr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_3ycfr\")\nregion = Rect2(52, 801, 162, 181)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_pocket_rocket_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bgkk3rxxnlruk\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_p1pyj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_p1pyj\")\nregion = Rect2(282, 781, 199, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_pocket_rocket_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dx0omauw5w4m5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_gv3oc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_gv3oc\")\nregion = Rect2(282, 781, 199, 233)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_pocket_rocket_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1d1diqsn8w7c\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_xv0ud\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_xv0ud\")\nregion = Rect2(547, 782, 186, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ray_blaster_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c1k2cdk13emhs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_3k4er\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_3k4er\")\nregion = Rect2(319, 288, 142, 171)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ray_blaster_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bc2j6ec71t25l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_ips6l\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ips6l\")\nregion = Rect2(319, 288, 142, 171)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(5, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ray_blaster_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bk0lvja2ra6b6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_xoyr5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xoyr5\")\nregion = Rect2(576, 272, 157, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ray_blaster_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dptc1bwnti3hg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_an0ul\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_an0ul\")\nregion = Rect2(576, 272, 157, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_ray_blaster_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://p47hf01rofg5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_i5to4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_i5to4\")\nregion = Rect2(805, 283, 181, 212)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_serpent_ward_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://2ogbjv62ddiw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_v4i3r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_v4i3r\")\nregion = Rect2(314, 549, 142, 192)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_serpent_ward_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b0ueyc8gihgkx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_rweua\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rweua\")\nregion = Rect2(314, 549, 142, 192)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_serpent_ward_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://v5yerf6c2vn2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_vx4xf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vx4xf\")\nregion = Rect2(537, 527, 202, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_serpent_ward_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1u3i61ckk4cw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_428as\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_428as\")\nregion = Rect2(537, 527, 202, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_torch_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cn1epm1d88gtb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_uqmp7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_uqmp7\")\nregion = Rect2(829, 30, 132, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_torch_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d4mibuuqdjjhi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_5ebsu\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_5ebsu\")\nregion = Rect2(829, 30, 132, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_torch_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dvf2k7lxok5q1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_dj167\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_dj167\")\nregion = Rect2(64, 275, 138, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_torch_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dft1i6genfsyc\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_nh4vo\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_nh4vo\")\nregion = Rect2(64, 275, 138, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/small_torch_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cujmtxi7diq3v\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://sd50h5ps6672\" path=\"res://assets/tower_sprites/fire_common.png\" id=\"1_8od3q\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_8od3q\")\nregion = Rect2(317, 284, 146, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/sniper_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b1xglbcfvvanh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_778k0\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_778k0\")\nregion = Rect2(278, 1063, 180, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/sniper_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c110eloy36vdx\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_yja3t\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_yja3t\")\nregion = Rect2(278, 1063, 180, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/sniper_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1mni55u6wfcg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_34m0c\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_34m0c\")\nregion = Rect2(528, 1045, 205, 210)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/sniper_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cqt0aha56nb5a\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_vkskw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vkskw\")\nregion = Rect2(786, 1052, 225, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/snowy_pebble_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7i6ui63bhnes\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_n5hsv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_n5hsv\")\nregion = Rect2(308, 312, 152, 148)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.55, 0.55)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/snowy_pebble_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bf6hhboh1heey\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_k2sgi\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_k2sgi\")\nregion = Rect2(308, 312, 152, 148)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/snowy_pebble_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cetrox1kgwmib\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_41ati\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_41ati\")\nregion = Rect2(536, 282, 196, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/snowy_pebble_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://054u1fvnh7oa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_380a1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_380a1\")\nregion = Rect2(536, 282, 196, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/snowy_pebble_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bnt3njabkshal\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_uot3x\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_uot3x\")\nregion = Rect2(781, 272, 215, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/snowy_pebble_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bmecvb0hxps83\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://w6nfohk2lg1s\" path=\"res://assets/tower_sprites/ice_common.png\" id=\"1_b6asg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_b6asg\")\nregion = Rect2(781, 272, 215, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/solar_collector_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dwknlto8pvkap\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_down6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_down6\")\nregion = Rect2(830, 8, 135, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/solar_collector_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://birsf3cu32nnf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://drd4dnffccck2\" path=\"res://assets/tower_sprites/iron_rare.png\" id=\"1_8ylgy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_8ylgy\")\nregion = Rect2(830, 8, 135, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.85, 0.85)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/solar_emitter_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://diu7yskrwpq3r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_2brom\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2brom\")\nregion = Rect2(571, 23, 130, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/solar_emitter_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dqs210qjxmr4e\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_y16ri\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_y16ri\")\nregion = Rect2(571, 23, 130, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/sorceress_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://f4l4mwdsu7e2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_weapl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2tibn\"]\natlas = ExtResource(\"1_weapl\")\nregion = Rect2(290, 278, 212, 222)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_2tibn\")\noffset = Vector2(15, -75)\n"
  },
  {
    "path": "src/towers/tower_sprites/soul_vault_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://gmsug4rt8x6l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_pge14\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_5rgfy\"]\natlas = ExtResource(\"1_pge14\")\nregion = Rect2(792, 534, 210, 220)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_5rgfy\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/soulflame_device_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dupikn0fjnmgq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_npqbc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u11wy\"]\natlas = ExtResource(\"1_npqbc\")\nregion = Rect2(283, 564, 197, 174)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_u11wy\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/spell_collector_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://grcmpq1qltuj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_jvohp\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jvohp\")\nregion = Rect2(50, 25, 162, 208)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/spell_collector_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://caqugqq122216\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_ey210\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ey210\")\nregion = Rect2(50, 25, 162, 208)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/spider_queen_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dydpvp7bibx8i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_ss0at\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hxid4\"]\natlas = ExtResource(\"1_ss0at\")\nregion = Rect2(9, 788, 236, 208)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_hxid4\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/star_gazer_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjjcfvc1j0gnw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_upfrc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_upfrc\")\nregion = Rect2(567, 35, 153, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/star_gazer_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dd27hut0diisr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_fmjto\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_fmjto\")\nregion = Rect2(567, 35, 153, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/star_gazer_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c3m6wj1ljxi6g\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_1my3p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_1my3p\")\nregion = Rect2(796, 23, 190, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/star_gazer_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b362jmuohqpis\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_xuwfh\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_xuwfh\")\nregion = Rect2(796, 23, 190, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/storm_battery_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://tu40dt2mkliy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_tiv04\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_tiv04\")\nregion = Rect2(292, 552, 180, 182)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/storm_battery_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://exa70j7h5q5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_37ibd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_37ibd\")\nregion = Rect2(292, 552, 180, 182)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/storm_battery_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dydev4xjleywr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_rw3xy\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_rw3xy\")\nregion = Rect2(556, 553, 181, 179)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/storm_coil_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cvtdmff0kk6vv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_b3x8k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_vhoi2\"]\natlas = ExtResource(\"1_b3x8k\")\nregion = Rect2(811, 557, 178, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_vhoi2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/storm_focus_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cmhi8s3xfhb2s\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_k8fb7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_keqj2\"]\natlas = ExtResource(\"1_k8fb7\")\nregion = Rect2(547, 25, 193, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_keqj2\")\noffset = Vector2(10, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/stormy_dog_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ctto64ewkr0at\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_d3pjq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_d3pjq\")\nregion = Rect2(285, 297, 200, 182)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/stormy_dog_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://brxceu8vrxvk4\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_u7ct3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_u7ct3\")\nregion = Rect2(285, 297, 200, 182)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/stormy_dog_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjkikniec8h4q\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_u53it\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_u53it\")\nregion = Rect2(527, 265, 222, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/stormy_dog_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://4ee4453813sa\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_okp2j\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_okp2j\")\nregion = Rect2(527, 265, 222, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/stormy_dog_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://jftutyfuncab\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_mgwyb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_mgwyb\")\nregion = Rect2(780, 285, 214, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/sun_crusader_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dtwalqn408i4w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_vucwf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vucwf\")\nregion = Rect2(313, 529, 158, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/sun_crusader_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b463nxiuj641m\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_lsfqd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_lsfqd\")\nregion = Rect2(313, 529, 158, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/taita_the_hermit_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8le5r1vrvcha\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_d36xf\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2jptc\"]\natlas = ExtResource(\"1_d36xf\")\nregion = Rect2(8, 266, 248, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nposition = Vector2(-1, -57)\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_2jptc\")\n"
  },
  {
    "path": "src/towers/tower_sprites/teacher_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://co225acpiw4ie\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_hykix\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hykix\")\nregion = Rect2(825, 532, 141, 208)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/teacher_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://u11b51g2j37t\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_87g1v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_87g1v\")\nregion = Rect2(825, 532, 141, 208)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-20, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/teacher_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cc0tgdqxcslih\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_n2tec\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_n2tec\")\nregion = Rect2(60, 786, 139, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/teacher_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://brhejo1mpy7s3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_t7mti\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_t7mti\")\nregion = Rect2(60, 786, 139, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/teacher_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d00fqxd1kfc3\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_2ek22\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_2ek22\")\nregion = Rect2(298, 786, 150, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/teacher_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bevqdefp1i7di\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c0i25gqykkvq2\" path=\"res://assets/tower_sprites/astral_uncommon.png\" id=\"1_vdqq6\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_vdqq6\")\nregion = Rect2(298, 786, 150, 219)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-30, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/tentacle_spawn_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://nye8eg31yaoh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_x4lmr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_x4lmr\")\nregion = Rect2(559, 292, 165, 169)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/tentacle_spawn_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cuwwy8fwrst30\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_7rffv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_7rffv\")\nregion = Rect2(559, 292, 165, 169)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/tentacle_spawn_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c0mle363pgwcb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_b57od\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_b57od\")\nregion = Rect2(788, 285, 221, 201)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/tentacle_spawn_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cf3wp5pmfkc2x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_y7mog\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_y7mog\")\nregion = Rect2(788, 285, 221, 201)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/tentacle_spawn_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfjy2q3y4e142\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_y0pb4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_y0pb4\")\nregion = Rect2(11, 521, 239, 238)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/tentacle_spawn_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dg74mroeme5wl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_vj6n3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_vj6n3\")\nregion = Rect2(11, 521, 239, 238)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_conduit_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b6ahsc51g2pfn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_okp4b\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_15e1t\"]\natlas = ExtResource(\"1_okp4b\")\nregion = Rect2(518, 516, 235, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_15e1t\")\noffset = Vector2(10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_council_of_demons_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjcke5qjbjhle\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b8avj0lojcn77\" path=\"res://assets/tower_sprites/darkness_unique.png\" id=\"1_6f0bk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b65j4\"]\natlas = ExtResource(\"1_6f0bk\")\nregion = Rect2(539, 269, 195, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_b65j4\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_fire_lord_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://btgo8tdpcp7qv\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_s54k1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_oo7q4\"]\natlas = ExtResource(\"1_s54k1\")\nregion = Rect2(272, 523, 206, 235)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_oo7q4\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_frozen_wyrm_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7slgeh7rxfh2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_r0bsv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_72f6p\"]\natlas = ExtResource(\"1_r0bsv\")\nregion = Rect2(279, 531, 212, 205)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_72f6p\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_furnace_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bimxpblrlyf72\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_klxa3\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qldai\"]\natlas = ExtResource(\"1_klxa3\")\nregion = Rect2(538, 302, 214, 191)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_qldai\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_omnislasher_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://pnk412qu38i7\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_ib3md\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q4fc6\"]\natlas = ExtResource(\"1_ib3md\")\nregion = Rect2(38, 277, 174, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_q4fc6\")\noffset = Vector2(-10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/the_steam_engine_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dioufaoh0ystr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_5f64r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_0ass1\"]\natlas = ExtResource(\"1_5f64r\")\nregion = Rect2(787, 265, 220, 228)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_0ass1\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/thief_apprentice_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://nsc6mgxjot2w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_rkctc\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_rkctc\")\nregion = Rect2(554, 306, 150, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/thief_apprentice_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dt7q0eniatipw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_m5bkt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_m5bkt\")\nregion = Rect2(554, 306, 150, 180)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/thief_apprentice_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cq3i120tt82mg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_uwuok\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_uwuok\")\nregion = Rect2(797, 269, 185, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/thief_apprentice_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b6gd5n06olgc8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_bayg2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_bayg2\")\nregion = Rect2(797, 269, 185, 224)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/thief_apprentice_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cc0umehwoa7yo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_qs40g\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_qs40g\")\nregion = Rect2(40, 522, 168, 237)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/tidewater_stream_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://qy7ay4etjlvt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_jacvr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_52w2x\"]\natlas = ExtResource(\"1_jacvr\")\nregion = Rect2(289, 31, 198, 195)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_52w2x\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/time_manipulator_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cvf5g8ocln7ok\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_fpuwa\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_k2j4o\"]\natlas = ExtResource(\"1_fpuwa\")\nregion = Rect2(19, 12, 224, 235)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_k2j4o\")\noffset = Vector2(-10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/timevault_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://clv8742pipnfw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_qrkvn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_2085v\"]\natlas = ExtResource(\"1_qrkvn\")\nregion = Rect2(291, 19, 195, 226)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_2085v\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_shrub_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://3oc33r6r5h64\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_yrrxd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_yrrxd\")\nregion = Rect2(41, 58, 170, 158)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_shrub_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d4lluktbj2qs6\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_n07a5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_n07a5\")\nregion = Rect2(41, 58, 170, 158)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_shrub_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cjfb8ddn80fsj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_kwdfr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_kwdfr\")\nregion = Rect2(276, 13, 207, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_shrub_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bt3jkergdipma\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_1e3q2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_1e3q2\")\nregion = Rect2(276, 13, 207, 234)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_shrub_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dvelj608pxbae\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_0iub5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_0iub5\")\nregion = Rect2(547, 12, 199, 228)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_shrub_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://4diqlblnocr\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_ioles\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ioles\")\nregion = Rect2(547, 12, 199, 228)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_storm_lantern_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bplb12qxyj4xb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_4sclw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_4sclw\")\nregion = Rect2(68, 1059, 135, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_storm_lantern_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dhclodddek7jo\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_5bkup\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_5bkup\")\nregion = Rect2(68, 1059, 135, 202)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_storm_lantern_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://0hp1m1bolqqs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_lpan5\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_lpan5\")\nregion = Rect2(317, 1054, 147, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tiny_storm_lantern_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://taqrgx564c1x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c7hu3aovppxyi\" path=\"res://assets/tower_sprites/storm_uncommon.png\" id=\"1_oiw0u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_oiw0u\")\nregion = Rect2(317, 1054, 147, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tombstone_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://wrrf1xdh7rw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_huags\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_huags\")\nregion = Rect2(302, 546, 174, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/tombstone_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1j0vroivrqg2\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_2lfm4\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_2lfm4\")\nregion = Rect2(302, 546, 174, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -50)\n"
  },
  {
    "path": "src/towers/tower_sprites/tombstone_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ogheh68148xl\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_ix6k7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ix6k7\")\nregion = Rect2(560, 543, 161, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tombstone_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bjsyxomfb3syb\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_sl7ml\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_sl7ml\")\nregion = Rect2(560, 543, 161, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tombstone_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://gw5ynbd0ehs0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_qdl3p\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_qdl3p\")\nregion = Rect2(785, 531, 211, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tombstone_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b35tm2k43e83h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cqetvcfdjje3s\" path=\"res://assets/tower_sprites/darkness_common.png\" id=\"1_ku2qj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"2\"]\natlas = ExtResource(\"1_ku2qj\")\nregion = Rect2(785, 531, 211, 232)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"2\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/trash_heap_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1p03sqtg108d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_b5ki8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_b5ki8\")\nregion = Rect2(304, 587, 140, 124)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/trash_heap_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d06v6g8rpujjj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_qbrkg\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_qbrkg\")\nregion = Rect2(304, 587, 140, 124)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/trash_heap_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://exraj1yd1303\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_yof0s\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_yof0s\")\nregion = Rect2(538, 545, 195, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/trash_heap_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bv3gy22500s16\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_rxnf7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_rxnf7\")\nregion = Rect2(538, 545, 195, 197)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/trash_heap_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b5e4pgifipmlf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_nnvrt\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_nnvrt\")\nregion = Rect2(787, 535, 226, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/trash_heap_6.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bxtl3f5rqw0of\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dcfvp18syyxci\" path=\"res://assets/tower_sprites/iron_common.png\" id=\"1_sqtam\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_sqtam\")\nregion = Rect2(787, 535, 226, 206)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/tree_stump_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://wqsrdyqkdtsu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_iv24k\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_iv24k\")\nregion = Rect2(568, 308, 153, 172)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/tree_stump_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://yrxk2bc542oy\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_aj1uk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_aj1uk\")\nregion = Rect2(568, 308, 153, 172)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/tree_stump_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://tllhpd1d5omn\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_df1vj\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_df1vj\")\nregion = Rect2(799, 291, 182, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tree_stump_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://yj4hysddt7l0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_ax0fb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_ax0fb\")\nregion = Rect2(799, 291, 182, 211)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tree_stump_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cl2q0wvyh8yb1\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8uwpkclo4nk5\" path=\"res://assets/tower_sprites/nature_common.png\" id=\"1_yglol\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_q32kx\"]\natlas = ExtResource(\"1_yglol\")\nregion = Rect2(44, 535, 173, 215)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_q32kx\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/tundra_stalker_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dkxccmeeuk3ff\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_l4srb\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_12oii\"]\natlas = ExtResource(\"1_l4srb\")\nregion = Rect2(534, 22, 207, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_12oii\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/tundra_stalker_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b44ahjipxwbvd\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_ab2wd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_12oii\"]\natlas = ExtResource(\"1_ab2wd\")\nregion = Rect2(534, 22, 207, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_12oii\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/tundra_stalker_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://barp2ywhn5cvp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_q1nqd\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_12oii\"]\natlas = ExtResource(\"1_q1nqd\")\nregion = Rect2(534, 22, 207, 221)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_12oii\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/tundra_stalker_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cfq555tb5yu2o\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_r6b68\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7bkgl\"]\natlas = ExtResource(\"1_r6b68\")\nregion = Rect2(787, 2, 225, 250)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_7bkgl\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/tundra_stalker_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cf1je0x0a1xnh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://clyoh08bhg4fv\" path=\"res://assets/tower_sprites/ice_uncommon.png\" id=\"1_e8mxe\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7bkgl\"]\natlas = ExtResource(\"1_e8mxe\")\nregion = Rect2(787, 2, 225, 250)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_7bkgl\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/undisturbed_crypt_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cah0lcybaa5bu\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_6u28l\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_6u28l\")\nregion = Rect2(33, 58, 193, 159)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/undisturbed_crypt_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ci7fdhu7oiwiw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_4mvnx\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_4mvnx\")\nregion = Rect2(33, 58, 193, 159)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/undisturbed_crypt_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://f6j7xe7fhlhp\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_mvp0v\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_mvp0v\")\nregion = Rect2(290, 49, 196, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/undisturbed_crypt_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dmfah0vlt4xp8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_i5b3c\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_voii6\"]\natlas = ExtResource(\"1_i5b3c\")\nregion = Rect2(290, 49, 196, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_voii6\")\noffset = Vector2(0, -20)\n"
  },
  {
    "path": "src/towers/tower_sprites/valor_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d06p4m8dcdjhm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_qfw7u\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_cgs55\"]\natlas = ExtResource(\"1_qfw7u\")\nregion = Rect2(280, 273, 219, 229)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_cgs55\")\noffset = Vector2(10, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/village_witch_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://wr26qm3wj7qq\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_43u3c\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_43u3c\")\nregion = Rect2(286, 541, 164, 198)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/village_witch_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cwa1hqf7yecns\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_37oqm\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_37oqm\")\nregion = Rect2(286, 541, 164, 198)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/village_witch_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cwfv16a4qhj7r\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_g7pab\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_g7pab\")\nregion = Rect2(537, 526, 206, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/village_witch_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ddsqots8x3yg8\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1n41qevrcqi\" path=\"res://assets/tower_sprites/darkness_uncommon.png\" id=\"1_luxvq\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_luxvq\")\nregion = Rect2(537, 526, 206, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/void_drake_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cy5pqtieycyoj\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_a11ln\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_f6pgn\"]\natlas = ExtResource(\"1_a11ln\")\nregion = Rect2(533, 25, 207, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_f6pgn\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/void_drake_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvqergyl07e3d\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://65jvdxexe8qw\" path=\"res://assets/tower_sprites/darkness_rare.png\" id=\"1_t4wji\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_b4fx0\"]\natlas = ExtResource(\"1_t4wji\")\nregion = Rect2(533, 25, 207, 223)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_b4fx0\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/vulshok_the_berserker_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bok3m8rgs4d8l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bn5nfw6lifhof\" path=\"res://assets/tower_sprites/fire_unique.png\" id=\"1_ovccn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_57c1s\"]\natlas = ExtResource(\"1_ovccn\")\nregion = Rect2(537, 34, 182, 214)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_57c1s\")\noffset = Vector2(-15, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/warrior_of_light_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dlaqwjrspncjs\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_7pp5c\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_7pp5c\")\nregion = Rect2(819, 29, 167, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/warrior_of_light_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bhtkt1ipn543i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_jioyl\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_jioyl\")\nregion = Rect2(819, 29, 167, 203)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-10, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/warrior_of_light_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://pjnfihsdp0i\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://biqwx15sdng3w\" path=\"res://assets/tower_sprites/astral_rare.png\" id=\"1_0qg2t\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_0qg2t\")\nregion = Rect2(21, 262, 195, 217)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/wild_warbeast_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b3a68k1htvjqi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cowfob3sgn0hd\" path=\"res://assets/tower_sprites/nature_unique.png\" id=\"1_5nvik\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_u0tu7\"]\natlas = ExtResource(\"1_5nvik\")\nregion = Rect2(270, 60, 236, 186)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_u0tu7\")\noffset = Vector2(0, -60)\n"
  },
  {
    "path": "src/towers/tower_sprites/witch_doctor_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://lfpcaaeka476\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://df1ouj1h6g583\" path=\"res://assets/tower_sprites/astral_unique.png\" id=\"1_nonxr\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_s3kxm\"]\natlas = ExtResource(\"1_nonxr\")\nregion = Rect2(24, 278, 188, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_s3kxm\")\noffset = Vector2(-15, -80)\n"
  },
  {
    "path": "src/towers/tower_sprites/wooden_trap_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dqye1auhofwgm\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_m45gs\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_m45gs\")\nregion = Rect2(33, 563, 183, 164)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/wooden_trap_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bpnae5jq52vqh\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_hcyas\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_hcyas\")\nregion = Rect2(33, 563, 183, 164)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/wooden_trap_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bseximvu7p4tt\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_x6lss\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_x6lss\")\nregion = Rect2(284, 545, 210, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/wooden_trap_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b362qff4g5rna\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_ftiu1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ftiu1\")\nregion = Rect2(284, 545, 210, 204)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/wooden_trap_5.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7gl112agi5tw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://tqwlpk8sdox0\" path=\"res://assets/tower_sprites/iron_uncommon.png\" id=\"1_tr4g8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_tr4g8\")\nregion = Rect2(540, 546, 203, 193)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/xeno_research_facility_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://c7emruu4fprb0\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://badivqvsvs52t\" path=\"res://assets/tower_sprites/iron_unique.png\" id=\"1_7hm4t\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_6tc85\"]\natlas = ExtResource(\"1_7hm4t\")\nregion = Rect2(25, 305, 203, 189)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_6tc85\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/ymir_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cr1307iyilgk5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://bcj5bery2fwd2\" path=\"res://assets/tower_sprites/ice_unique.png\" id=\"1_ljfao\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ilbf6\"]\natlas = ExtResource(\"1_ljfao\")\nregion = Rect2(264, 260, 242, 247)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.9, 0.9)\ntexture = SubResource(\"AtlasTexture_ilbf6\")\noffset = Vector2(0, -90)\n"
  },
  {
    "path": "src/towers/tower_sprites/young_northern_troll_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://coiuxdrx8iu1x\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_ooi4h\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_ooi4h\")\nregion = Rect2(523, 30, 220, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.6, 0.6)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/young_northern_troll_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://qewakcw1bsga\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_bgqmv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_bgqmv\")\nregion = Rect2(523, 30, 220, 218)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/young_northern_troll_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cb384lb8uyc5w\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://djwd1fnrh5xpc\" path=\"res://assets/tower_sprites/ice_rare.png\" id=\"1_t2he1\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_lrt4k\"]\natlas = ExtResource(\"1_t2he1\")\nregion = Rect2(779, 9, 238, 227)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_lrt4k\")\noffset = Vector2(-25, -70)\n"
  },
  {
    "path": "src/towers/tower_sprites/zealot_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://crawndwmrrfp5\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_vvvpk\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_vvvpk\")\nregion = Rect2(559, 25, 174, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.65, 0.65)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/zealot_2.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cuw3iaj1cgipg\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_8n2l7\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_8n2l7\")\nregion = Rect2(559, 25, 174, 207)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.7, 0.7)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -30)\n"
  },
  {
    "path": "src/towers/tower_sprites/zealot_3.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ci1b3dfmj41gw\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_obujw\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_obujw\")\nregion = Rect2(783, 35, 220, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.75, 0.75)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/zealot_4.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dtysqcjwfvx1l\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://p0uh8dc0naey\" path=\"res://assets/tower_sprites/storm_rare.png\" id=\"1_qs2mv\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_d0cuo\"]\natlas = ExtResource(\"1_qs2mv\")\nregion = Rect2(783, 35, 220, 183)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\nscale = Vector2(0.8, 0.8)\ntexture = SubResource(\"AtlasTexture_d0cuo\")\noffset = Vector2(0, -40)\n"
  },
  {
    "path": "src/towers/tower_sprites/zeus_1.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dhmt3trt5ndqe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://b0lv1vv13qxox\" path=\"res://assets/tower_sprites/storm_unique.png\" id=\"1_cotu8\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_hta3y\"]\natlas = ExtResource(\"1_cotu8\")\nregion = Rect2(284, 270, 205, 231)\n\n[node name=\"Sprite2D\" type=\"Sprite2D\"]\ntexture = SubResource(\"AtlasTexture_hta3y\")\noffset = Vector2(10, -90)\n"
  },
  {
    "path": "src/ui/buttons/ability_button.gd",
    "content": "class_name AbilityButton extends Button\n\n\n# Button for tower abilities. Note that this is for not-active abilities. Active abilities use AutocastButton.\n\n\nclass Data:\n\tvar name_english: String = \"PLACEHOLDER name\"\n\tvar ability_name: String = \"PLACEHOLDER name\"\n\tvar icon: String = \"PLACEHOLDER icon\"\n\tvar description_long: String = \"PLACEHOLDER description_long\"\n\n\nconst FALLBACK_ICON: String = \"res://resources/icons/mechanical/compass.tres\"\n\n\nvar _icon_path: String = \"\"\nvar _tooltip_text: String = \"\"\nvar _ability_name_english: String = \"\"\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar icon_path_is_valid: bool = ResourceLoader.exists(_icon_path)\n\tif !icon_path_is_valid:\n\t\tif !_icon_path.is_empty():\n\t\t\tpush_error(\"Invalid icon path for ability: %s\" % _icon_path)\n\n\t\t_icon_path = FALLBACK_ICON\n\n\tvar ability_icon: Texture2D = load(_icon_path)\n\tset_button_icon(ability_icon)\n\n\tmouse_entered.connect(_on_mouse_entered)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_ability_name_english() -> String:\n\treturn _ability_name_english\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make_from_data(data: AbilityButton.Data) -> AbilityButton:\n\tvar button: AbilityButton = Preloads.ability_button_scene.instantiate()\n\tbutton._icon_path = data.icon\n\t\n\tvar ability_name: String = data.ability_name\n\tvar description: String = data.description_long\n\tvar description_colored: String = RichTexts.add_color_to_numbers(description)\n\tbutton._tooltip_text = \"[color=GOLD]%s[/color]\\n \\n%s\" % [ability_name, description_colored]\n\n\tbutton._ability_name_english = data.name_english\n\n\treturn button\n\n\nstatic func make_from_ability_id(ability_id: int) -> AbilityButton:\n\tvar button: AbilityButton = Preloads.ability_button_scene.instantiate()\n\t\n\tbutton._icon_path = AbilityProperties.get_icon_path(ability_id)\n\n\tvar ability_name: String = AbilityProperties.get_ability_name(ability_id)\n\tvar description: String = AbilityProperties.get_description_long(ability_id)\n\tdescription = RichTexts.add_color_to_numbers(description)\n\tbutton._tooltip_text = \"[color=GOLD]%s[/color]\\n \\n%s\" % [ability_name, description]\n\n\treturn button\n\n\nstatic func make_from_aura_id(aura_id: int) -> AbilityButton:\n\tvar button: AbilityButton = Preloads.ability_button_scene.instantiate()\n\tbutton._icon_path = AuraProperties.get_icon_path(aura_id)\n\n\tvar aura_name: String = AuraProperties.get_aura_name(aura_id)\n\tvar description: String = AuraProperties.get_description_long(aura_id)\n\tvar description_colored: String = RichTexts.add_color_to_numbers(description)\n\tbutton._tooltip_text = \"[color=GOLD]%s - %s[/color]\\n \\n%s\" % [aura_name, Utils.tr(\"AURA_WORD_IN_TITLE\"), description_colored]\n\t\n\tbutton._ability_name_english = AuraProperties.get_name_english(aura_id)\n\n\treturn button\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_mouse_entered():\n\tButtonTooltip.show_tooltip(self, _tooltip_text, ButtonTooltip.Location.BOTTOM)\n"
  },
  {
    "path": "src/ui/buttons/ability_button.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://d0aesr1u8n1xt\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_vdlb1\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ckb2soah83qpl\" path=\"res://resources/icons/rockets/rocket_05.tres\" id=\"2_b5mkd\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/ability_button.gd\" id=\"3_cgguu\"]\n\n[node name=\"AbilityButton\" type=\"Button\"]\ncustom_minimum_size = Vector2(85, 85)\nfocus_mode = 0\ntheme = ExtResource(\"1_vdlb1\")\ntheme_type_variation = &\"PassiveAbilityButton\"\nicon = ExtResource(\"2_b5mkd\")\nicon_alignment = 1\nexpand_icon = true\nscript = ExtResource(\"3_cgguu\")\n"
  },
  {
    "path": "src/ui/buttons/auto_mode_indicator.gd",
    "content": "@tool\nclass_name AutoModeIndicator extends Control\n\n\n# Displays 4 \"comets\" which move around the border of parent\n# UI element. Should be used to display that autocast\n# automatic mode is enabled.\n\n# NOTE: ParticlesContainer node is needed to be able to hide\n# particles without modifying \"visible\" property of the\n# AutoModeIndicator itself. This way, the indicator can\n# show/hide it's particles while the parent of the indicator\n# can decide whether the indicator should be visible\n# overall.\n\n# NOTE: in msec\nconst INDICATOR_CYCLE_DURATION: float = 3.0 * 1000\n\nvar _autocast: Autocast = null\n\n@export var _particles_container: Control\n@export var _particles_1: CPUParticles2D\n@export var _particles_2: CPUParticles2D\n@export var _particles_3: CPUParticles2D\n@export var _particles_4: CPUParticles2D\n\n\n@onready var _particle_list: Array[CPUParticles2D] = [\n\t_particles_1,\n\t_particles_2,\n\t_particles_3,\n\t_particles_4,\n]\n\n\nfunc set_autocast(autocast: Autocast):\n\t_autocast = autocast\n\n\nfunc _process(_delta: float):\n\tif !Engine.is_editor_hint():\n\t\t_particles_container.visible = _autocast != null && _autocast.auto_mode_is_enabled()\n\t\n\tif !_particles_container.visible:\n\t\treturn\n\t\n\tAutoModeIndicator.update_border_particles(self, _particle_list, 0.25)\n\n\nstatic func update_border_particles(parent_control: Control, particle_list: Array[CPUParticles2D], border_ratio_per_particle: float):\n\tvar particle_area_size: Vector2 = parent_control.size\n\tvar particle_area_perimeter: float = 2 * (particle_area_size.x + particle_area_size.y)\n\t\n\tvar cycle_timer: float = fmod(Time.get_ticks_msec(), INDICATOR_CYCLE_DURATION)\n\tvar distance_ratio_base: float = cycle_timer / INDICATOR_CYCLE_DURATION\n\t\n\tfor i in range(0, particle_list.size()):\n\t\tvar particle: CPUParticles2D = particle_list[i]\n\t\tvar distance_ratio: float = distance_ratio_base + border_ratio_per_particle * i\n\t\tvar travel_distance: float = particle_area_perimeter * distance_ratio\n\t\t\n\t\tvar current_direction: Vector2 = Vector2(1, 0)\n\t\t\n\t\tvar particle_pos: Vector2 = Vector2(0, 0)\n\t\twhile travel_distance > 0:\n\t\t\tvar travel_vector: Vector2 = current_direction * travel_distance\n\t\t\ttravel_vector = travel_vector.clamp(-particle_area_size, particle_area_size)\n\t\t\tparticle_pos += travel_vector\n\t\t\ttravel_distance -= travel_vector.length()\n\t\t\t\n\t\t\tcurrent_direction = current_direction.rotated(deg_to_rad(90))\n\n\t\tparticle.position = particle_pos\n"
  },
  {
    "path": "src/ui/buttons/auto_mode_indicator.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://bovo5mbv22jly\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/auto_mode_indicator.gd\" id=\"1_r4cmb\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ce6k2v2g5l88d\" path=\"res://assets/misc/autocast_automode_particle.png\" id=\"2_jh2gc\"]\n\n\n[sub_resource type=\"Curve\" id=\"Curve_4kjed\"]\n_data = [Vector2(0, 0.663158), 0.0, 0.0, 0, 0, Vector2(0.911227, 0.294737), 0.0, 0.0, 0, 0]\npoint_count = 2\n\n[sub_resource type=\"Gradient\" id=\"Gradient_pb6mi\"]\ncolors = PackedColorArray(1, 1, 1, 0.784314, 1, 1, 1, 0.392157)\n\n[node name=\"AutoModeIndicator\" type=\"Control\" node_paths=PackedStringArray(\"_particles_container\", \"_particles_1\", \"_particles_2\", \"_particles_3\", \"_particles_4\")]\nlayout_mode = 3\nanchors_preset = 0\noffset_right = 80.0\noffset_bottom = 80.0\nmouse_filter = 2\nscript = ExtResource(\"1_r4cmb\")\n_particles_container = NodePath(\"ParticlesContainer\")\n_particles_1 = NodePath(\"ParticlesContainer/CPUParticles2D\")\n_particles_2 = NodePath(\"ParticlesContainer/CPUParticles2D2\")\n_particles_3 = NodePath(\"ParticlesContainer/CPUParticles2D3\")\n_particles_4 = NodePath(\"ParticlesContainer/CPUParticles2D4\")\n\n[node name=\"ParticlesContainer\" type=\"Control\" parent=\".\"]\nanchors_preset = 0\noffset_right = 40.0\noffset_bottom = 40.0\nmouse_filter = 2\n\n[node name=\"CPUParticles2D\" type=\"CPUParticles2D\" parent=\"ParticlesContainer\"]\nposition = Vector2(28.4444, 0)\namount = 32\nlifetime = 0.6\nrandomness = 1.0\nlifetime_randomness = 0.2\ntexture = ExtResource(\"2_jh2gc\")\ngravity = Vector2(0, 0)\nscale_amount_curve = SubResource(\"Curve_4kjed\")\ncolor_ramp = SubResource(\"Gradient_pb6mi\")\n\n[node name=\"CPUParticles2D2\" type=\"CPUParticles2D\" parent=\"ParticlesContainer\"]\nposition = Vector2(80, 28.4444)\namount = 32\nlifetime = 0.6\nrandomness = 1.0\nlifetime_randomness = 0.2\ntexture = ExtResource(\"2_jh2gc\")\ngravity = Vector2(0, 0)\nscale_amount_curve = SubResource(\"Curve_4kjed\")\ncolor_ramp = SubResource(\"Gradient_pb6mi\")\n\n[node name=\"CPUParticles2D3\" type=\"CPUParticles2D\" parent=\"ParticlesContainer\"]\nposition = Vector2(51.5555, 80)\namount = 32\nlifetime = 0.6\nrandomness = 1.0\nlifetime_randomness = 0.2\ntexture = ExtResource(\"2_jh2gc\")\ngravity = Vector2(0, 0)\nscale_amount_curve = SubResource(\"Curve_4kjed\")\ncolor_ramp = SubResource(\"Gradient_pb6mi\")\n\n[node name=\"CPUParticles2D4\" type=\"CPUParticles2D\" parent=\"ParticlesContainer\"]\nposition = Vector2(-3.89936e-06, 51.5555)\namount = 32\nlifetime = 0.6\nrandomness = 1.0\nlifetime_randomness = 0.2\ntexture = ExtResource(\"2_jh2gc\")\ngravity = Vector2(0, 0)\nscale_amount_curve = SubResource(\"Curve_4kjed\")\ncolor_ramp = SubResource(\"Gradient_pb6mi\")\n"
  },
  {
    "path": "src/ui/buttons/autocast_button.gd",
    "content": "class_name AutocastButton extends Button\n\n\nconst FALLBACK_AUTOCAST_ICON: String = \"res://resources/icons/mechanical/compass.tres\"\n\n\nvar _autocast: Autocast = null\n@export var _time_indicator: TimeIndicator\n@export var _auto_mode_indicator: AutoModeIndicator\n@export var _indicator_container: MarginContainer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar icon_path: String = _autocast.get_icon_path()\n\tvar icon_path_is_valid: bool = ResourceLoader.exists(icon_path)\n\n\tif !icon_path_is_valid:\n\t\tpush_error(\"Invalid icon path for autocast: %s\" % icon_path)\n\n\t\ticon_path = FALLBACK_AUTOCAST_ICON\n\n\tvar autocast_icon: Texture2D = load(icon_path)\n\tset_button_icon(autocast_icon)\n\n\tmouse_entered.connect(_on_mouse_entered)\n\n\t_time_indicator.set_autocast(_autocast)\n\t_auto_mode_indicator.set_autocast(_autocast)\n\n\tvar button_stylebox: StyleBox = get_theme_stylebox(\"normal\", \"Button\")\n\n#\tNOTE: need to load margins here because they are not\n#\tfinalized while in editor\n\t_indicator_container.add_theme_constant_override(\"margin_top\", int(button_stylebox.content_margin_top))\n\t_indicator_container.add_theme_constant_override(\"margin_left\", int(button_stylebox.content_margin_left))\n\t_indicator_container.add_theme_constant_override(\"margin_bottom\", int(button_stylebox.content_margin_bottom))\n\t_indicator_container.add_theme_constant_override(\"margin_right\", int(button_stylebox.content_margin_right))\n\n\nfunc _gui_input(event):\n\tvar pressed_right_click: bool = event.is_action_released(\"right_click\")\n\n\tif pressed_right_click:\n\t\tEventBus.player_right_clicked_autocast.emit(_autocast)\n\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_autocast() -> Autocast:\n\treturn _autocast\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_pressed():\n\tEventBus.player_clicked_autocast.emit(_autocast)\n\n\n#########################\n###       Static      ###\n#########################\n\nfunc _on_mouse_entered():\n\tvar tooltip: String = RichTexts.get_autocast_tooltip(_autocast)\n\tButtonTooltip.show_tooltip(self, tooltip, ButtonTooltip.Location.BOTTOM)\n\n\nstatic func make(autocast: Autocast) -> AutocastButton:\n\tvar autocast_button_scene: PackedScene = preload(\"res://src/ui/buttons/autocast_button.tscn\")\n\tvar button: AutocastButton = autocast_button_scene.instantiate()\n\tbutton._autocast = autocast\n\t\n\treturn button\n"
  },
  {
    "path": "src/ui/buttons/autocast_button.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://cf3dgj0hegtqq\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/autocast_button.gd\" id=\"1_eojut\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://0npkf7jas08m\" path=\"res://resources/icons/gloves/heal.tres\" id=\"2_o57jp\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/time_indicator.gd\" id=\"3_d6wsi\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"3_rtugu\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bovo5mbv22jly\" path=\"res://src/ui/buttons/auto_mode_indicator.tscn\" id=\"5_xah78\"]\n\n[node name=\"AutocastButton\" type=\"Button\" node_paths=PackedStringArray(\"_time_indicator\", \"_auto_mode_indicator\", \"_indicator_container\")]\ncustom_minimum_size = Vector2(85, 85)\nfocus_mode = 0\ntheme = ExtResource(\"3_rtugu\")\ntheme_type_variation = &\"UnitButton\"\nicon = ExtResource(\"2_o57jp\")\nexpand_icon = true\nscript = ExtResource(\"1_eojut\")\n_time_indicator = NodePath(\"IndicatorContainer/TimeIndicator\")\n_auto_mode_indicator = NodePath(\"IndicatorContainer/MarginContainer/AutoModeIndicator\")\n_indicator_container = NodePath(\"IndicatorContainer\")\n\n[node name=\"IndicatorContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme_override_constants/margin_left = 4\ntheme_override_constants/margin_top = 4\ntheme_override_constants/margin_right = 4\ntheme_override_constants/margin_bottom = 4\n\n[node name=\"TimeIndicator\" type=\"Control\" parent=\"IndicatorContainer\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme = ExtResource(\"3_rtugu\")\nscript = ExtResource(\"3_d6wsi\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"IndicatorContainer\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_left = 2\ntheme_override_constants/margin_top = 2\ntheme_override_constants/margin_right = 2\ntheme_override_constants/margin_bottom = 2\n\n[node name=\"AutoModeIndicator\" parent=\"IndicatorContainer/MarginContainer\" instance=ExtResource(\"5_xah78\")]\nlayout_mode = 2\n\n[connection signal=\"pressed\" from=\".\" to=\".\" method=\"_on_pressed\"]\n"
  },
  {
    "path": "src/ui/buttons/buff_group_button.gd",
    "content": "@tool\nclass_name BuffGroupButton extends Button\n\n\n@export var _buff_group_number: int = 0\n@export var _number_label: Label\n@export var _texture_rect: TextureRect\n\nconst _buff_group_none_icon: Texture2D = preload(\"res://resources/ui_textures/buff_group_none.tres\")\nconst _buff_group_incoming_icon: Texture2D = preload(\"res://resources/ui_textures/buff_group_incoming.tres\")\nconst _buff_group_outgoing_icon: Texture2D = preload(\"res://resources/ui_textures/buff_group_outgoing.tres\")\nconst _buff_group_both_icon: Texture2D = preload(\"res://resources/ui_textures/buff_group_both.tres\")\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_number_label.text = str(_buff_group_number)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_buff_group_number() -> int:\n\treturn _buff_group_number\n\n\nfunc set_buff_group_mode(value: BuffGroupMode.enm):\n\tmatch value:\n\t\tBuffGroupMode.enm.NONE: \n\t\t\t_texture_rect.texture = _buff_group_none_icon\n\t\t\ttooltip_text = tr(\"BUFFGROUP_DESCRIPTION_NONE\").format({BUFFGROUP_NUMBER = _buff_group_number})\n\t\tBuffGroupMode.enm.OUTGOING: \n\t\t\t_texture_rect.texture = _buff_group_outgoing_icon\n\t\t\ttooltip_text = tr(\"BUFFGROUP_DESCRIPTION_OUTGOING\").format({BUFFGROUP_NUMBER = _buff_group_number})\n\t\tBuffGroupMode.enm.INCOMING: \n\t\t\t_texture_rect.texture = _buff_group_incoming_icon\n\t\t\ttooltip_text = tr(\"BUFFGROUP_DESCRIPTION_INCOMING\").format({BUFFGROUP_NUMBER = _buff_group_number})\n\t\tBuffGroupMode.enm.BOTH: \n\t\t\t_texture_rect.texture = _buff_group_both_icon\n\t\t\ttooltip_text = tr(\"BUFFGROUP_DESCRIPTION_BOTH\").format({BUFFGROUP_NUMBER = _buff_group_number})\n"
  },
  {
    "path": "src/ui/buttons/buff_group_button.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dfid7khpwu0i8\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_2mwqg\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/buff_group_button.gd\" id=\"1_ddno2\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dho1jq3a82j7u\" path=\"res://resources/ui_textures/buff_group_none.tres\" id=\"3_d7v21\"]\n\n[node name=\"BuffGroupButton\" type=\"Button\" node_paths=PackedStringArray(\"_number_label\", \"_texture_rect\")]\ncustom_minimum_size = Vector2(50, 50)\noffset_right = 50.0\noffset_bottom = 50.0\nfocus_mode = 0\ntheme = ExtResource(\"1_2mwqg\")\ntheme_type_variation = &\"BuffGroupButton\"\nscript = ExtResource(\"1_ddno2\")\n_number_label = NodePath(\"MarginContainer/NumberLevel\")\n_texture_rect = NodePath(\"TextureRect\")\n\n[node name=\"TextureRect\" type=\"TextureRect\" parent=\".\"]\ncustom_minimum_size = Vector2(50, 50)\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntexture = ExtResource(\"3_d7v21\")\nexpand_mode = 1\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme_override_constants/margin_top = 15\n\n[node name=\"NumberLevel\" type=\"Label\" parent=\"MarginContainer\"]\ncustom_minimum_size = Vector2(50, 50)\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0, 0, 0, 1)\ntext = \"0\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n"
  },
  {
    "path": "src/ui/buttons/builder_button.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://wqb5cj4ppde8\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_btx8k\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/button_with_rich_tooltip.gd\" id=\"1_il3lu\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cirq2nbm85h2e\" path=\"res://resources/icons/faces/orc_02.tres\" id=\"2_28q2n\"]\n\n\n[node name=\"BuilderButton\" type=\"Button\"]\ncustom_minimum_size = Vector2(100, 100)\nfocus_mode = 0\ntheme = ExtResource(\"1_btx8k\")\ntheme_type_variation = &\"UnitButton\"\nicon = ExtResource(\"2_28q2n\")\nicon_alignment = 1\nexpand_icon = true\nscript = ExtResource(\"1_il3lu\")\n"
  },
  {
    "path": "src/ui/buttons/button_tooltip.gd",
    "content": "class_name ButtonTooltip extends PanelContainer\n\n\n# Tooltip used to display tower/item details when their\n# buttons are hovered by mouse. Note that this is different\n# from native Control tooltip because this tooltip is\n# displayed at a pre-defined position, not under mouse\n# cursor.\n\n\nenum Location {\n\tTOP,\n\tBOTTOM,\n}\n\n\nstatic var _tooltip_instance_top: ButtonTooltip = null\nstatic var _tooltip_instance_bottom: ButtonTooltip = null\nstatic var _current_button_global: Button = null\n\n@export var _label: RichTextLabel\n\nvar _current_button: Button = null\n\n\nstatic func setup_tooltip_instances(tooltip_top: ButtonTooltip, tooltip_bottom: ButtonTooltip):\n\tButtonTooltip._tooltip_instance_top = tooltip_top\n\tButtonTooltip._tooltip_instance_bottom = tooltip_bottom\n\n\nstatic func show_tooltip(button: Button, tooltip: String, location: Location = Location.TOP):\t\n\tif ButtonTooltip._tooltip_instance_top == null || ButtonTooltip._tooltip_instance_bottom == null:\n\t\tpush_error(\"Tooltip instances weren't setup correctly: [%s, %s]\" % [ButtonTooltip._tooltip_instance_top, ButtonTooltip._tooltip_instance_bottom])\n\n\t\treturn\n\t\n\tvar tooltip_instance: ButtonTooltip\n\tmatch location:\n\t\tLocation.TOP: tooltip_instance = ButtonTooltip._tooltip_instance_top\n\t\tLocation.BOTTOM: tooltip_instance = ButtonTooltip._tooltip_instance_bottom\n\n\tButtonTooltip._tooltip_instance_top._clear_current_button()\n\tButtonTooltip._tooltip_instance_bottom._clear_current_button()\n\t\n\ttooltip_instance._show_tooltip(button, tooltip)\n\tButtonTooltip._current_button_global = button\n\n\nstatic func get_current_target() -> Button:\n\treturn ButtonTooltip._current_button_global\n\n\nfunc _show_tooltip(button: Button, tooltip: String):\n\t_clear_current_button()\n\n\t_current_button = button\n\t_current_button.mouse_exited.connect(_clear_current_button)\n\t_current_button.tree_exited.connect(_clear_current_button)\n\t_current_button.hidden.connect(_clear_current_button)\n\n\t_label.clear()\n\t_label.append_text(tooltip)\n\n\tshow()\n\n\nfunc _clear_current_button():\n\tif _current_button != null && is_instance_valid(_current_button):\n\t\t_current_button.mouse_exited.disconnect(_clear_current_button)\n\t\t_current_button.tree_exited.disconnect(_clear_current_button)\n\t\t_current_button.hidden.disconnect(_clear_current_button)\n\n\t_current_button = null\n\thide()\n"
  },
  {
    "path": "src/ui/buttons/button_tooltip.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://nl0pvhb4rasi\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"1_4g5vq\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/button_tooltip.gd\" id=\"1_xd471\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"3_jper7\"]\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_47fwl\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 10.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"1_4g5vq\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 154)\nmodulate_color = Color(1, 1, 1, 0.72549)\n\n[node name=\"ButtonTooltip\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_label\")]\noffset_right = 540.0\noffset_bottom = 139.0\nmouse_filter = 2\ntheme_override_styles/panel = SubResource(\"StyleBoxTexture_47fwl\")\nscript = ExtResource(\"1_xd471\")\n_label = NodePath(\"MarginContainer/RichTextLabel\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"MarginContainer\"]\ncustom_minimum_size = Vector2(600, 100)\nlayout_mode = 2\ntheme = ExtResource(\"3_jper7\")\ntext = \"PLACEHOLDER\"\nfit_content = true\n"
  },
  {
    "path": "src/ui/buttons/button_with_rich_tooltip.gd",
    "content": "class_name ButtonWithRichTooltip extends Button\n\n\n# This button has a RichTextLabel tooltip. Normal Button\n# class supports only Label tooltips.\n\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n"
  },
  {
    "path": "src/ui/buttons/element_button.gd",
    "content": "class_name ElementButton extends Button\n\n\n# This button is used in Elements menu.\n\n\n@export var _level_label: Label\n\n\nfunc set_level(level: int):\n\t_level_label.text = str(level)\n"
  },
  {
    "path": "src/ui/buttons/element_button.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bpdanpr2im0gg\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_qxufv\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://63uq7vjycais\" path=\"res://resources/icons/elements/ice.tres\" id=\"2_y31aw\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/element_button.gd\" id=\"3_eftv1\"]\n\n[node name=\"ElementButton\" type=\"Button\" node_paths=PackedStringArray(\"_level_label\")]\ncustom_minimum_size = Vector2(80, 80)\nfocus_mode = 0\ntheme = ExtResource(\"1_qxufv\")\ntheme_type_variation = &\"TinyUnitButton\"\nicon = ExtResource(\"2_y31aw\")\nicon_alignment = 1\nexpand_icon = true\nscript = ExtResource(\"3_eftv1\")\n_level_label = NodePath(\"MarginContainer2/AspectRatioContainer/LevelLabel\")\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\".\"]\nz_index = 1\nlayout_mode = 1\nanchors_preset = 3\nanchor_left = 1.0\nanchor_top = 1.0\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_left = -38.0\noffset_top = -38.0\ngrow_horizontal = 0\ngrow_vertical = 0\ntheme_override_constants/margin_right = -10\ntheme_override_constants/margin_bottom = -10\n\n[node name=\"AspectRatioContainer\" type=\"AspectRatioContainer\" parent=\"MarginContainer2\"]\nlayout_mode = 2\n\n[node name=\"LevelLabel\" type=\"Label\" parent=\"MarginContainer2/AspectRatioContainer\"]\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_vertical = 1\ntheme_type_variation = &\"CounterLabel\"\ntext = \"0\"\nhorizontal_alignment = 1\nvertical_alignment = 2\n"
  },
  {
    "path": "src/ui/buttons/empty_unit_button.gd",
    "content": "class_name EmptyUnitButton\nextends Button\n\n\nstatic func make() -> EmptyUnitButton:\n\treturn Preloads.empty_slot_button_scene.instantiate()\n"
  },
  {
    "path": "src/ui/buttons/empty_unit_button.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8xsklkw4jhlw\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_lv050\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/empty_unit_button.gd\" id=\"2_0vien\"]\n\n\n[node name=\"EmptyUnitButton\" type=\"Button\"]\ncustom_minimum_size = Vector2(120, 120)\nfocus_mode = 0\nmouse_filter = 1\ntheme = ExtResource(\"1_lv050\")\ntheme_type_variation = &\"EmptySlot\"\nscript = ExtResource(\"2_0vien\")\n"
  },
  {
    "path": "src/ui/buttons/freshness_indicator.gd",
    "content": "@tool\nclass_name FreshnessIndicator extends Control\n\n\n# Displays two moving particles around the border of an item\n# button. Used to indicate when an item is \"fresh\", meaning\n# that it just dropped. Using two particles so it looks\n# different from auto mode indicator which has 4 particles.\n\n\n@export var _particle_1: CPUParticles2D\n@export var _particle_2: CPUParticles2D\n\t\n@onready var _particle_list: Array[CPUParticles2D] = [\n\t_particle_1,\n\t_particle_2,\n]\n\n\nfunc _process(_delta: float):\n\tif !visible:\n\t\treturn\n\t\n\tAutoModeIndicator.update_border_particles(self, _particle_list, 0.5)\n"
  },
  {
    "path": "src/ui/buttons/freshness_indicator.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://dpsfkaoappjpe\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://ce6k2v2g5l88d\" path=\"res://assets/misc/autocast_automode_particle.png\" id=\"1_ke6i2\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/freshness_indicator.gd\" id=\"1_t5wvv\"]\n\n[sub_resource type=\"Curve\" id=\"Curve_fdccb\"]\n_data = [Vector2(0, 0.663158), 0.0, 0.0, 0, 0, Vector2(0.911227, 0.294737), 0.0, 0.0, 0, 0]\npoint_count = 2\n\n[sub_resource type=\"Gradient\" id=\"Gradient_crf6a\"]\ncolors = PackedColorArray(1, 1, 1, 0.784314, 1, 1, 1, 0.392157)\n\n[sub_resource type=\"Curve\" id=\"Curve_umuqf\"]\n_data = [Vector2(0, 0.663158), 0.0, 0.0, 0, 0, Vector2(0.911227, 0.294737), 0.0, 0.0, 0, 0]\npoint_count = 2\n\n[sub_resource type=\"Gradient\" id=\"Gradient_wp2cn\"]\ncolors = PackedColorArray(1, 1, 1, 0.784314, 1, 1, 1, 0.392157)\n\n[node name=\"FreshnessIndicator\" type=\"Control\" node_paths=PackedStringArray(\"_particle_1\", \"_particle_2\")]\nlayout_mode = 3\nanchors_preset = 0\noffset_right = 80.0\noffset_bottom = 80.0\nmouse_filter = 2\nscript = ExtResource(\"1_t5wvv\")\n_particle_1 = NodePath(\"CPUParticles2D\")\n_particle_2 = NodePath(\"CPUParticles2D2\")\n\n[node name=\"CPUParticles2D\" type=\"CPUParticles2D\" parent=\".\"]\nposition = Vector2(80, 23.8398)\namount = 32\nlifetime = 0.6\nrandomness = 1.0\nlifetime_randomness = 0.2\ntexture = ExtResource(\"1_ke6i2\")\ngravity = Vector2(0, 0)\nscale_amount_curve = SubResource(\"Curve_fdccb\")\ncolor_ramp = SubResource(\"Gradient_crf6a\")\n\n[node name=\"CPUParticles2D2\" type=\"CPUParticles2D\" parent=\".\"]\nposition = Vector2(2.16116e-06, 18.8938)\namount = 32\nlifetime = 0.6\nrandomness = 1.0\nlifetime_randomness = 0.2\ntexture = ExtResource(\"1_ke6i2\")\ngravity = Vector2(0, 0)\nscale_amount_curve = SubResource(\"Curve_umuqf\")\ncolor_ramp = SubResource(\"Gradient_wp2cn\")\n"
  },
  {
    "path": "src/ui/buttons/inventory_slot_button.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://fwj77pscccxg\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_t0n1x\"]\n\n[node name=\"InventorySlotButton\" type=\"Button\"]\ncustom_minimum_size = Vector2(88, 88)\nfocus_mode = 0\ntheme = ExtResource(\"1_t0n1x\")\ntheme_type_variation = &\"TinyUnitButton\"\n"
  },
  {
    "path": "src/ui/buttons/item_button.gd",
    "content": "class_name ItemButton\nextends Button\n\n\nsignal right_clicked()\nsignal shift_right_clicked()\nsignal ctrl_right_clicked()\nsignal horadric_lock_changed()\n\n\nvar _item: Item = null\nvar _tooltip_location: ButtonTooltip.Location = ButtonTooltip.Location.TOP\nvar _show_charges: bool = false\nvar _horadric_lock_display_is_enabled: bool = false\n\n\n@export var _rarity_background: RarityBackground\n@export var _time_indicator: TimeIndicator\n@export var _auto_mode_indicator: AutoModeIndicator\n@export var _freshness_indicator: FreshnessIndicator\n@export var _charges_label: Label\n@export var _lock_indicator: TextureRect\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_set_item_internal(null)\n\n\nfunc _gui_input(event):\n\tif _item == null:\n\t\treturn\n\n\tvar pressed_right_click: bool = event.is_action_released(\"right_click\")\n\tvar pressed_shift: bool = Input.is_action_pressed(\"shift\")\n\tvar pressed_ctrl: bool = Input.is_action_pressed(\"ctrl\")\n\tvar shift_right_click: bool = pressed_shift && pressed_right_click\n\tvar ctrl_right_click: bool = pressed_ctrl && pressed_right_click\n\n\tif shift_right_click:\n\t\tshift_right_clicked.emit()\n\telif ctrl_right_click:\n\t\tctrl_right_clicked.emit()\n\telif pressed_right_click:\n\t\tright_clicked.emit()\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: button becomes transparent if item is null\nfunc set_item(item: Item):\n\tvar item_changed: bool = item != _item\n\n\tif item_changed:\n\t\t_set_item_internal(item)\n\n\nfunc setup_button_for_encyclopedia(item_id: int):\n\t_setup_button_appearance(item_id)\n\n#\tNOTE: need to change module because _ready() sets it to\n#\tTRANSPARENT when item is null. Item is null for buttons\n#\tin Encyclopedia.\n\tmodulate = Color.WHITE\n\t\n#\tNOTE: can't use set_horadric_lock_visible() here because\n#\tit can only be used before _ready()\n\t_lock_indicator.visible = false\n\t\n\tcustom_minimum_size = Vector2(120, 120)\n\n\n# NOTE: need this because ItemButtons should display\n# horadric lock only when they are in item stash. Not in\n# tower inventory or horadric stash.\nfunc set_horadric_lock_visible(value: bool):\n\t_horadric_lock_display_is_enabled = value\n\n\nfunc set_cooldown_indicator_visible(value: bool):\n\t_time_indicator.visible = value\n\n\nfunc set_auto_mode_indicator_visible(value: bool):\n\t_auto_mode_indicator.visible = value\n\n\nfunc set_charges_visible(value: bool):\n\t_show_charges = value\n\n\nfunc get_item() -> Item:\n\treturn _item\n\n\nfunc set_tooltip_location(value: ButtonTooltip.Location):\n\t_tooltip_location = value\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _setup_button_appearance(item_id: int):\n\tvar item_icon: Texture2D = ItemProperties.get_icon(item_id)\n\tset_button_icon(item_icon)\n\t\n\tvar item_rarity: Rarity.enm = ItemProperties.get_rarity(item_id)\n\t_rarity_background.set_rarity(item_rarity)\n\n\n# NOTE: need this sub f-n to be able to set initial item to\n# null. set_item() only executes if item changed and\n# null->null is detected as no change.\nfunc _set_item_internal(item: Item):\n\tvar prev_item: Item = _item\n\n\t_item = item\n\n\tvar button_color: Color\n\tif item != null:\n\t\tbutton_color = Color.WHITE\n\telse:\n\t\tbutton_color = Color.TRANSPARENT\n\tmodulate = button_color\n\n\tif item != null:\n\t\tvar item_id: int = _item.get_id()\n\t\t_setup_button_appearance(item_id)\n\n\tvar autocast: Autocast\n\tif item != null:\n\t\tautocast = _item.get_autocast()\n\telse:\n\t\tautocast = null\n\n\t_time_indicator.set_autocast(autocast)\n\t_auto_mode_indicator.set_autocast(autocast)\n\n\tif prev_item != null:\n\t\tprev_item.charges_changed.disconnect(_on_item_charges_changed)\n\t\tprev_item.horadric_lock_changed.disconnect(_on_item_horadric_lock_changed)\n\t\tprev_item.freshness_changed.disconnect(_on_item_freshness_changed)\n\n\tif item != null:\n\t\t_item.charges_changed.connect(_on_item_charges_changed)\n\t\t_on_item_charges_changed()\n\n\t\t_item.horadric_lock_changed.connect(_on_item_horadric_lock_changed)\n\t\t_on_item_horadric_lock_changed()\n\t\t\n\t\t_item.freshness_changed.connect(_on_item_freshness_changed)\n\t\t_on_item_freshness_changed()\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_mouse_entered():\n\tif _item == null:\n\t\treturn\n\n\tvar tooltip: String = RichTexts.get_item_text(_item)\n\tButtonTooltip.show_tooltip(self, tooltip, _tooltip_location)\n\n\t_item.set_is_fresh(false)\n\n\nfunc _on_item_charges_changed():\n\tif _item == null:\n\t\treturn\n\t\n\tvar charges_count: int = _item.get_charges()\n\tvar charges_text: String = str(charges_count)\n\t_charges_label.set_text(charges_text)\n\n\tvar charges_should_be_visible: bool = _item.uses_charges() && _show_charges\n\t_charges_label.set_visible(charges_should_be_visible)\n\n\nfunc _on_item_horadric_lock_changed():\n\tif _item == null:\n\t\treturn\n\t\n\tvar horadric_lock_is_enabled: bool = _item.get_horadric_lock_is_enabled()\n\t_lock_indicator.visible = _horadric_lock_display_is_enabled && horadric_lock_is_enabled\n\n\thoradric_lock_changed.emit()\n\n\nfunc _on_item_freshness_changed():\n\tif _item == null:\n\t\treturn\n\t\n\tvar item_is_fresh: bool = _item.get_is_fresh()\n\t_freshness_indicator.visible = item_is_fresh\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make() -> ItemButton:\n\tvar item_button: ItemButton = Preloads.item_button_scene.instantiate()\n\n\treturn item_button\n"
  },
  {
    "path": "src/ui/buttons/item_button.tscn",
    "content": "[gd_scene load_steps=9 format=3 uid=\"uid://cj8l153f630bb\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_hwmts\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bbax2xlr25ajb\" path=\"res://resources/icons/mechanical/compass.tres\" id=\"2_4ao5v\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8mjwtvwfpjf5\" path=\"res://src/ui/buttons/rarity_background.tscn\" id=\"2_byhor\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/item_button.gd\" id=\"3_if4ie\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://d1i5vdh8yrhbx\" path=\"res://src/ui/buttons/time_indicator.tscn\" id=\"4_xna04\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dpsfkaoappjpe\" path=\"res://src/ui/buttons/freshness_indicator.tscn\" id=\"5_mfbh4\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bovo5mbv22jly\" path=\"res://src/ui/buttons/auto_mode_indicator.tscn\" id=\"6_8tjm3\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bya4q121hruh1\" path=\"res://resources/ui_textures/unit_button_disabled.tres\" id=\"7_1ary0\"]\n\n\n[node name=\"ItemButton\" type=\"Button\" node_paths=PackedStringArray(\"_rarity_background\", \"_time_indicator\", \"_auto_mode_indicator\", \"_freshness_indicator\", \"_charges_label\", \"_lock_indicator\")]\ncustom_minimum_size = Vector2(80, 80)\nfocus_mode = 0\ntheme = ExtResource(\"1_hwmts\")\ntheme_type_variation = &\"TinyUnitButton\"\nicon = ExtResource(\"2_4ao5v\")\nicon_alignment = 1\nexpand_icon = true\nscript = ExtResource(\"3_if4ie\")\n_rarity_background = NodePath(\"RarityBackground\")\n_time_indicator = NodePath(\"TimeIndicator\")\n_auto_mode_indicator = NodePath(\"MarginContainer/AutoModeIndicator\")\n_freshness_indicator = NodePath(\"FreshnessIndicator\")\n_charges_label = NodePath(\"AspectRatioContainer/ChargesLabel\")\n_lock_indicator = NodePath(\"AspectRatioContainer2/LockIndicator\")\n\n[node name=\"RarityBackground\" parent=\".\" instance=ExtResource(\"2_byhor\")]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"TimeIndicator\" parent=\".\" instance=ExtResource(\"4_xna04\")]\nvisible = false\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"FreshnessIndicator\" parent=\".\" instance=ExtResource(\"5_mfbh4\")]\nvisible = false\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_filter = 2\ntheme_override_constants/margin_left = 2\ntheme_override_constants/margin_top = 2\ntheme_override_constants/margin_right = 2\ntheme_override_constants/margin_bottom = 2\n\n[node name=\"AutoModeIndicator\" parent=\"MarginContainer\" instance=ExtResource(\"6_8tjm3\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"AspectRatioContainer\" type=\"AspectRatioContainer\" parent=\".\"]\nlayout_mode = 0\noffset_right = 40.0\noffset_bottom = 40.0\nscale = Vector2(0.8, 0.8)\nmouse_filter = 2\n\n[node name=\"ChargesLabel\" type=\"Label\" parent=\"AspectRatioContainer\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"CounterLabel\"\ntheme_override_font_sizes/font_size = 16\ntext = \"1\"\n\n[node name=\"AspectRatioContainer2\" type=\"AspectRatioContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 2\nanchor_top = 1.0\nanchor_bottom = 1.0\noffset_top = -30.0\noffset_right = 30.0\ngrow_vertical = 0\nmouse_filter = 2\n\n[node name=\"LockIndicator\" type=\"TextureRect\" parent=\"AspectRatioContainer2\"]\nz_index = 1\ncustom_minimum_size = Vector2(30, 30)\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntexture = ExtResource(\"7_1ary0\")\nexpand_mode = 2\n\n[connection signal=\"mouse_entered\" from=\".\" to=\".\" method=\"_on_mouse_entered\"]\n"
  },
  {
    "path": "src/ui/buttons/item_button_inner.gd",
    "content": "extends TextureButton\n\n\n# Need this script to reroute shift right click event into a\n# signal. Can't place _gui_input() in ItemButton.gd\n# because root node of ItemButton is a Margin\n# Container not the button itself.\n\n\nsignal right_clicked()\n\n\nfunc _gui_input(event):\n\tvar pressed_right_click: bool = event.is_action_released(\"right_click\")\n\n\tif pressed_right_click:\n\t\tright_clicked.emit()\n"
  },
  {
    "path": "src/ui/buttons/menu_expanding_button.gd",
    "content": "class_name MenuExpandingButton extends Button\n\n\n# This button is used to toggle a menu on and off. When used\n# as a group of buttons, they can toggle one menu at a time.\n# When a menu is open, this button shows a rectangle between\n# the button and the menu - to visually connect the two UI\n# elements.\n\n\n# NOTE: set the \"_menu\" variable to the menu which this\n# button should toggle\n@export var _menu: Control\n@export var _panel: PanelContainer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_menu.hidden.connect(_on_menu_hidden)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_toggled(button_is_pressed: bool):\n\t_panel.visible = button_is_pressed\n\t_menu.visible = button_is_pressed\n\n\nfunc _on_menu_hidden():\n\tset_pressed(false)\n"
  },
  {
    "path": "src/ui/buttons/menu_expanding_button.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://dwexxkjguqohm\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_r701g\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://r7qkt7vep0ar\" path=\"res://resources/icons/hud/tower_stash.tres\" id=\"2_7h80o\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/menu_expanding_button.gd\" id=\"3_cmnlx\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"4_3y845\"]\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_ebngv\"]\ncontent_margin_left = 10.0\ncontent_margin_right = 50.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"4_3y845\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 154)\nmodulate_color = Color(1, 1, 1, 0.784314)\n\n[node name=\"MenuExpandingButton\" type=\"Button\" node_paths=PackedStringArray(\"_panel\")]\ncustom_minimum_size = Vector2(100, 100)\nfocus_mode = 0\ntheme = ExtResource(\"1_r701g\")\ntheme_type_variation = &\"BigCircleButton\"\ntheme_override_constants/icon_max_width = 90\ntoggle_mode = true\nicon = ExtResource(\"2_7h80o\")\nicon_alignment = 1\nexpand_icon = true\nscript = ExtResource(\"3_cmnlx\")\n_panel = NodePath(\"MarginContainer/PanelContainer\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_direction = 3\nlayout_mode = 0\noffset_right = 40.0\noffset_bottom = 40.0\nmouse_filter = 2\ntheme_override_constants/margin_right = 50\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"MarginContainer\"]\nvisible = false\nz_index = -1\ncustom_minimum_size = Vector2(200, 100)\nlayout_direction = 3\nlayout_mode = 2\nmouse_filter = 2\ntheme = ExtResource(\"1_r701g\")\ntheme_override_styles/panel = SubResource(\"StyleBoxTexture_ebngv\")\n\n[connection signal=\"toggled\" from=\".\" to=\".\" method=\"_on_toggled\"]\n"
  },
  {
    "path": "src/ui/buttons/rarity_background.gd",
    "content": "class_name RarityBackground extends PanelContainer\n\n\n# Used in button scenes to indicate rarity.\n\n\nfunc set_rarity(rarity: Rarity.enm):\n\tvar theme_type_variation_name: String\n\tmatch rarity:\n\t\tRarity.enm.COMMON:\n\t\t\ttheme_type_variation_name = \"CommonRarityPanelContainer\"\n\t\tRarity.enm.UNCOMMON:\n\t\t\ttheme_type_variation_name = \"UncommonRarityPanelContainer\"\n\t\tRarity.enm.RARE:\n\t\t\ttheme_type_variation_name = \"RareRarityPanelContainer\"\n\t\tRarity.enm.UNIQUE:\n\t\t\ttheme_type_variation_name = \"UniqueRarityPanelContainer\"\n\t\t_:\n\t\t\ttheme_type_variation_name = \"\"\n\t\n\ttheme_type_variation = theme_type_variation_name\n"
  },
  {
    "path": "src/ui/buttons/rarity_background.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8mjwtvwfpjf5\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_h8l7j\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/rarity_background.gd\" id=\"2_6a5cr\"]\n\n\n[node name=\"RarityBackground\" type=\"PanelContainer\"]\nshow_behind_parent = true\noffset_right = 100.0\noffset_bottom = 100.0\nmouse_filter = 2\ntheme = ExtResource(\"1_h8l7j\")\ntheme_type_variation = &\"CommonRarityPanelContainer\"\nscript = ExtResource(\"2_6a5cr\")\n"
  },
  {
    "path": "src/ui/buttons/recipe_button.gd",
    "content": "class_name RecipeButton extends Button\n\n@export var recipe: HoradricCube.Recipe\n\n\nfunc _ready():\n\tvar recipe_description: String = RecipeProperties.get_description(recipe)\n\tset_tooltip_text(recipe_description)\n\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n"
  },
  {
    "path": "src/ui/buttons/recipe_button.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://c1ccsqvpyqd4i\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/recipe_button.gd\" id=\"1_3j7jj\"]\n\n[node name=\"RecipeButton\" type=\"Button\" groups=[\"recipe_buttons\"]]\nfocus_mode = 0\ntheme_type_variation = &\"TinyUnitButton\"\nexpand_icon = true\nscript = ExtResource(\"1_3j7jj\")\n"
  },
  {
    "path": "src/ui/buttons/speed_button.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://dq1y6eowvvl45\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://c8fri6mdej3gu\" path=\"res://resources/ui_textures/speed_normal.tres\" id=\"1_005ge\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_o2nu2\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_6u40t\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_jh5rr\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_3r3a6\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_3k4s2\"]\n\n[node name=\"speed_button\" type=\"Button\"]\ncustom_minimum_size = Vector2(48, 48)\nfocus_mode = 0\ntheme_override_colors/icon_normal_color = Color(0.6, 0.6, 0.6, 1)\ntheme_override_colors/icon_pressed_color = Color(1, 1, 1, 1)\ntheme_override_colors/icon_hover_color = Color(0.8, 0.8, 0.8, 1)\ntheme_override_styles/normal = SubResource(\"StyleBoxEmpty_o2nu2\")\ntheme_override_styles/hover = SubResource(\"StyleBoxEmpty_6u40t\")\ntheme_override_styles/pressed = SubResource(\"StyleBoxEmpty_jh5rr\")\ntheme_override_styles/disabled = SubResource(\"StyleBoxEmpty_3r3a6\")\ntheme_override_styles/focus = SubResource(\"StyleBoxEmpty_3k4s2\")\ntoggle_mode = true\nicon = ExtResource(\"1_005ge\")\nexpand_icon = true\n"
  },
  {
    "path": "src/ui/buttons/time_indicator.gd",
    "content": "@tool\nclass_name TimeIndicator extends Control\n\n# Displays a rotating shadow polygon over a square area,\n# like a clock hand. Has two styles:\n# - Expanding - shadow starts small and grows as elapsed\n#   time increases until it covers the whole square.\n# - Shrinking - shadow starts full, covering the whole\n#   square, then shrinks until it goes away completely.\n\n\n# NOTE: this angle determines the distance between progress\n# points, in degrees\nconst ANGLE_STEP: int = 5\n\nenum DrawStyle {\n\tEXPANDING,\n\tSHRINKING,\n}\n\n\nstatic var _progress_point_list: Array[Vector2]\nstatic var _center_point: Vector2\nstatic var _top_middle_point: Vector2\nstatic var _top_left_point: Vector2\nstatic var _top_right_point: Vector2\nstatic var _bottom_left_point: Vector2\nstatic var _bottom_right_point: Vector2\n\nvar _autocast: Autocast = null\nvar _progress_in_editor: float = 0.0\nvar _elapsed_progress: float = 0.0\n\n\n@export var overlay_color: Color = Color8(0, 0, 0, 180)\n@export var draw_style: TimeIndicator.DrawStyle = DrawStyle.SHRINKING\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# Setup points once inside static vars and reuse for all\n# instances of TimeIndicator.\n# Pick points on a square, spaced out by angle from\n# center. There is definitely a better way to do this but\n# whatever.\nstatic func _static_init():\n\t_center_point = Vector2(0.5, 0.5)\n\t_top_left_point = Vector2(0.0, 0.0)\n\t_top_middle_point = Vector2(0.5, 0.0)\n\t_top_right_point = Vector2(1.0, 0.0)\n\t_bottom_left_point = Vector2(0.0, 1.0)\n\t_bottom_right_point = Vector2(1.0, 1.0)\n\n#\tGenerate \"progress points\", these points are spread\n#\tevenly along a square perimeter.\n\n\t_progress_point_list.append(_top_middle_point)\n\n# \tFrom top center to top right\n\tfor angle in range(0, 45, ANGLE_STEP):\n\t\tvar x: float = 0.5 + 0.5 * tan(deg_to_rad(angle))\n\t\tvar y: float = 0\n\t\tvar point: Vector2 = Vector2(x, y)\n\t\t_progress_point_list.append(point)\n\n#\tFrom top right to bottom right\n\tfor angle in range(-45, 45, ANGLE_STEP):\n\t\tvar x: float = 1.0\n\t\tvar y: float = 0.5 + 0.5 * tan(deg_to_rad(angle))\n\t\tvar point: Vector2 = Vector2(x, y)\n\t\t_progress_point_list.append(point)\n\n# \tFrom bottom right to bottom left\n\tfor angle in range(-45, 45, ANGLE_STEP):\n\t\tvar x: float = 0.5 - 0.5 * tan(deg_to_rad(angle))\n\t\tvar y: float = 1.0\n\t\tvar point: Vector2 = Vector2(x, y)\n\t\t_progress_point_list.append(point)\n\n#\tFrom bottom left to top left\n\tfor angle in range(-45, 45, ANGLE_STEP):\n\t\tvar x: float = 0.0\n\t\tvar y: float = 0.5 - 0.5 * tan(deg_to_rad(angle))\n\t\tvar point: Vector2 = Vector2(x, y)\n\t\t_progress_point_list.append(point)\n\n# \tFrom top left to top center\n\tfor angle in range(-45, 0, ANGLE_STEP):\n\t\tvar x: float = 0.5 + 0.5 * tan(deg_to_rad(angle))\n\t\tvar y: float = 0\n\t\tvar point: Vector2 = Vector2(x, y)\n\t\t_progress_point_list.append(point)\n\n\t_progress_point_list.append(_top_middle_point)\n\n\nfunc _process(_delta: float):\n#\tNOTE: simulate increasing progress for preview in editor\n\tif Engine.is_editor_hint():\n\t\t_progress_in_editor += 0.005\n\t\tif _progress_in_editor > 1.0:\n\t\t\t_progress_in_editor = 0.0\n\n\t\t_elapsed_progress = _progress_in_editor\n\telif _autocast != null && is_instance_valid(_autocast):\n#\t\tPull time values from autocast, if it's defined\n\t\tvar overall_cooldown: float = _autocast.get_cooldown()\n\t\tvar remaining_cooldown: float = _autocast.get_remaining_cooldown()\n\t\tvar elapsed_cooldown: float = overall_cooldown - remaining_cooldown\n\t\tset_time_values(elapsed_cooldown, overall_cooldown)\n\n\tqueue_redraw()\n\n\nfunc _draw():\n\tvar icon_size: float = size.x\n\tvar point_list: PackedVector2Array = TimeIndicator._generate_draw_points(_elapsed_progress, icon_size, draw_style)\n\n\tif point_list.is_empty():\n\t\treturn\n\n\tdraw_colored_polygon(point_list, overlay_color)\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: need to clamp value because one time an autocast\n# somehow had set elapsed time higher than overall time.\n# Couldn't reproduce, try to look into it.\nfunc set_time_values(elapsed_time: float, overall_time: float):\n\t_elapsed_progress = Utils.divide_safe(elapsed_time, overall_time)\n\t_elapsed_progress = clampf(_elapsed_progress, 0.0, 1.0)\n\n\n# NOTE: you can pass an autocast to the indicator and the\n# indicator will automatically pull cooldown values from it.\nfunc set_autocast(autocast: Autocast):\n\t_autocast = autocast\n\t\n#\tNOTE: need to reset time values if there's no autocast\n#\tso that if item was changed, indicator doesn't keep\n#\tshowing time value for previous item. Set item values to\n#\t1/1 (100% progress) so that no time indicator is drawn.\n\tif autocast == null:\n\t\tset_time_values(1.0, 1.0)\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func _generate_draw_points(progress: float, icon_size: float, style: TimeIndicator.DrawStyle) -> PackedVector2Array:\n\tvar current_progress_point: int = floori(progress * (_progress_point_list.size() - 1))\n\tcurrent_progress_point = clampi(current_progress_point, 0, _progress_point_list.size() - 1)\n\tvar progress_point: Vector2 = _progress_point_list[current_progress_point]\n\t\n\tvar point_list: PackedVector2Array = []\n\n#\tPick appropriate corner points, to complete the polygon\n\tmatch style:\n\t\tTimeIndicator.DrawStyle.EXPANDING:\n\t\t\tpoint_list.append(_center_point)\n\t\t\tpoint_list.append(_top_middle_point)\n\n\t\t\tif progress >= 1 / 8.0:\n\t\t\t\tpoint_list.append(_top_right_point)\n\t\t\tif progress >= 3 / 8.0:\n\t\t\t\tpoint_list.append(_bottom_right_point)\n\t\t\tif progress >= 5 / 8.0:\n\t\t\t\tpoint_list.append(_bottom_left_point)\n\t\t\tif progress >= 7 / 8.0:\n\t\t\t\tpoint_list.append(_top_left_point)\n\n\t\t\tpoint_list.append(progress_point)\n\t\tTimeIndicator.DrawStyle.SHRINKING:\n\t\t\tvar remaining_progress: float = 1.0 - progress\n\t\t\t\n\t\t\tpoint_list.append(_center_point)\n\t\t\tpoint_list.append(progress_point)\n\n\t\t\tif remaining_progress >= 7 / 8.0:\n\t\t\t\tpoint_list.append(_top_right_point)\n\t\t\tif remaining_progress >= 5 / 8.0:\n\t\t\t\tpoint_list.append(_bottom_right_point)\n\t\t\tif remaining_progress >= 3 / 8.0:\n\t\t\t\tpoint_list.append(_bottom_left_point)\n\t\t\tif remaining_progress >= 1 / 8.0:\n\t\t\t\tpoint_list.append(_top_left_point)\n\t\n\t\t\tpoint_list.append(_top_middle_point)\n\n#\tScale all points so that they match the icon size\n\tfor i in point_list.size():\n\t\tpoint_list[i] *= icon_size\n\t\n\treturn point_list\n"
  },
  {
    "path": "src/ui/buttons/time_indicator.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://d1i5vdh8yrhbx\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/time_indicator.gd\" id=\"1_wuiti\"]\n\n[node name=\"TimeIndicator\" type=\"Control\"]\nlayout_mode = 3\nanchors_preset = 0\noffset_right = 64.0\noffset_bottom = 64.0\nmouse_filter = 1\nscript = ExtResource(\"1_wuiti\")\n"
  },
  {
    "path": "src/ui/buttons/tower_button.gd",
    "content": "class_name TowerButton\nextends Button\n\nvar _tower_id: int = 1\nvar _tooltip_is_enabled: bool = true\n\n@export var _disabled_lock: TextureRect\n@export var _tier_icon: TextureRect\n@export var _freshness_timer: Timer\n@export var _freshness_indicator: FreshnessIndicator\n@export var _rarity_background: RarityBackground\n@export var _counter_label: Label\n\n@export var _tooltip_location: ButtonTooltip.Location\n@export var _show_freshness: bool = true\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tset_locked(false)\n\n\tif _show_freshness:\n\t\t_freshness_timer.start()\n\t\t\n\t\tif !visible:\n\t\t\t_freshness_timer.pause()\n\t\t\n\t\t_freshness_indicator.show()\n\t\t\n\t\tvar game_mode_is_build: bool = Globals.get_game_mode() == GameMode.enm.BUILD\n\t\tif game_mode_is_build:\n\t\t\t_freshness_indicator.hide()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc hide_freshness_indicator():\n\tif is_inside_tree():\n\t\t_freshness_indicator.visible = false\n\telse:\n\t\t_show_freshness = false\n\n\nfunc set_tooltip_is_enabled(value: bool):\n\t_tooltip_is_enabled = value\n\n\nfunc get_tower_id() -> int:\n\treturn _tower_id\n\n\n# NOTE: must be called after button is added to parent\nfunc set_tower_id(tower_id: int):\n\t_tower_id = tower_id\n\n\tvar rarity: Rarity.enm = TowerProperties.get_rarity(tower_id)\n\t_rarity_background.set_rarity(rarity)\n\t\n\tvar tower_icon: Texture2D = TowerProperties.get_icon(tower_id)\n\tset_button_icon(tower_icon)\n\t\n\tvar tier_icon: Texture2D = UnitIcons.get_tower_tier_icon(tower_id)\n\t_tier_icon.texture = tier_icon\n\n\nfunc set_tier_visible(value: bool):\n\t_tier_icon.visible = value\n\n\nfunc set_locked(value: bool):\n\t_disabled_lock.visible = value\n\tdisabled = value\n\n\nfunc set_count(count: int):\n\t_counter_label.text = str(count)\n\t_counter_label.visible = count > 1\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_mouse_entered():\n\tif !_tooltip_is_enabled:\n\t\treturn\n\t\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar tooltip: String = RichTexts.get_tower_text(_tower_id, local_player)\n\tButtonTooltip.show_tooltip(self, tooltip, _tooltip_location)\n\t\n\t_freshness_indicator.hide()\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make():\n\tvar tower_button: TowerButton = Preloads.tower_button_scene.instantiate()\n\treturn tower_button\n\n\n# Pause freshness timer while button is not visible\nfunc _on_visibility_changed():\n\tif _freshness_timer.is_stopped():\n\t\treturn\n\t\n\t_freshness_timer.set_paused(!visible)\n\n\nfunc _on_freshness_timer_timeout():\n\t_freshness_indicator.hide()\n"
  },
  {
    "path": "src/ui/buttons/tower_button.tscn",
    "content": "[gd_scene load_steps=9 format=3 uid=\"uid://ni34yd5liwbj\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_gjufa\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b0cvl7ota8rxq\" path=\"res://resources/icons/tower_icons/lesser_iron_defender.tres\" id=\"2_5y7kf\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8mjwtvwfpjf5\" path=\"res://src/ui/buttons/rarity_background.tscn\" id=\"2_sd6cs\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/tower_button.gd\" id=\"3_ht2cb\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bxlxlgnldo7ci\" path=\"res://assets/icons/tier_icons_m.png\" id=\"3_n04co\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bya4q121hruh1\" path=\"res://resources/ui_textures/unit_button_disabled.tres\" id=\"4_kwp58\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dpsfkaoappjpe\" path=\"res://src/ui/buttons/freshness_indicator.tscn\" id=\"5_tame2\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_80ypy\"]\natlas = ExtResource(\"3_n04co\")\nregion = Rect2(0, 0, 64, 64)\n\n[node name=\"TowerButton\" type=\"Button\" node_paths=PackedStringArray(\"_disabled_lock\", \"_tier_icon\", \"_freshness_timer\", \"_freshness_indicator\", \"_rarity_background\", \"_counter_label\")]\ncustom_minimum_size = Vector2(120, 120)\nfocus_mode = 0\ntheme = ExtResource(\"1_gjufa\")\ntheme_type_variation = &\"UnitButton\"\nicon = ExtResource(\"2_5y7kf\")\nicon_alignment = 1\nexpand_icon = true\nscript = ExtResource(\"3_ht2cb\")\n_disabled_lock = NodePath(\"LockTexture\")\n_tier_icon = NodePath(\"TierContainer/TierIcon\")\n_freshness_timer = NodePath(\"FreshnessTimer\")\n_freshness_indicator = NodePath(\"MarginContainer3/FreshnessIndicator\")\n_rarity_background = NodePath(\"RarityBackground\")\n_counter_label = NodePath(\"MarginContainer2/AspectRatioContainer/CounterLabel\")\n\n[node name=\"RarityBackground\" parent=\".\" instance=ExtResource(\"2_sd6cs\")]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"TierContainer\" type=\"MarginContainer\" parent=\".\"]\nz_index = 1\nlayout_mode = 1\nanchors_preset = 1\nanchor_left = 1.0\nanchor_right = 1.0\noffset_left = -43.0\noffset_bottom = 43.0\ngrow_horizontal = 0\ntheme_override_constants/margin_top = -15\ntheme_override_constants/margin_right = -15\n\n[node name=\"TierIcon\" type=\"TextureRect\" parent=\"TierContainer\"]\nvisible = false\ncustom_minimum_size = Vector2(50, 50)\nlayout_mode = 2\ntexture = SubResource(\"AtlasTexture_80ypy\")\nexpand_mode = 1\nstretch_mode = 4\n\n[node name=\"LockTexture\" type=\"TextureRect\" parent=\".\"]\nvisible = false\nz_index = 1\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntexture = ExtResource(\"4_kwp58\")\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme_override_constants/margin_left = 5\ntheme_override_constants/margin_top = 5\ntheme_override_constants/margin_right = 5\ntheme_override_constants/margin_bottom = 5\n\n[node name=\"FreshnessIndicator\" parent=\"MarginContainer3\" instance=ExtResource(\"5_tame2\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\".\"]\nz_index = 1\nlayout_mode = 1\nanchors_preset = 3\nanchor_left = 1.0\nanchor_top = 1.0\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_left = -38.0\noffset_top = -38.0\ngrow_horizontal = 0\ngrow_vertical = 0\ntheme_override_constants/margin_right = -10\ntheme_override_constants/margin_bottom = -10\n\n[node name=\"AspectRatioContainer\" type=\"AspectRatioContainer\" parent=\"MarginContainer2\"]\nlayout_mode = 2\n\n[node name=\"CounterLabel\" type=\"Label\" parent=\"MarginContainer2/AspectRatioContainer\"]\nvisible = false\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_vertical = 1\ntheme_type_variation = &\"CounterLabel\"\ntext = \"1\"\nhorizontal_alignment = 1\nvertical_alignment = 2\n\n[node name=\"FreshnessTimer\" type=\"Timer\" parent=\".\"]\nwait_time = 7.0\none_shot = true\n\n[connection signal=\"mouse_entered\" from=\".\" to=\".\" method=\"_on_mouse_entered\"]\n[connection signal=\"visibility_changed\" from=\".\" to=\".\" method=\"_on_visibility_changed\"]\n[connection signal=\"timeout\" from=\"FreshnessTimer\" to=\".\" method=\"_on_freshness_timer_timeout\"]\n"
  },
  {
    "path": "src/ui/buttons/wisdom_upgrade_button.gd",
    "content": "class_name WisdomUpgradeButton extends Button\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_upgrade_used_status(value: bool):\n\tif value:\n\t\tmodulate = Color.WHITE\n\telse:\n\t\tmodulate = Color(0.3, 0.3, 0.3, 1.0)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(upgrade_id: int ) -> WisdomUpgradeButton:\n\tvar scene: PackedScene = load(\"res://src/ui/buttons/wisdom_upgrade_button.tscn\")\n\tvar button: WisdomUpgradeButton = scene.instantiate()\n\t\n\tvar tooltip: String = WisdomUpgradeProperties.get_tooltip(upgrade_id)\n\tbutton.set_tooltip_text(tooltip)\n\n\tvar icon_path: String = WisdomUpgradeProperties.get_icon_path(upgrade_id)\n\tvar icon_exists: bool = ResourceLoader.exists(icon_path)\n\tif icon_exists:\n\t\tbutton.icon = load(icon_path)\n\n\treturn button\n"
  },
  {
    "path": "src/ui/buttons/wisdom_upgrade_button.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://5rnrbjr6xx64\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://cdqtd51r814ka\" path=\"res://resources/icons/generic_icons/egg.tres\" id=\"1_kndti\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_vwwoe\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/buttons/wisdom_upgrade_button.gd\" id=\"2_ra3be\"]\n\n\n[node name=\"WisdomUpgradeButton\" type=\"Button\"]\noffset_right = 64.0\noffset_bottom = 64.0\nfocus_mode = 0\ntheme = ExtResource(\"1_vwwoe\")\ntheme_type_variation = &\"UnitButton\"\nicon = ExtResource(\"1_kndti\")\nscript = ExtResource(\"2_ra3be\")\n"
  },
  {
    "path": "src/ui/dev_controls/dev_controls.gd",
    "content": "extends Control\n\n\n@onready var dev_control_buttons = get_tree().get_nodes_in_group(\"dev_control_button\")\n@onready var dev_controls = get_tree().get_nodes_in_group(\"dev_control\")\n@export var positional_control: PopupMenu\n@onready var oil_ids: Array = []\n@onready var item_ids: Array = []\n@export var position_info_label: Label\n\nfunc _ready():\n\tfor dev_control in dev_controls:\n\t\tdev_control.close_requested.connect(func (): dev_control.hide())\n\t\n\tfor dev_control_button in dev_control_buttons:\n\t\tdev_control_button.button_up.connect(_on_DevControlButton_button_up.bind(dev_control_button))\n\t\n\tposition_info_label.visible = Config.show_position_info_label()\n\t\n\t_init_oils_and_items_controls()\n\n\nfunc _process(_delta: float):\n\tposition_info_label.position = get_global_mouse_position()\n\tvar accumulated_info = {}\n\taccumulated_info[\"global_mouse_position\"] = get_global_mouse_position()\n\taccumulated_info[\"snap_canvas_pos_to_buildable_pos\"] = VectorUtils.snap_canvas_pos_to_buildable_pos(position_info_label.position)\n\tposition_info_label.text = _dict_join(accumulated_info)\n\n\nfunc _dict_join(accumulated_info: Dictionary, separator = \"\\n\") -> String:\n\tvar output = \"\";\n\tfor pos_type in accumulated_info.keys():\n\t\toutput += \"%s %s%s\" % [pos_type, accumulated_info[pos_type], separator]\n\toutput = output.left( output.length() - separator.length() )\n\treturn output\n\n\nfunc _init_oils_and_items_controls():\n\tvar regular_type_string: String = ItemType.convert_to_string(ItemType.enm.REGULAR)\n\tvar oil_type_string: String = ItemType.convert_to_string(ItemType.enm.OIL)\n\toil_ids = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, oil_type_string)\n\titem_ids = ItemProperties.get_id_list_by_filter(ItemProperties.CsvProperty.TYPE, regular_type_string)\n\t\n\tassert(oil_ids.size() > 0 && item_ids.size() > 0, \\\n\t\"Data file for items and oils probably has been updated.\")\n\t\n\tvar oil_submenu = PopupMenu.new()\n\toil_submenu.set_name(\"oil_submenu\")\n\tpositional_control.add_child(oil_submenu)\n\t\n\tvar item_submenu = PopupMenu.new()\n\titem_submenu.set_name(\"item_submenu\")\n\tpositional_control.add_child(item_submenu)\n\t\n\tfor oil_id in oil_ids:\n\t\tvar oil_name = ItemProperties.get_display_name(oil_id)\n\t\toil_submenu.add_item(oil_name, oil_id)\n\t\n\tfor item_id in item_ids:\n\t\tvar item_name = ItemProperties.get_display_name(item_id)\n\t\titem_submenu.add_item(item_name, item_id)\n\t\n\tpositional_control.add_submenu_item(\"Spawn Oil\", \"oil_submenu\")\n\tpositional_control.add_submenu_item(\"Spawn Item\", \"item_submenu\")\n\toil_submenu.id_pressed.connect(_on_PositionalControl_id_pressed)\n\titem_submenu.id_pressed.connect(_on_PositionalControl_id_pressed)\n\n\nfunc _unhandled_input(event):\n\tif event is InputEventMouse:\n\t\tvar right_click: bool = event.is_action_released(\"right_click\")\n\t\tif right_click:\n\t\t\tpositional_control.show()\n\t\t\tpositional_control.position = event.position\n\t\telse:\n\t\t\tpositional_control.hide()\n\nfunc _on_DevControlButton_button_up(button: Button):\n\tvar control_name = button.get_name().replace(\"Button\", \"\")\n\tfor dev_control in dev_controls:\n\t\tif dev_control.get_name() == control_name:\n\t\t\tdev_control.show()\n\t\t\tbreak\n\nfunc _on_PositionalControl_id_pressed(id):\n\tif oil_ids.has(id) or item_ids.has(id):\n\t\tvar clicked_pos: Vector2 = positional_control.position\n\t\tvar hud_to_world: Transform2D = get_viewport().get_canvas_transform().affine_inverse()\n\t\tvar clicked_pos_in_world: Vector2 = hud_to_world * clicked_pos\n\t\tvar local_player: Player = PlayerManager.get_local_player()\n\t\tvar item_pos_wc3_2d: Vector2 = VectorUtils.canvas_to_wc3_2d(clicked_pos_in_world)\n\t\tvar item_pos_wc3: Vector3 = Vector3(item_pos_wc3_2d.x, item_pos_wc3_2d.y, 0)\n\t\tvar item: Item = Item.create(local_player, id, item_pos_wc3)\n\t\titem.fly_to_stash(0.0)\n"
  },
  {
    "path": "src/ui/dev_controls/dev_controls.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cro8ec573upqo\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/dev_controls/dev_controls.gd\" id=\"1_0jdrl\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bsu2i4smjlpui\" path=\"res://src/ui/dev_controls/wave_control.tscn\" id=\"2_455wo\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cojr80363rwx2\" path=\"res://src/ui/dev_controls/signals_control.tscn\" id=\"3_esahe\"]\n\n\n[node name=\"DevControls\" type=\"Control\" node_paths=PackedStringArray(\"positional_control\", \"position_info_label\")]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_filter = 1\nscript = ExtResource(\"1_0jdrl\")\npositional_control = NodePath(\"PositionalControl\")\nposition_info_label = NodePath(\"PositionInfoLabel\")\n\n[node name=\"WaveControl\" type=\"Window\" parent=\".\" groups=[\"dev_control\"]]\ntransparent_bg = true\ntitle = \"Wave Control\"\nposition = Vector2i(100, 100)\nsize = Vector2i(1000, 500)\nvisible = false\nwrap_controls = true\npopup_window = true\n\n[node name=\"WaveControl\" parent=\"WaveControl\" instance=ExtResource(\"2_455wo\")]\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"SignalsControl\" type=\"Window\" parent=\".\" groups=[\"dev_control\"]]\ntransparent_bg = true\ntitle = \"Signals Control\"\nposition = Vector2i(100, 100)\nsize = Vector2i(1000, 500)\nvisible = false\nwrap_controls = true\npopup_window = true\n\n[node name=\"SignalsControl\" parent=\"SignalsControl\" instance=ExtResource(\"3_esahe\")]\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 2\nanchor_top = 1.0\nanchor_bottom = 1.0\noffset_top = -96.0\noffset_right = 428.0\ngrow_vertical = 0\nmouse_filter = 0\n\n[node name=\"DevControlButtons\" type=\"GridContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\ncolumns = 10\n\n[node name=\"WaveControlButton\" type=\"Button\" parent=\"MarginContainer/DevControlButtons\" groups=[\"dev_control_button\"]]\nlayout_mode = 2\ntext = \"Wave\"\nflat = true\n\n[node name=\"TowerControlButton\" type=\"Button\" parent=\"MarginContainer/DevControlButtons\" groups=[\"dev_control_button\"]]\nlayout_mode = 2\ndisabled = true\ntext = \"Tower\"\nflat = true\n\n[node name=\"CreepControlButton\" type=\"Button\" parent=\"MarginContainer/DevControlButtons\" groups=[\"dev_control_button\"]]\nlayout_mode = 2\ndisabled = true\ntext = \"Creep\"\nflat = true\n\n[node name=\"SignalsControlButton\" type=\"Button\" parent=\"MarginContainer/DevControlButtons\" groups=[\"dev_control_button\"]]\nlayout_mode = 2\ntext = \"Signal\"\nflat = true\n\n[node name=\"PositionalControl\" type=\"PopupMenu\" parent=\".\"]\n\n[node name=\"PositionInfoLabel\" type=\"Label\" parent=\".\"]\ntop_level = true\nlayout_mode = 0\noffset_right = 40.0\noffset_bottom = 23.0\nscale = Vector2(0.5, 0.5)\npivot_offset = Vector2(20, 2.08165e-12)\ntheme_override_colors/font_shadow_color = Color(0, 0, 0, 1)\ntext = \"test_position (0, 0)\"\n\n[connection signal=\"id_focused\" from=\"PositionalControl\" to=\".\" method=\"_on_PositionalControl_id_focused\"]\n"
  },
  {
    "path": "src/ui/dev_controls/signals_control.gd",
    "content": "extends Control\n\n\n@onready var debug_enabled = OS.is_debug_build()\n@onready var debug_label: Label = %SignalsTitle\n@onready var debug_signals: GridContainer = %SignalsGrid\n@onready var signal_arg_edit: LineEdit = $SignalArgEdit\n@export var debug_container: VBoxContainer\n\nvar current_node: Node\nvar prev_node: Node\n#var node_selection_blocked: bool = false\nvar acc_delta: float = 0\n\n\nfunc _ready():\n\tif !debug_enabled || !Config.dev_controls_enabled():\n\t\treturn\n\t_connect_all_nodes(get_tree().get_root().get_node(\"GameScene\"))\n\tget_tree().node_added.connect(_on_Node_added)\n#\tdebug_control.gui_input.connect(_on_Gui_input)\n\n\n# Called every frame. 'delta' is the elapsed time since the previous frame.\nfunc _process(delta):\n\tif current_node != prev_node && acc_delta > 1:\n\t\tif current_node == null:\n\t\t\tdebug_container.hide()\n\t\t\tprev_node = current_node\n\t\t\treturn\n\t\t\n\t\tdebug_container.show()\n\t\t\n\t\tvar signal_list = current_node.get_signal_list()\n\t\tfor old_signals in debug_signals.get_children():\n\t\t\told_signals.queue_free()\n\t\t\n\t\tfor i in len(signal_list):\n\t\t\tvar node_signal = signal_list[i]\n\t\t\tvar button = MenuButton.new()\n\t\t\tbutton.name = \"SignalButton\"\n\t\t\tbutton.text = \"%s. %s\" % [i, node_signal.name]\n\t\t\tfor node_signal_arg in signal_list[i][\"args\"]:\n\t\t\t\tbutton.get_popup().add_item(node_signal_arg[\"name\"])\n\t\t\tfor node_signal_arg in signal_list[i][\"default_args\"]:\n\t\t\t\tbutton.get_popup().add_item(node_signal_arg[\"name\"])\n\t\t\tif button.get_popup().item_count == 0:\n\t\t\t\tbutton.get_popup().add_item(\"no-args\")\n\t\t\tbutton.get_popup().id_pressed.connect(_on_SignalButton_pressed.bind(button.get_popup(), current_node, node_signal))\n\t\t\tbutton.pressed.connect(func(): button.get_popup().show())\n\t\t\tdebug_signals.add_child.call_deferred(button)\n\t\tdebug_label.text = \"%s: %s\" % [current_node.get_class(), current_node.name]\n\t\tacc_delta = 0\n\telse: \n\t\tacc_delta += delta\n\tprev_node = current_node\n\n\nfunc _on_DevControlButton_button_up():\n\tshow()\n\n\nfunc _on_SignalButton_pressed(id: int, popup: PopupMenu, node, node_signal):\n\tif popup.get_item_text(id) == \"no-args\":\n\t\tprint_debug(\"Manual signal [%s] was emitted on node [%s] with [no-args].\" % [node_signal[\"name\"], node])\n\t\tnode.emit_signal(node_signal[\"name\"])\n\telse:\n\t\tsignal_arg_edit.show()\n\t\tsignal_arg_edit.clear()\n\t\tsignal_arg_edit.text_submitted.disconnect(_on_SignalArgEdit_submitted)\n\t\tsignal_arg_edit.text_submitted.connect(_on_SignalArgEdit_submitted.bind(popup.get_item_text(id), node, node_signal))\n\n\nfunc _on_SignalArgEdit_submitted(command, arg_name, node, node_signal):\n\tvar expression = Expression.new()\n\tvar error = expression.parse(command)\n\tif error != OK:\n\t\tprint_debug(expression.get_error_text())\n\t\treturn\n\tvar result = expression.execute()\n\t\n\tvar arg\n\tif !expression.has_execute_failed():\n\t\targ = result\n\telse:\n\t\targ = command\n\t\n\tprint_debug(\"Manual signal [%s] was emitted on node [%s] with [%s=%s].\" % [node_signal[\"name\"], node, arg_name, arg])\n\tnode.emit_signal(node_signal[\"name\"], arg)\n\t\n\tsignal_arg_edit.hide()\n\tsignal_arg_edit.clear()\n\n\n#func _on_Gui_input(event):\n#\tif event is InputEventMouseButton:\n#\t\tif event.get_button_index() == MOUSE_BUTTON_LEFT || event.get_button_index() == MOUSE_BUTTON_RIGHT:\n#\t\t\tnode_selection_blocked = true\n\n\nfunc _on_Node_added(node: Node):\n\tif (node is Control || node is CollisionObject2D) && !_is_parent_of(node, self):\n\t\tnode.mouse_entered.connect(_on_Node_mouse_entered.bind(node))\n\t\tnode.mouse_exited.connect(_on_Node_mouse_exited.bind(node))\n\n\nfunc _on_Node_mouse_entered(node: Node):\n#\tif !node_selection_blocked:\n\tcurrent_node = node\n\n\nfunc _on_Node_mouse_exited(_node: Node):\n\tcurrent_node = null\n\n\nfunc _connect_all_nodes(node):\n\tfor n in node.get_children():\n\t\tif n.get_instance_id() == get_instance_id():\n\t\t\tcontinue\n\t\t_on_Node_added(n)\n\t\tif n.get_child_count() > 0:\n\t\t\t_connect_all_nodes(n)\n\n\nfunc _is_parent_of(node, parent_node) -> bool:\n\tif node == null:\n\t\treturn false\n\telif node.get_instance_id() == parent_node.get_instance_id():\n\t\treturn true\n\telse:\n\t\treturn _is_parent_of(node.get_parent(), parent_node)\n"
  },
  {
    "path": "src/ui/dev_controls/signals_control.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://cojr80363rwx2\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/dev_controls/signals_control.gd\" id=\"1_3sjri\"]\n\n\n[node name=\"SignalsControl\" type=\"Control\" node_paths=PackedStringArray(\"debug_container\")]\nprocess_priority = -1\nlayout_mode = 3\nanchors_preset = 0\noffset_right = 1000.0\noffset_bottom = 500.0\nscript = ExtResource(\"1_3sjri\")\ndebug_container = NodePath(\"VBoxContainer\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 0\noffset_right = 164.0\noffset_bottom = 40.0\n\n[node name=\"SignalsTitle\" type=\"Label\" parent=\"VBoxContainer\"]\nunique_name_in_owner = true\nlayout_mode = 2\ntext = \"THIS IS DEBUG LABEL\"\n\n[node name=\"SignalsGrid\" type=\"GridContainer\" parent=\"VBoxContainer\"]\nunique_name_in_owner = true\nmodulate = Color(0, 0, 0, 1)\nlayout_mode = 2\ncolumns = 6\n\n[node name=\"SignalArgEdit\" type=\"LineEdit\" parent=\".\"]\nvisible = false\ncustom_minimum_size = Vector2(1000, 500)\nlayout_mode = 0\noffset_right = 1000.0\noffset_bottom = 500.0\nplaceholder_text = \"Type value for the signal arg here. Examples:\\\"23\\\", \\\"Node2D.new()\\\", \\\"sdasd\\\"\"\ncaret_blink = true\ncaret_blink_interval = 0.5\n"
  },
  {
    "path": "src/ui/dev_controls/wave_control.gd",
    "content": "extends Control\n\n\nfunc _on_DevControlButton_button_up():\n\tshow()\n"
  },
  {
    "path": "src/ui/dev_controls/wave_control.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://bsu2i4smjlpui\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/dev_controls/wave_control.gd\" id=\"1_4w1t3\"]\n\n\n[node name=\"WaveControl\" type=\"Control\"]\nlayout_mode = 3\nanchors_preset = 0\noffset_right = 300.0\noffset_bottom = 300.0\nscript = ExtResource(\"1_4w1t3\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/HBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"StartWaveButton\" type=\"Button\" parent=\"MarginContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nfocus_mode = 0\ntext = \"Start wave\"\n\n[node name=\"StopWaveButton\" type=\"Button\" parent=\"MarginContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nfocus_mode = 0\ntext = \"Stop wave\"\n\n[node name=\"WaveProgress\" type=\"HBoxContainer\" parent=\"MarginContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"WaveProgressLabel\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/VBoxContainer/WaveProgress\"]\nlayout_mode = 2\ntext = \"Wave progress:\"\n\n[node name=\"WaveProgressValue\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/VBoxContainer/WaveProgress\"]\nlayout_mode = 2\ntext = \"0\"\n\n[node name=\"WaveEdit\" type=\"HBoxContainer\" parent=\"MarginContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"WaveNumberLabel\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/VBoxContainer/WaveEdit\"]\nlayout_mode = 2\ntext = \"Wave:\"\n\n[node name=\"WaveNumberValue\" type=\"SpinBox\" parent=\"MarginContainer/HBoxContainer/VBoxContainer/WaveEdit\"]\nlayout_mode = 2\nfocus_next = NodePath(\"../../../../../..\")\nfocus_previous = NodePath(\"../../../../../..\")\nfocus_mode = 1\nmin_value = 1.0\nvalue = 1.0\n\n[node name=\"CreepCount\" type=\"HBoxContainer\" parent=\"MarginContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"CreepCountLabel\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/VBoxContainer/CreepCount\"]\nlayout_mode = 2\ntext = \"Creeps exited:\"\n\n[node name=\"CreepCountValue\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/VBoxContainer/CreepCount\"]\nlayout_mode = 2\ntext = \"0\"\n\n[node name=\"WaveSignals\" type=\"VBoxContainer\" parent=\"MarginContainer/HBoxContainer\"]\nlayout_mode = 2\n\n[connection signal=\"value_changed\" from=\"MarginContainer/HBoxContainer/VBoxContainer/WaveEdit/WaveNumberValue\" to=\"MarginContainer/HBoxContainer/VBoxContainer/WaveEdit/WaveNumberValue\" method=\"_on_WaveEdit_value_changed\"]\n"
  },
  {
    "path": "src/ui/filter_buttons/element_filter.gd",
    "content": "class_name ElementsContainer extends VBoxContainer\n\n\nsignal element_changed()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_element() -> Element.enm:\n\tvar buttons: Array[Node] = get_children()\n\t\n\tfor button in buttons:\n\t\tif button.button_pressed:\n\t\t\tvar element: Element.enm = button.element\n\t\t\t\n\t\t\treturn element\n\t\n\tvar fallback_element: Element.enm = Element.enm.ICE\n\t\n\treturn fallback_element\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_element_button_pressed(_button_pressed: bool):\n\telement_changed.emit()\n"
  },
  {
    "path": "src/ui/filter_buttons/element_filter.tscn",
    "content": "[gd_scene load_steps=11 format=3 uid=\"uid://l8hrrql7ne16\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/filter_buttons/element_filter.gd\" id=\"1_6o50p\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cgdwym7h2i5ot\" path=\"res://src/ui/filter_buttons/filter_button_element.tscn\" id=\"2_ds1w8\"]\n[ext_resource type=\"ButtonGroup\" uid=\"uid://btb8xdpulas1s\" path=\"res://resources/button_groups/element_filter_button_group.tres\" id=\"3_g3ljb\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://63uq7vjycais\" path=\"res://resources/icons/elements/ice.tres\" id=\"4_p60bo\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c14cl1op1y5wk\" path=\"res://resources/icons/elements/nature.tres\" id=\"5_s2nhr\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bvhrjk28kmjxg\" path=\"res://resources/icons/elements/fire.tres\" id=\"6_kuaiu\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b58m66c4f8n2n\" path=\"res://resources/icons/elements/astral.tres\" id=\"7_6nm5y\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ofrvficsj8ih\" path=\"res://resources/icons/elements/storm.tres\" id=\"8_yvbhi\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b7c8ugpn34iib\" path=\"res://resources/icons/elements/darkness.tres\" id=\"9_fsbg5\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://3aghxlv6b4hb\" path=\"res://resources/icons/elements/iron.tres\" id=\"10_xf7tc\"]\n\n[node name=\"ElementFilter\" type=\"VBoxContainer\"]\nalignment = 2\nscript = ExtResource(\"1_6o50p\")\n\n[node name=\"FilterButtonElement\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_ICE\"\nbutton_pressed = true\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"4_p60bo\")\n\n[node name=\"FilterButtonElement2\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_NATURE\"\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"5_s2nhr\")\nelement = 1\n\n[node name=\"FilterButtonElement3\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_FIRE\"\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"6_kuaiu\")\nelement = 2\n\n[node name=\"FilterButtonElement4\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_ASTRAL\"\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"7_6nm5y\")\nelement = 3\n\n[node name=\"FilterButtonElement7\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_STORM\"\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"8_yvbhi\")\nelement = 6\n\n[node name=\"FilterButtonElement5\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_DARKNESS\"\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"9_fsbg5\")\nelement = 4\n\n[node name=\"FilterButtonElement6\" parent=\".\" instance=ExtResource(\"2_ds1w8\")]\nlayout_mode = 2\ntooltip_text = \"ELEMENT_IRON\"\nbutton_group = ExtResource(\"3_g3ljb\")\nicon = ExtResource(\"10_xf7tc\")\nelement = 5\n\n[connection signal=\"toggled\" from=\"FilterButtonElement\" to=\".\" method=\"_on_element_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonElement2\" to=\".\" method=\"_on_element_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonElement3\" to=\".\" method=\"_on_element_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonElement4\" to=\".\" method=\"_on_element_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonElement7\" to=\".\" method=\"_on_element_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonElement5\" to=\".\" method=\"_on_element_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonElement6\" to=\".\" method=\"_on_element_button_pressed\"]\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bpewn2rh5b1kf\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://775ninjr2sio\" path=\"res://resources/icons/hud/gem_all_rarities.tres\" id=\"1_4j25c\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_dx1f6\"]\n\n[node name=\"FilterButton\" type=\"Button\"]\ncustom_minimum_size = Vector2(64, 64)\nfocus_mode = 0\ntheme = ExtResource(\"1_dx1f6\")\ntheme_type_variation = &\"FilterButton\"\ntoggle_mode = true\nicon = ExtResource(\"1_4j25c\")\nexpand_icon = true\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button_element.gd",
    "content": "extends Button\n\n\n@export var element: Element.enm\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button_element.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cgdwym7h2i5ot\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://bpewn2rh5b1kf\" path=\"res://src/ui/filter_buttons/filter_button.tscn\" id=\"1_daova\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/filter_buttons/filter_button_element.gd\" id=\"2_crwt1\"]\n\n[node name=\"FilterButtonElement\" instance=ExtResource(\"1_daova\")]\nscript = ExtResource(\"2_crwt1\")\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button_item_type.gd",
    "content": "extends Button\n\n@export var filter_value: Array[ItemType.enm]\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button_item_type.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://8rqr6mlftwrx\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://bpewn2rh5b1kf\" path=\"res://src/ui/filter_buttons/filter_button.tscn\" id=\"1_l27c0\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/filter_buttons/filter_button_item_type.gd\" id=\"2_wk4uf\"]\n\n[node name=\"FilterButtonItemType\" instance=ExtResource(\"1_l27c0\")]\nscript = ExtResource(\"2_wk4uf\")\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button_rarity.gd",
    "content": "extends Button\n\n@export var rarity_list: Array[Rarity.enm]\n"
  },
  {
    "path": "src/ui/filter_buttons/filter_button_rarity.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bg7nrj1oufmwa\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://bpewn2rh5b1kf\" path=\"res://src/ui/filter_buttons/filter_button.tscn\" id=\"1_c5lm0\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/filter_buttons/filter_button_rarity.gd\" id=\"2_45pqm\"]\n\n[node name=\"FilterButtonRarity\" instance=ExtResource(\"1_c5lm0\")]\nscript = ExtResource(\"2_45pqm\")\n"
  },
  {
    "path": "src/ui/filter_buttons/item_type_filter.gd",
    "content": "# ItemFilterContainer\nextends VBoxContainer\n\n\nsignal filter_changed()\n\n\nfunc get_filter() -> Array:\n\tvar buttons = get_children()\n\tvar active_filter = []\n\tfor button in buttons:\n\t\tif button.button_pressed:\n\t\t\tif typeof(button.filter_value) == TYPE_ARRAY:\n\t\t\t\tfor filter_value in button.filter_value:\n\t\t\t\t\tactive_filter.append(filter_value)\n\t\t\telse:\n\t\t\t\tactive_filter.append(button.filter_value)\n\treturn active_filter\n\n\nfunc _on_filter_button_pressed(_value):\n\tfilter_changed.emit()\n"
  },
  {
    "path": "src/ui/filter_buttons/item_type_filter.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://ib3y0a6h0v46\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/filter_buttons/item_type_filter.gd\" id=\"1_jj4ac\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8rqr6mlftwrx\" path=\"res://src/ui/filter_buttons/filter_button_item_type.tscn\" id=\"2_dcwgy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://boxxhen27xatf\" path=\"res://resources/icons/hud/item_stash.tres\" id=\"2_ftq7a\"]\n[ext_resource type=\"ButtonGroup\" uid=\"uid://cycas5vk7h2lw\" path=\"res://resources/button_groups/item_type_filter_button_group.tres\" id=\"3_254a3\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bk4dvb16ukwx8\" path=\"res://resources/icons/hud/recipe_reassemble.tres\" id=\"4_0ptir\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c50etdjubvudf\" path=\"res://resources/icons/hud/oils.tres\" id=\"5_fd3uu\"]\n\n[node name=\"ItemTypeFilter\" type=\"VBoxContainer\"]\nsize_flags_horizontal = 10\nalignment = 2\nscript = ExtResource(\"1_jj4ac\")\n\n[node name=\"FilterButtonItemType\" parent=\".\" instance=ExtResource(\"2_dcwgy\")]\nlayout_mode = 2\ntooltip_text = \"ITEM_TYPE_FILTER_ALL\"\ntheme = null\nbutton_pressed = true\nbutton_group = ExtResource(\"3_254a3\")\nicon = ExtResource(\"2_ftq7a\")\nfilter_value = Array[int]([0, 1, 2])\n\n[node name=\"FilterButtonItemType2\" parent=\".\" instance=ExtResource(\"2_dcwgy\")]\nlayout_mode = 2\ntooltip_text = \"ITEM_TYPE_FILTER_PERMANENT\"\ntheme = null\nbutton_group = ExtResource(\"3_254a3\")\nicon = ExtResource(\"4_0ptir\")\nfilter_value = Array[int]([0])\n\n[node name=\"FilterButtonItemType3\" parent=\".\" instance=ExtResource(\"2_dcwgy\")]\nlayout_mode = 2\ntooltip_text = \"ITEM_TYPE_FILTER_OILS\"\ntheme = null\nbutton_group = ExtResource(\"3_254a3\")\nicon = ExtResource(\"5_fd3uu\")\nfilter_value = Array[int]([1, 2])\n\n[connection signal=\"toggled\" from=\"FilterButtonItemType\" to=\".\" method=\"_on_filter_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonItemType2\" to=\".\" method=\"_on_filter_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonItemType3\" to=\".\" method=\"_on_filter_button_pressed\"]\n"
  },
  {
    "path": "src/ui/filter_buttons/rarity_filter.gd",
    "content": "class_name RarityFilter extends VBoxContainer\n\n\nsignal filter_changed()\n\n\n# NOTE: need to create a new ButtonGroup here so that\n# RarityFilter can be used in multiple scenes without\n# conflicts.\nfunc _ready():\n\tvar button_group: ButtonGroup = ButtonGroup.new()\n\t\n\tvar button_node_list: Array[Node] = get_children()\n\t\n\tfor button_node in button_node_list:\n\t\tvar button: Button = button_node as Button\n\t\t\n\t\tif button == null:\n\t\t\tcontinue\n\t\t\n\t\tbutton.set_button_group(button_group)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_filter() -> Array[Rarity.enm]:\n\tvar buttons = get_children()\n\t\n\tfor button in buttons:\n\t\tif button.button_pressed:\n\t\t\tvar rarity_list: Array[Rarity.enm] = button.rarity_list\n\t\t\t\n\t\t\treturn rarity_list\n\t\n\tvar fallback_rarity_list: Array[Rarity.enm] = [Rarity.enm.COMMON]\n\t\n\treturn fallback_rarity_list\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_filter_button_pressed(_value):\n\tfilter_changed.emit()\n"
  },
  {
    "path": "src/ui/filter_buttons/rarity_filter.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://qcct52drete4\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/filter_buttons/rarity_filter.gd\" id=\"1_b88ja\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bg7nrj1oufmwa\" path=\"res://src/ui/filter_buttons/filter_button_rarity.tscn\" id=\"2_j5bkp\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dnfyls46vqccy\" path=\"res://resources/icons/hud/gem_common.tres\" id=\"3_nd2bw\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bbgnvq4hx2ady\" path=\"res://resources/icons/hud/gem_uncommon.tres\" id=\"4_6gbsy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://do0ipsu6xkehe\" path=\"res://resources/icons/hud/gem_rare.tres\" id=\"5_wbg08\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://fhntdx77to0k\" path=\"res://resources/icons/hud/gem_unique.tres\" id=\"6_ufthl\"]\n\n[node name=\"RarityFilter\" type=\"VBoxContainer\"]\nsize_flags_horizontal = 0\nscript = ExtResource(\"1_b88ja\")\n\n[node name=\"FilterButtonRarity\" parent=\".\" instance=ExtResource(\"2_j5bkp\")]\nlayout_mode = 2\ntooltip_text = \"RARITY_FILTER_ALL\"\nbutton_pressed = true\nrarity_list = Array[int]([0, 1, 2, 3])\n\n[node name=\"FilterButtonRarity2\" parent=\".\" instance=ExtResource(\"2_j5bkp\")]\nlayout_mode = 2\ntooltip_text = \"RARITY_COMMON\"\nicon = ExtResource(\"3_nd2bw\")\nrarity_list = Array[int]([0])\n\n[node name=\"FilterButtonRarity3\" parent=\".\" instance=ExtResource(\"2_j5bkp\")]\nlayout_mode = 2\ntooltip_text = \"RARITY_UNCOMMON\"\nicon = ExtResource(\"4_6gbsy\")\nrarity_list = Array[int]([1])\n\n[node name=\"FilterButtonRarity4\" parent=\".\" instance=ExtResource(\"2_j5bkp\")]\nlayout_mode = 2\ntooltip_text = \"RARITY_RARE\"\nicon = ExtResource(\"5_wbg08\")\nrarity_list = Array[int]([2])\n\n[node name=\"FilterButtonRarity5\" parent=\".\" instance=ExtResource(\"2_j5bkp\")]\nlayout_mode = 2\ntooltip_text = \"RARITY_UNIQUE\"\nicon = ExtResource(\"6_ufthl\")\nrarity_list = Array[int]([3])\n\n[connection signal=\"toggled\" from=\"FilterButtonRarity\" to=\".\" method=\"_on_filter_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonRarity2\" to=\".\" method=\"_on_filter_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonRarity3\" to=\".\" method=\"_on_filter_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonRarity4\" to=\".\" method=\"_on_filter_button_pressed\"]\n[connection signal=\"toggled\" from=\"FilterButtonRarity5\" to=\".\" method=\"_on_filter_button_pressed\"]\n"
  },
  {
    "path": "src/ui/game_menu/credits_menu.gd",
    "content": "extends PanelContainer\n\nsignal close_pressed()\n\n\nfunc _on_close_button_pressed():\n\tclose_pressed.emit()\n"
  },
  {
    "path": "src/ui/game_menu/credits_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bx0xth6bthpon\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_phxvu\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/game_menu/credits_menu.gd\" id=\"2_u7bhi\"]\n\n\n[node name=\"CreditsMenu\" type=\"PanelContainer\"]\ncustom_minimum_size = Vector2(800, 900)\ntheme = ExtResource(\"1_phxvu\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_u7bhi\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_top = 15\ntheme_override_constants/margin_right = 15\ntheme_override_constants/margin_bottom = 15\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 15\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Credits\"\nhorizontal_alignment = 1\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"MarginContainer/VBoxContainer/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nbbcode_enabled = true\ntext = \"YouTD2 was made by:\n \n[color=GOLD]Praytic[/color]\n[color=GOLD]Dmitry Degtyarev[/color]\n \nWith contributions from:\n \n[color=GOLD]Sea[/color]\n[color=GOLD]G3s[/color]\n[color=GOLD]Smeto[/color]\n[color=GOLD]Anufis[/color]\n[color=GOLD]vbogach[/color]\n[color=GOLD]TiGPyLLle4kA[/color]\n[color=GOLD]Lizreu[/color]\n[color=GOLD]jdbuenol[/color]\n[color=GOLD]jhoijhoi[/color]\n[color=GOLD]Patcharoo[/color]\n[color=GOLD]Garrett[/color]\n[color=GOLD]AlexHuni[/color]\n[color=GOLD]hka[/color]\n[color=GOLD]Alex Isobaev[/color]\n[color=GOLD]mittig[/color]\n[color=GOLD]lichcay[/color]\n[color=GOLD]lamess233[/color]\n \nThis game was made with the [color=LIGHTBLUE]Godot Engine[/color].\n[url]https://godotengine.org/license/[/url]\n \nThis game uses the [color=BURLYWOOD]Isometric Dungeon Tiles[/color] tileset created by [color=ORANGE]Kenney[/color].\n \nThis game uses the [color=BURLYWOOD]RTS Mega Pack[/color] created by [color=ORANGE]Bitgem[/color].\n \nThis game uses the [color=BURLYWOOD]Effect and FX Pixel All[/color] asset pack created by [color=ORANGE]BDragon1727[/color]. [url]https://bdragon1727.itch.io/effect-and-fx-pixel-all[/url]\n \nMany thanks to [color=RED]Garrett[/color] for operating the [color=LIGHTBLUE]youtd.best[/color] website. It contains a database of YouTD towers and items which was a lot of help during the development of this game!\n\nThis game was localized with the help of:\n[color=GOLD]lamess233 - Chinese[/color]\n[color=GOLD]lichcay - Chinese[/color]\n[color=GOLD]C4lut - Italian[/color]\n \nYouTD2 is based on [color=RED]geX[/color]'s [color=SILVER]YouTD[/color] - a custom map for Warcraft 3 made with the help of many contributors:\n \n[color=FORESTGREEN]boekie[/color]\n[color=GOLD]drol[/color]\n[color=FORESTGREEN]cedi[/color]\n[color=GOLD]SirCoqaLot[/color]\n[color=GOLD]Natac[/color]\n[color=RED]geX[/color]\n[color=FORESTGREEN]m0ck[/color]\n[color=GOLD]Majildian[/color]\n[color=GOLD]SternBogen[/color]\n[color=FORESTGREEN]tolleder[/color]\n[color=GOLD]DaveMatthews[/color]\n[color=GOLD]Velex[/color]\n[color=FORESTGREEN]der_kleine_Tomy[/color]\n[color=DARKRED]MasterCassim[/color]\n[color=GOLD]Neotopia[/color]\n[color=GOLD]Palandu[/color]\n[color=GOLD]Chronos[/color]\n[color=GOLD]Lapsus[/color]\n[color=GOLD]poussix[/color]\n[color=GOLD]IamanEvilMan[/color]\n[color=GOLD]Cyony[/color]\n[color=GOLD]ShyGnome[/color]\n[color=GOLD]Monolith[/color]\n[color=FORESTGREEN]Glowackos[/color]\n[color=FORESTGREEN]KublaiKhan1[/color]\n[color=GOLD]BetrayedKnight[/color]\n[color=GOLD]Killamasta[/color]\n[color=GOLD]Ashbringer[/color]\n[color=GOLD]His_Shadow[/color]\n[color=FORESTGREEN]Deemzul[/color]\n[color=GOLD]Shaddow[/color]\n[color=GOLD]Joe[/color]\n[color=GOLD]D10000[/color]\n[color=GOLD]👉👉👉[/color]\n[color=GOLD]the-red-terror[/color]\n[color=GOLD]Coldrocker[/color]\n[color=GOLD]McDoNaldGaNgStA[/color]\n[color=GOLD]SymphonyX[/color]\n[color=GOLD]F12ight[/color]\n[color=GOLD]hokkei[/color]\n[color=GOLD]axllow[/color]\n[color=GOLD]TopBanana[/color]\n[color=GOLD]Guennter[/color]\n[color=GOLD]Nubz[/color]\n[color=GOLD]Ely[/color]\n[color=GOLD]Kricz[/color]\n[color=GOLD]Sunken[/color]\n[color=GOLD]Cyrganth[/color]\n[color=GOLD]lumfa[/color]\n[color=GOLD]Ranakastrasz[/color]\n[color=GOLD]Khlox-NL-[/color]\n[color=GOLD]LordHellHunter[/color]\n[color=GOLD]Bartuck[/color]\n[color=GOLD]YouJizzTD[/color]\n[color=GOLD]Zloj[/color]\n[color=GOLD]KySoto[/color]\n[color=GOLD]zed[/color]\n \nYouTD2 contains icons from [color=GOLD]game-icons.net[/color], used under CC BY 3.0. Icon authors:\n[color=GOLD]Lorc[/color]\n[color=GOLD]Delapouite[/color]\n[color=GOLD]Wildabeast[/color]\n[color=GOLD]Caro Asercion[/color]\n[color=GOLD]sbed[/color]\n \nYouTD2 contains sound effects made by multiple people:\n \nSlash by qubodup -- https://freesound.org/s/442903/ -- License: Creative Commons 0  splat.ogg by gprosser -- https://freesound.org/s/360942/ -- License: Creative Commons 0  Bloody Blade 2.wav by Kreastricon62 -- https://freesound.org/s/323526/ -- License: Creative Commons 0\n \nWar Game Battle Level Up by qubodup -- https://freesound.org/s/161654/ -- License: Creative Commons 0  timp_rolls.flac by spt3125 -- https://freesound.org/s/24810/ -- License: Creative Commons 0\n \nEnchant.flac by qubodup - https://freesound.org/people/qubodup/sounds/202147/ - License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\n \nFireball by qubodup -- https://freesound.org/s/442827/ -- License: Attribution 4.0  Short-Fireball-Woosh.flac by wjl -- https://freesound.org/s/267887/ -- License: Creative Commons 0  Match by qubodup -- https://freesound.org/s/171693/ -- License: Attribution 4.0  23 FIACCOLA PASS.aiff by lollosound -- https://freesound.org/s/124372/ -- License: Creative Commons 0  Dull Decompression Punch Impact Explodes 96kHz by qubodup -- https://freesound.org/s/71274/ -- License: Creative Commons 0\n \nCloud Poof by qubodup -- https://freesound.org/s/714258/ -- License: Attribution 4.0  cloud-punch.wav by CaptainYulef -- https://freesound.org/s/641241/ -- License: Creative Commons 0  Gas Cloud.wav by puppetmaster685719 -- https://freesound.org/s/627733/ -- License: Creative Commons 0  Poof in cloud by Mateusz_Chenc -- https://freesound.org/s/512217/ -- License: Creative Commons 0  Poof.wav by ryansitz -- https://freesound.org/s/387834/ -- License: Creative Commons 0  explosionsfx.wav by OtisJames -- https://freesound.org/s/249613/ -- License: Creative Commons 0\n \nOrc Grunt 2 by qubodup -- https://freesound.org/s/738438/ - License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\n \nBlast / Explosion by TigrePlayz_ -- https://freesound.org/s/745156/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n \nCoins3 by NoisyRedFox -- https://freesound.org/s/734247/ -- License: Creative Commons 0\n \nStomp Soft by brettrader -- https://freesound.org/s/683044/ -- License: Creative Commons 0\n \nPick up Item 1.wav by SilverIllusionist -- https://freesound.org/s/411177/ -- License: Attribution 4.0\n \nSpell Cast / Buff / High Tone by SypherZent - https://freesound.org/people/SypherZent/sounds/420676/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n \nMagic Fire Spell Impact & Punch by EminYILDIRIM - freesound.org/people/EminYILDIRIM/sounds/541478 – License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\n \nHeal - Rpg by colorsCrimsonTears - https://freesound.org/s/562292/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n \nSword_Water01.wav by SonoFxAudio - https://freesound.org/people/SonoFxAudio/sounds/649359/ - License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\n \nthud.mp3 by sunflora -- https://freesound.org/s/665082/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n \nMagic spell by Bastianhallo -- https://freesound.org/s/682635/ - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n \nSpell 4 (FIRE) by Bart K. -- https://opengameart.org/content/spell-4-fire -- License: Creative Commons 3\n \n3 Item sounds by Michel Baradari -- https://opengameart.org/content/3-item-sounds -- License: Creative Commons 3\n \nLava splash by Michel Baradari -  https://opengameart.org/content/lava-splash - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\n \nteleport by Q009 - https://opengameart.org/content/q009s-weapon-sounds - License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\n \nFantasy Sound Effects Library by Little Robot Sound Factory -  https://opengameart.org/content/fantasy-sound-effects-library - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/)\n \nArchers shooting by copyc4t (Paolo D'Emilio) - https://opengameart.org/content/archers-shooting - License: CC BY 3.0 (https://creativecommons.org/licenses/by/3.0/) This work is an adaption of other works below: bow_sound.wav by Anton -- https://freesound.org/s/54/ -- License: Attribution 4.0 Swosh / Whoosh / Air Cut by qubodup -- https://freesound.org/s/60030/ -- License: Creative Commons 0 Bow Releases.wav by Benboncan -- https://freesound.org/s/85019/ -- License: Attribution 4.0\n \n3 Heal Spells by DoKashiteru - https://opengameart.org/content/3-heal-spells - License: CC BY (https://creativecommons.org/licenses/by/3.0/)\n \nFreeze Spell by artisticdude - https://opengameart.org/content/freeze-spell-0 - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n \nSpell Sounds Starter Pack by p0ss - https://opengameart.org/content/spell-sounds-starter-pack - License: CC BY SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/)\n \n80 CC0 creature SFX by rubberduck - https://opengameart.org/content/80-cc0-creature-sfx - License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)\n\"\nfit_content = true\n\n[node name=\"CloseButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nfocus_mode = 0\ntext = \"Close\"\n\n[connection signal=\"pressed\" from=\"MarginContainer/VBoxContainer/CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/game_menu/game_menu.gd",
    "content": "extends VBoxContainer\n\n\nenum Tab {\n\tMAIN = 0,\n\tHELP,\n\tENCYCLOPEDIA,\n\tSETTINGS,\n}\n\n\nsignal continue_pressed()\nsignal quit_pressed()\n\n\n@export var _tab_container: TabContainer\n@export var _settings_menu: SettingsMenu\n@export var _encyclopedia_placeholder: PanelContainer\n\nvar _encyclopedia_instance: EncyclopediaMenu = null\n\n\nfunc _ready():\n\t_settings_menu.set_opened_in_game(true)\n\n\nfunc switch_to_help_menu():\n\t_tab_container.current_tab = Tab.HELP\n\n\nfunc _on_continue_button_pressed():\n\tcontinue_pressed.emit()\n\n\nfunc _on_help_button_pressed():\n\t_tab_container.current_tab = Tab.HELP\n\n\nfunc _on_settings_button_pressed():\n\t_tab_container.current_tab = Tab.SETTINGS\n\n\nfunc _on_hidden():\n\t_tab_container.current_tab = Tab.MAIN\n\t\n\tif _encyclopedia_instance != null:\n\t\t_encyclopedia_placeholder.remove_child(_encyclopedia_instance)\n\t\t_encyclopedia_instance.queue_free()\n\t\t_encyclopedia_instance = null\n\n\nfunc _on_help_menu_closed():\n\t_tab_container.current_tab = Tab.MAIN\n\n\nfunc _on_help_menu_hidden():\n\t_tab_container.current_tab = Tab.MAIN\n\n\nfunc _on_settings_menu_cancel_pressed():\n\t_tab_container.current_tab = Tab.MAIN\n\n\nfunc _on_settings_menu_ok_pressed():\n\t_tab_container.current_tab = Tab.MAIN\n\n\nfunc _on_quit_button_pressed():\n\tquit_pressed.emit()\n\n\nfunc _on_encyclopedia_button_pressed() -> void:\n\t_tab_container.current_tab = Tab.ENCYCLOPEDIA\n\t\n\tif _encyclopedia_instance == null:\n\t\tvar encyclopedia_scene: PackedScene = load(\"res://src/ui/title_screen/encyclopedia_menu.tscn\")\n\t\t_encyclopedia_instance = encyclopedia_scene.instantiate()\n\t\t_encyclopedia_placeholder.add_child(_encyclopedia_instance)\n\t\t_encyclopedia_instance.close_pressed.connect(_on_encyclopedia_menu_close_pressed)\n\n\nfunc _on_encyclopedia_menu_close_pressed() -> void:\n\t_tab_container.current_tab = Tab.MAIN\n"
  },
  {
    "path": "src/ui/game_menu/game_menu.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://hiex318b5cvk\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/game_menu/game_menu.gd\" id=\"1_8lyul\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_v8b77\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bbrryq35rxvkv\" path=\"res://src/ui/game_menu/help_menu.tscn\" id=\"3_vf4xx\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cx86ea3loo8a2\" path=\"res://src/ui/game_menu/settings_menu.tscn\" id=\"5_y1l7h\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_6c4dp\"]\n\n[node name=\"GameMenu\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_tab_container\", \"_settings_menu\", \"_encyclopedia_placeholder\")]\ntheme = ExtResource(\"1_v8b77\")\nscript = ExtResource(\"1_8lyul\")\n_tab_container = NodePath(\"TabContainer\")\n_settings_menu = NodePath(\"TabContainer/SettingsMenu\")\n_encyclopedia_placeholder = NodePath(\"TabContainer/EncyclopediaPlaceholder\")\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_6c4dp\")\ncurrent_tab = 0\ntabs_visible = false\n\n[node name=\"MainTab\" type=\"PanelContainer\" parent=\"TabContainer\"]\nlayout_mode = 2\ntheme = ExtResource(\"1_v8b77\")\ntheme_type_variation = &\"MainPanelContainer\"\nmetadata/_tab_index = 0\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/MainTab\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"ContinueButton\" type=\"Button\" parent=\"TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"CONTINUE_BUTTON\"\n\n[node name=\"HelpButton\" type=\"Button\" parent=\"TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"HELP_BUTTON\"\n\n[node name=\"EncyclopediaButton\" type=\"Button\" parent=\"TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"ENCYCLOPEDIA_BUTTON\"\n\n[node name=\"SettingsButton\" type=\"Button\" parent=\"TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_BUTTON\"\n\n[node name=\"QuitButton\" type=\"Button\" parent=\"TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"QUIT_TO_MENU_BUTTON\"\n\n[node name=\"HintsMenu\" parent=\"TabContainer\" instance=ExtResource(\"3_vf4xx\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 1\n\n[node name=\"EncyclopediaPlaceholder\" type=\"PanelContainer\" parent=\"TabContainer\"]\nvisible = false\nself_modulate = Color(1, 1, 1, 0)\nlayout_mode = 2\nmetadata/_tab_index = 2\n\n[node name=\"SettingsMenu\" parent=\"TabContainer\" instance=ExtResource(\"5_y1l7h\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 3\n\n[connection signal=\"hidden\" from=\".\" to=\".\" method=\"_on_hidden\"]\n[connection signal=\"pressed\" from=\"TabContainer/MainTab/VBoxContainer/ContinueButton\" to=\".\" method=\"_on_continue_button_pressed\"]\n[connection signal=\"pressed\" from=\"TabContainer/MainTab/VBoxContainer/HelpButton\" to=\".\" method=\"_on_help_button_pressed\"]\n[connection signal=\"pressed\" from=\"TabContainer/MainTab/VBoxContainer/EncyclopediaButton\" to=\".\" method=\"_on_encyclopedia_button_pressed\"]\n[connection signal=\"pressed\" from=\"TabContainer/MainTab/VBoxContainer/SettingsButton\" to=\".\" method=\"_on_settings_button_pressed\"]\n[connection signal=\"pressed\" from=\"TabContainer/MainTab/VBoxContainer/QuitButton\" to=\".\" method=\"_on_quit_button_pressed\"]\n[connection signal=\"closed\" from=\"TabContainer/HintsMenu\" to=\".\" method=\"_on_help_menu_closed\"]\n[connection signal=\"cancel_pressed\" from=\"TabContainer/SettingsMenu\" to=\".\" method=\"_on_settings_menu_cancel_pressed\"]\n[connection signal=\"ok_pressed\" from=\"TabContainer/SettingsMenu\" to=\".\" method=\"_on_settings_menu_ok_pressed\"]\n"
  },
  {
    "path": "src/ui/game_menu/help_menu.gd",
    "content": "extends TabContainer\n\n\n# Contains help information and hints for the game. Loads\n# data from a CSV file. Left side of the menu contains a\n# list of titles, while the right side of the menu displays\n# the text of the selected section.\n\n\nsignal closed()\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar tab_node_list: Array[Node] = get_children()\n\t\n\tfor tab_node in tab_node_list:\n\t\tvar tab: HelpMenuTab = tab_node as HelpMenuTab\n\t\t\n\t\tif tab == null:\n\t\t\tcontinue\n\t\t\n\t\ttab.closed.connect(_on_tab_closed)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_tab_closed():\n\tclosed.emit()\n"
  },
  {
    "path": "src/ui/game_menu/help_menu.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://bbrryq35rxvkv\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_njctg\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/game_menu/help_menu.gd\" id=\"2_jpay6\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dqb37g0dwa4o2\" path=\"res://src/ui/game_menu/help_menu_tab.tscn\" id=\"3_iygdm\"]\n\n[node name=\"HelpMenu\" type=\"TabContainer\"]\ncustom_minimum_size = Vector2(1100, 700)\noffset_right = 900.0\noffset_bottom = 705.0\ntheme = ExtResource(\"1_njctg\")\ntheme_type_variation = &\"MainPanelContainer\"\ncurrent_tab = 0\nscript = ExtResource(\"2_jpay6\")\n\n[node name=\"HELP_MENU_BASICS\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nlayout_mode = 2\ncsv_path = \"res://data/hints/basics.csv\"\nmetadata/_tab_index = 0\n\n[node name=\"HELP_MENU_TUTORIAL\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/tutorial.csv\"\nmetadata/_tab_index = 1\n\n[node name=\"HELP_MENU_CHAT_COMMANDS\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/chat_commands.csv\"\nmetadata/_tab_index = 2\n\n[node name=\"HELP_MENU_TOWERS\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/towers.csv\"\nmetadata/_tab_index = 3\n\n[node name=\"HELP_MENU_ITEMS\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/items.csv\"\nmetadata/_tab_index = 4\n\n[node name=\"HELP_MENU_CREEPS\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/creeps.csv\"\nmetadata/_tab_index = 5\n\n[node name=\"HELP_MENU_CREEP_SPECIALS\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/creep_specials.csv\"\nmetadata/_tab_index = 6\n\n[node name=\"HELP_MENU_ADVANCED\" parent=\".\" instance=ExtResource(\"3_iygdm\")]\nvisible = false\nlayout_mode = 2\ncsv_path = \"res://data/hints/advanced.csv\"\nmetadata/_tab_index = 7\n"
  },
  {
    "path": "src/ui/game_menu/help_menu_tab.gd",
    "content": "class_name HelpMenuTab extends VBoxContainer\n\n\nsignal closed()\n\nenum CsvProperty {\n\tTITLE_ENGLISH,\n\tTITLE,\n\tTEXT,\n}\n\nvar _title_list: Array[String] = []\nvar _text_list: Array[String] = []\n\n@export var csv_path: String\n@export var _tree: Tree\n@export var _text_label: RichTextLabel\n\nvar _properties: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tUtilsStatic.load_csv_properties_with_automatic_ids(csv_path, _properties)\n\t\n\tvar root: TreeItem = _tree.create_item()\n\n\tvar id_list: Array = _properties.keys()\n\tid_list.sort()\n\t\n\tfor id in id_list:\n\t\tvar displayed_index: int = id + 1\n\t\tvar entry: Dictionary = _properties[id]\n\t\tvar title_text_id: String = entry[CsvProperty.TITLE]\n\t\tvar title: String = tr(title_text_id)\n\t\tvar text_text_id: String = entry[CsvProperty.TEXT]\n\t\tvar text: String = tr(text_text_id)\n\n\t\tvar tree_item_text: String = \"%d. %s\" % [displayed_index, title]\n\t\tvar child: TreeItem = _tree.create_item(root)\n\t\tchild.set_text(0, tree_item_text)\n\t\t\n\t\t_title_list.append(title)\n\t\t_text_list.append(text)\n\t\n\tvar first_item: TreeItem = root.get_child(0)\n\t_tree.set_selected(first_item, 0)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_tree_item_selected():\n\tvar selected_item: TreeItem = _tree.get_selected()\n\tvar index: int = selected_item.get_index()\n\tvar title: String = _title_list[index]\n\tvar text: String = _text_list[index]\n\ttext = RichTexts.add_color_to_numbers(text)\n\t\n\tvar combined_text: String = \"[center][color=GOLD]%s[/color][/center]\\n \\n%s\" % [title, text]\n\n\t_text_label.clear()\n\t_text_label.append_text(combined_text)\n\n\nfunc _on_close_button_pressed():\n\tclosed.emit()\n"
  },
  {
    "path": "src/ui/game_menu/help_menu_tab.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://dqb37g0dwa4o2\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/game_menu/help_menu_tab.gd\" id=\"1_q2uv5\"]\n\n[node name=\"HelpMenuTab\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_tree\", \"_text_label\")]\ncustom_minimum_size = Vector2(1000, 900)\ntheme_override_constants/separation = 10\nscript = ExtResource(\"1_q2uv5\")\n_tree = NodePath(\"HBoxContainer/Tree\")\n_text_label = NodePath(\"HBoxContainer/PanelContainer/MarginContainer/ScrollContainer/TextLabel\")\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"Tree\" type=\"Tree\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_stretch_ratio = 0.5\nallow_search = false\nhide_folding = true\nhide_root = true\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"HBoxContainer/PanelContainer/MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"TextLabel\" type=\"RichTextLabel\" parent=\"HBoxContainer/PanelContainer/MarginContainer/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 6\nbbcode_enabled = true\ntext = \"Hint text goes here.\"\nfit_content = true\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\ntext = \"Close\"\n\n[connection signal=\"item_selected\" from=\"HBoxContainer/Tree\" to=\".\" method=\"_on_tree_item_selected\"]\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/game_menu/settings_menu.gd",
    "content": "class_name SettingsMenu extends PanelContainer\n\n\nsignal cancel_pressed()\nsignal ok_pressed()\n\n\n@export var _enable_plus_mode: CheckBox\n@export var _damage_numbers: CheckBox\n@export var _enable_floating_text: CheckBox\n@export var _enable_vfx: CheckBox\n@export var _enable_sfx: CheckBox\n@export var _enable_mouse_scroll: CheckBox\n@export var _show_combat_log: CheckBox\n@export var _show_tutorial_on_start: CheckBox\n@export var _projectile_density: Slider\n@export var _mouse_scroll: Slider\n@export var _keyboard_scroll: Slider\n@export var _interface_size_button_group: ButtonGroup\n@export var _apply_button: Button\n@export var _display_mode_combo: OptionButton\n@export var _language_combo: OptionButton\n@export var _interface_size_button_small: Button\n@export var _interface_size_button_medium: Button\n@export var _interface_size_button_large: Button\n\n\nvar _setting_to_combo_map: Dictionary\nvar _setting_to_checkbox_map: Dictionary\nvar _setting_to_slider_map: Dictionary\n@onready var _interface_size_button_to_size_map: Dictionary = {\n\t_interface_size_button_small: Settings.InterfaceSize.SMALL,\n\t_interface_size_button_medium: Settings.InterfaceSize.MEDIUM,\n\t_interface_size_button_large: Settings.InterfaceSize.LARGE,\n}\nvar _is_dirty: bool = false\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n#\tNOTE: need to setup these maps inside ready() because this map uses @export vars which are not ready before ready()\n\t_setting_to_combo_map = {\n\t\tSettings.DISPLAY_MODE: _display_mode_combo,\n\t\tSettings.LANGUAGE: _language_combo,\n\t}\n\t\n\tfor setting in _setting_to_combo_map.keys():\n\t\tvar combo: OptionButton = _setting_to_combo_map[setting]\n\t\tcombo.item_selected.connect(_on_combo_changed)\n\t\n\t_setting_to_checkbox_map = {\n\t\tSettings.ENABLE_PLUS_MODE: _enable_plus_mode,\n\t\tSettings.SHOW_ALL_DAMAGE_NUMBERS: _damage_numbers,\n\t\tSettings.ENABLE_FLOATING_TEXT: _enable_floating_text,\n\t\tSettings.ENABLE_VFX: _enable_vfx,\n\t\tSettings.ENABLE_SFX: _enable_sfx,\n\t\tSettings.ENABLE_MOUSE_SCROLL: _enable_mouse_scroll,\n\t\tSettings.SHOW_COMBAT_LOG: _show_combat_log,\n\t\tSettings.SHOW_TUTORIAL_ON_START: _show_tutorial_on_start,\n\t}\n\t\n\tfor setting in _setting_to_checkbox_map.keys():\n\t\tvar checkbox: CheckBox = _setting_to_checkbox_map[setting]\n\t\tcheckbox.pressed.connect(_on_checkbox_pressed)\n\t\t\n\t_setting_to_slider_map = {\n\t\tSettings.PROJECTILE_DENSITY: _projectile_density,\n\t\tSettings.MOUSE_SCROLL: _mouse_scroll,\n\t\tSettings.KEYBOARD_SCROLL: _keyboard_scroll,\n\t}\n\t\n\tfor setting in _setting_to_slider_map.keys():\n\t\tvar slider: Slider = _setting_to_slider_map[setting]\n\t\tslider.changed.connect(_on_slider_changed)\n\t\n\t_interface_size_button_group.pressed.connect(_on_interface_size_button_group_pressed)\n\t\n\t_load_current_settings()\n\n\n#########################\n###       Public      ###\n#########################\n\n# NOTE: some settings need to be hidden while in-game\nfunc set_opened_in_game(opened_in_game: bool):\n\t_enable_plus_mode.visible = !opened_in_game\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _load_current_settings():\n\tvar selected_display_mode_int: int = Settings.get_setting(Settings.DISPLAY_MODE) as int\n\t_display_mode_combo.select(selected_display_mode_int)\n\t\n\tvar language_string: String = Settings.get_setting(Settings.LANGUAGE)\n\tvar selected_language_int: int = Language.get_option_from_locale(language_string)\n\t_language_combo.select(selected_language_int)\n\t\n\tfor setting in _setting_to_checkbox_map.keys():\n\t\tvar checkbox: CheckBox = _setting_to_checkbox_map[setting]\n\t\tvar enabled: bool = Settings.get_bool_setting(setting)\n\t\tcheckbox.set_pressed(enabled)\n\t\t\n\tfor setting in _setting_to_slider_map.keys():\n\t\tvar slider: Slider = _setting_to_slider_map[setting]\n\t\tvar value: float = Settings.get_setting(setting) as float\n\t\tslider.value = value\n\t\n\tvar selected_interface_size: Settings.InterfaceSize = Settings.get_interface_size_enum()\n\tfor button in _interface_size_button_to_size_map.keys():\n\t\tvar button_interface_size: Settings.InterfaceSize = _interface_size_button_to_size_map[button]\n\t\tvar button_is_selected: bool = button_interface_size == selected_interface_size\n\t\t\n\t\tif button_is_selected:\n\t\t\tbutton.set_pressed(true)\n\t\t\tbreak\n\t\n\t_clear_dirty_state()\n\n\n# NOTE: language and display settings are special cases and\n# are not handled here. Instead, they are handled in\n# specialised callbacks:\n# _on_display_mode_combo_item_selected() and\n# _on_language_item_selected()\nfunc _apply_changes():\n\tfor setting in _setting_to_checkbox_map.keys():\n\t\tvar checkbox: CheckBox = _setting_to_checkbox_map[setting]\n\t\tvar enabled: bool = checkbox.is_pressed()\n\t\tSettings.set_setting(setting, enabled)\n\t\n\tfor setting in _setting_to_slider_map.keys():\n\t\tvar slider: Slider = _setting_to_slider_map[setting]\n\t\tvar value: float = slider.value\n\t\tSettings.set_setting(setting, value)\n\t\n\tvar pressed_interface_size_button: Button = _interface_size_button_group.get_pressed_button()\n\tvar selected_interface_size: Settings.InterfaceSize = _interface_size_button_to_size_map[pressed_interface_size_button]\n\tSettings.set_setting(Settings.INTERFACE_SIZE, selected_interface_size)\n\n\t# NOTE: tricky interaction here, if the player disabled\n\t# the \"plus mode\" setting in the menu, then we need to\n\t# also disable all of the \"plus mode\" upgrades before\n\t# saving settings. The function below does this.\n\t_filter_wisdom_upgrades_based_on_plus_mode()\n\t\n\tSettings.flush()\n\t\n\t_clear_dirty_state()\n\n\nfunc _set_dirty_state():\n\t_is_dirty = true\n\t_apply_button.disabled = false\n\n\nfunc _clear_dirty_state():\n\t_is_dirty = false\n\t_apply_button.disabled = true\n\n\n# Disable all \"plus mode\" wisdom upgrades. This will also be\n# reflected in the wisdom upgrade UI in Profile menu because\n# Profile menu will pull in the changes when Profile menu is\n# opened.\nfunc _filter_wisdom_upgrades_based_on_plus_mode():\n\tvar plus_mode_is_enabled: bool = Settings.get_bool_setting(Settings.ENABLE_PLUS_MODE)\n\n\t# If plus mode is enabled, do not need to filter\n\t# anything because all upgrades are available\n\tif plus_mode_is_enabled:\n\t\treturn\n\n\tvar upgrades_cache: Dictionary = Settings.get_wisdom_upgrades()\n\tvar plus_mode_upgrade_list: Array = WisdomUpgradeProperties.get_plus_mode_upgrade_list()\n\n\tfor upgrade in plus_mode_upgrade_list:\n\t\tupgrades_cache[upgrade] = false\n\n\tSettings.set_setting(Settings.WISDOM_UPGRADES_CACHED, upgrades_cache)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_cancel_button_pressed():\n\t_load_current_settings()\n\tcancel_pressed.emit()\n\n\nfunc _on_apply_button_pressed():\n\t_apply_changes()\n\n\nfunc _on_ok_button_pressed():\n\t_apply_changes()\n\tok_pressed.emit()\n\n\nfunc _on_interface_size_button_group_pressed(_button: BaseButton):\n\t_set_dirty_state()\n\n\nfunc _on_slider_changed(_value: float):\n\t_set_dirty_state()\n\n\nfunc _on_combo_changed(_index: int):\n\t_set_dirty_state()\n\n\nfunc _on_checkbox_pressed():\n\t_set_dirty_state()\n\n\n# Load current settings when menu is opened. Need to do this because settings can get changed outside of this menu, in code.\nfunc _on_visibility_changed():\n\tif visible:\n\t\t_load_current_settings()\n\n\nfunc _on_display_mode_combo_item_selected(index: int):\n\tvar display_mode_int: int = index\n\tSettings.set_setting(Settings.DISPLAY_MODE, display_mode_int)\n\n\nfunc _on_language_item_selected(index: int) -> void:\n\tvar selected_locale: String = Language.get_locale_from_option(index)\n\tSettings.set_setting(Settings.LANGUAGE, selected_locale)\n"
  },
  {
    "path": "src/ui/game_menu/settings_menu.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://cx86ea3loo8a2\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_73d58\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/game_menu/settings_menu.gd\" id=\"2_2dtmk\"]\n[ext_resource type=\"ButtonGroup\" uid=\"uid://di3e75guncq3c\" path=\"res://resources/button_groups/interface_size_setting_button_group.tres\" id=\"2_fh8ol\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://bw17avoi3cj5m\" path=\"res://resources/theme/selected_unit_info/panel_container.tres\" id=\"4_o5p4r\"]\n\n[node name=\"SettingsMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_enable_plus_mode\", \"_damage_numbers\", \"_enable_floating_text\", \"_enable_vfx\", \"_enable_sfx\", \"_enable_mouse_scroll\", \"_show_combat_log\", \"_show_tutorial_on_start\", \"_projectile_density\", \"_mouse_scroll\", \"_keyboard_scroll\", \"_apply_button\", \"_display_mode_combo\", \"_language_combo\", \"_interface_size_button_small\", \"_interface_size_button_medium\", \"_interface_size_button_large\")]\ncustom_minimum_size = Vector2(800, 900)\ntheme = ExtResource(\"1_73d58\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_2dtmk\")\n_enable_plus_mode = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer/EnablePlusMode\")\n_damage_numbers = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/DamageNumbers\")\n_enable_floating_text = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/FloatingText\")\n_enable_vfx = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/EnableVfx\")\n_enable_sfx = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer/EnableSfx\")\n_enable_mouse_scroll = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer/EnableMouseScroll\")\n_show_combat_log = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer/ShowCombatLog\")\n_show_tutorial_on_start = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer/ShowTutorialOnStart\")\n_projectile_density = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/ProjectileDensity\")\n_mouse_scroll = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer/MouseScroll\")\n_keyboard_scroll = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer/KeyboardScroll\")\n_interface_size_button_group = ExtResource(\"2_fh8ol\")\n_apply_button = NodePath(\"MarginContainer/VBoxContainer/HBoxContainer/ApplyButton\")\n_display_mode_combo = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/DisplayModeCombo\")\n_language_combo = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/Language\")\n_interface_size_button_small = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/HBoxContainer7/SmallInterfaceSizeButton\")\n_interface_size_button_medium = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/HBoxContainer7/MediumInterfaceSizeButton\")\n_interface_size_button_large = NodePath(\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/HBoxContainer7/LargeInterfaceSizeButton\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_top = 15\ntheme_override_constants/margin_right = 15\ntheme_override_constants/margin_bottom = 15\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 15\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Settings\"\nhorizontal_alignment = 1\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_constants/margin_right = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_constants/separation = 20\n\n[node name=\"SectionOther\" type=\"PanelContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_styles/panel = ExtResource(\"4_o5p4r\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"SETTINGS_MISC\"\nhorizontal_alignment = 1\n\n[node name=\"EnablePlusMode\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"PLUS_MODE_TOOLTIP\"\ntext = \"PLUS_MODE\"\n\n[node name=\"EnableSfx\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_SFX\"\n\n[node name=\"ShowCombatLog\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_LOG\"\n\n[node name=\"ShowTutorialOnStart\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionOther/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_TUTRL\"\n\n[node name=\"SectionDisplay\" type=\"PanelContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_styles/panel = ExtResource(\"4_o5p4r\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"SETTINGS_SECTION_DISPLAY\"\nhorizontal_alignment = 1\n\n[node name=\"Label2\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\ntext = \"SETTINGS_DISPLAY_MODE\"\n\n[node name=\"DisplayModeCombo\" type=\"OptionButton\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nselected = 0\nitem_count = 3\npopup/item_0/text = \"SETTINGS_DISPLAY_MODE_FS\"\npopup/item_1/text = \"SETTINGS_DISPLAY_MODE_BFS\"\npopup/item_1/id = 1\npopup/item_2/text = \"SETTINGS_DISPLAY_MODE_W\"\npopup/item_2/id = 2\n\n[node name=\"LanguageLabel\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\ntext = \"SETTINGS_LANGUAGE\"\n\n[node name=\"Language\" type=\"OptionButton\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nselected = 0\nitem_count = 3\npopup/item_0/text = \"English\"\npopup/item_1/text = \"中文\"\npopup/item_1/id = 1\npopup/item_2/text = \"Italiana\"\npopup/item_2/id = 2\n\n[node name=\"InterfaceSizeLabel\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\ntext = \"SETTINGS_INTERFACE_SIZE\"\n\n[node name=\"HBoxContainer7\" type=\"HBoxContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"SmallInterfaceSizeButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/HBoxContainer7\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_override_colors/font_color = Color(1, 1, 1, 0.588235)\ntoggle_mode = true\nbutton_group = ExtResource(\"2_fh8ol\")\ntext = \"SETTINGS_INTERFACE_SMALL\"\nflat = true\n\n[node name=\"MediumInterfaceSizeButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/HBoxContainer7\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_override_colors/font_color = Color(1, 1, 1, 0.588235)\ntoggle_mode = true\nbutton_pressed = true\nbutton_group = ExtResource(\"2_fh8ol\")\ntext = \"SETTINGS_INTERFACE_MEDIUM\"\nflat = true\n\n[node name=\"LargeInterfaceSizeButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/HBoxContainer7\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_override_colors/font_color = Color(1, 1, 1, 0.588235)\ntoggle_mode = true\nbutton_group = ExtResource(\"2_fh8ol\")\ntext = \"SETTINGS_INTERFACE_LARGE\"\nflat = true\n\n[node name=\"DamageNumbers\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_DMG_NUM\"\n\n[node name=\"FloatingText\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_FLOATING_TXT\"\n\n[node name=\"EnableVfx\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"SETTINGS_VFX\"\n\n[node name=\"ProjectileDensityLabel\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"SETTINGS_TOOLTIP_PROJECTILE_DENSITY\"\nmouse_filter = 1\ntext = \"SETTINGS_PJT_DST\"\n\n[node name=\"ProjectileDensity\" type=\"HSlider\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer\"]\ncustom_minimum_size = Vector2(350, 0)\nlayout_mode = 2\nsize_flags_horizontal = 0\ntooltip_text = \"SETTINGS_TOOLTIP_PROJECTILE_DENSITY\"\nfocus_mode = 0\nmax_value = 1.0\nstep = 0.1\nscrollable = false\n\n[node name=\"SectionInput\" type=\"PanelContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_styles/panel = ExtResource(\"4_o5p4r\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"Label3\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"SETTINGS_INPUT\"\nhorizontal_alignment = 1\n\n[node name=\"EnableMouseScroll\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"SETTINGS_TOOLTIP_MOUSE_SCROLL\"\nfocus_mode = 0\ntext = \"SETTINGS_ENBL_MOUSE_SCRL\"\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer\"]\nlayout_mode = 2\ntext = \"SETTINGS_MOUSE_SCRL\"\n\n[node name=\"MouseScroll\" type=\"HSlider\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer\"]\ncustom_minimum_size = Vector2(350, 0)\nlayout_mode = 2\nsize_flags_horizontal = 0\nfocus_mode = 0\nmax_value = 1.0\nstep = 0.25\nvalue = 0.5\nscrollable = false\n\n[node name=\"Label2\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer\"]\nlayout_mode = 2\ntext = \"SETTINGS_KBD_SCRL\"\n\n[node name=\"KeyboardScroll\" type=\"HSlider\" parent=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionInput/VBoxContainer\"]\ncustom_minimum_size = Vector2(350, 0)\nlayout_mode = 2\nsize_flags_horizontal = 0\nfocus_mode = 0\nmax_value = 1.0\nstep = 0.25\nvalue = 0.5\nscrollable = false\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\n\n[node name=\"OkButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"OK\"\n\n[node name=\"CancelButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nfocus_mode = 0\ntext = \"CANCEL_BUTTON\"\n\n[node name=\"ApplyButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ndisabled = true\ntext = \"APPLY_BUTTON\"\n\n[connection signal=\"visibility_changed\" from=\".\" to=\".\" method=\"_on_visibility_changed\"]\n[connection signal=\"item_selected\" from=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/DisplayModeCombo\" to=\".\" method=\"_on_display_mode_combo_item_selected\"]\n[connection signal=\"item_selected\" from=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/Language\" to=\".\" method=\"_on_language_item_selected\"]\n[connection signal=\"ready\" from=\"MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer/SectionDisplay/VBoxContainer/Language\" to=\".\" method=\"_on_language_ready\"]\n[connection signal=\"pressed\" from=\"MarginContainer/VBoxContainer/HBoxContainer/OkButton\" to=\".\" method=\"_on_ok_button_pressed\"]\n[connection signal=\"pressed\" from=\"MarginContainer/VBoxContainer/HBoxContainer/CancelButton\" to=\".\" method=\"_on_cancel_button_pressed\"]\n[connection signal=\"pressed\" from=\"MarginContainer/VBoxContainer/HBoxContainer/ApplyButton\" to=\".\" method=\"_on_apply_button_pressed\"]\n"
  },
  {
    "path": "src/ui/hud/OneTimeHelpPopup.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cbp7l1tdfvept\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_elidx\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/one_time_help_popup.gd\" id=\"2_3qpff\"]\n\n[node name=\"OneTimeHelpPopup\" type=\"PanelContainer\"]\ncustom_minimum_size = Vector2(500, 0)\ntheme = ExtResource(\"1_elidx\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_3qpff\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 50\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nbbcode_enabled = true\ntext = \"ONE_TIME_HELP_POP\"\nfit_content = true\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\n\n[node name=\"CloseButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"CLOSE_BUTTON\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/hud/build_version_label.gd",
    "content": "extends Label\n\n\n# Called when the node enters the scene tree for the first time.\nfunc _ready():\n\ttext = Config.build_version()\n"
  },
  {
    "path": "src/ui/hud/build_version_label.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://i0b3uilwt2as\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/build_version_label.gd\" id=\"1_cj454\"]\n\n[node name=\"BuildVersionLabel\" type=\"Label\"]\nmodulate = Color(1, 1, 1, 0.537255)\nanchors_preset = 2\nanchor_top = 1.0\nanchor_bottom = 1.0\noffset_top = -26.0\noffset_right = 245.0\ngrow_vertical = 0\nmouse_filter = 1\ntext = \"Version: PLACEHOLDER\"\nscript = ExtResource(\"1_cj454\")\n"
  },
  {
    "path": "src/ui/hud/builder_menu.gd",
    "content": "class_name BuilderMenu extends PanelContainer\n\n\n# NOTE: the buttons for this menu are created\n# programmatically inside _ready().\n\n\nsignal finished()\n\n\n@export var _beginner_container: GridContainer\n@export var _advanced_container: GridContainer\n@export var _specialist_container: GridContainer\n@export var _hardcore_container: GridContainer\n\n\nvar _builder_id: int\n\n\nfunc _ready():\n\tvar builder_list: Array = BuilderProperties.get_id_list()\n\t\n\tfor builder in builder_list:\n\t\tvar short_name: String = BuilderProperties.get_short_name(builder)\n\n\t\tif short_name == \"none\":\n\t\t\tcontinue\n\n\t\tvar display_name: String = BuilderProperties.get_display_name(builder)\n\t\tvar description: String = BuilderProperties.get_description(builder)\n\t\tvar required_level: int = BuilderProperties.get_required_level(builder)\n\t\tvar local_player_level: int = Utils.get_local_player_level()\n\t\tvar builder_is_unlocked: bool = local_player_level >= required_level\n\n\t\tvar builder_tooltip: String\n\t\tif builder_is_unlocked:\n\t\t\tbuilder_tooltip = \"%s\\n \\n%s\" % [display_name, description]\n\t\telse:\n\t\t\tbuilder_tooltip = \"[color=GOLD]%s[/color] [color=RED]%d[/color]\\n \\n%s\\n \\n%s\" % [tr(\"BUILDER_REQUIRED_LEVEL\"), required_level, display_name, description]\n\t\t\n\t\tvar button: Button = Preloads.builder_button_scene.instantiate()\n\t\tvar icon_path: String = BuilderProperties.get_icon_path(builder)\n\t\tbutton.icon = load(icon_path)\n\t\tbutton.tooltip_text = builder_tooltip\n\t\tbutton.pressed.connect(_on_generic_button_pressed.bind(builder))\n\t\tbutton.disabled = !builder_is_unlocked\n\t\t\n\t\tvar container_for_button: GridContainer\n\t\tvar builder_tier: BuilderTier.enm = BuilderProperties.get_tier(builder)\n\t\tmatch builder_tier:\n\t\t\tBuilderTier.enm.BEGINNER: container_for_button = _beginner_container\n\t\t\tBuilderTier.enm.ADVANCED: container_for_button = _advanced_container\n\t\t\tBuilderTier.enm.SPECIALIST: container_for_button = _specialist_container\n\t\t\tBuilderTier.enm.HARDCORE: container_for_button = _hardcore_container\n\t\t\n\t\tcontainer_for_button.add_child(button)\n\n\nfunc get_builder_id() -> int:\n\treturn _builder_id\n\nfunc _on_generic_button_pressed(builder_id: int):\n\t_builder_id = builder_id\n\tfinished.emit()\n"
  },
  {
    "path": "src/ui/hud/builder_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://4dakdefm73rd\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_phv1q\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/builder_menu.gd\" id=\"2_es4f5\"]\n\n[node name=\"BuilderMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_beginner_container\", \"_advanced_container\", \"_specialist_container\", \"_hardcore_container\")]\ncustom_minimum_size = Vector2(700, 600)\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -132.5\noffset_top = -200.0\noffset_right = 132.5\noffset_bottom = 200.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_force_pass_scroll_events = false\ntheme = ExtResource(\"1_phv1q\")\ntheme_type_variation = &\"CenterPanel\"\nscript = ExtResource(\"2_es4f5\")\n_beginner_container = NodePath(\"VBoxContainer/ScrollContainer/VBoxContainer/BeginnerContainer\")\n_advanced_container = NodePath(\"VBoxContainer/ScrollContainer/VBoxContainer/AdvancedContainer\")\n_specialist_container = NodePath(\"VBoxContainer/ScrollContainer/VBoxContainer/SpecialistContainer\")\n_hardcore_container = NodePath(\"VBoxContainer/ScrollContainer/VBoxContainer/HardcoreContainer\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"BUILDER_MENU_TITLE\"\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\nhorizontal_scroll_mode = 0\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"VBoxContainer/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_constants/separation = 10\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"BUILDER_MENU_BEGINNER\"\nhorizontal_alignment = 1\n\n[node name=\"BeginnerContainer\" type=\"GridContainer\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 6\n\n[node name=\"Label2\" type=\"Label\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"BUILDER_MENU_ADVANCED\"\nhorizontal_alignment = 1\n\n[node name=\"AdvancedContainer\" type=\"GridContainer\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 6\n\n[node name=\"Label3\" type=\"Label\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"BUILDER_MENU_SPECIALIST\"\n\n[node name=\"SpecialistContainer\" type=\"GridContainer\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 6\n\n[node name=\"Label4\" type=\"Label\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"BUILDER_MENU_HARDCORE\"\nhorizontal_alignment = 1\n\n[node name=\"HardcoreContainer\" type=\"GridContainer\" parent=\"VBoxContainer/ScrollContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 6\n"
  },
  {
    "path": "src/ui/hud/combat_log_window.gd",
    "content": "extends MovableWindow\n\n\n# Displays log entries collected by CombatLog. Can be\n# shown/hidden via settings.\n\n# NOTE: using custom MovableWindow instead of the built-in\n# Godot class \"Window\" because Window steals all input focus\n# when you interact with it. You need to constantly click\n# outside of the Window to be able to give inputs to the\n# rest of the game, which is annoying. The custom\n# MovableWindow is missing some functionality but it works\n# nicely with the rest of the game in terms of input.\n\n\n# NOTE: 22 lines is the amount of lines which fit within\n# combat log window without causing the scrollbar to appear.\nconst DISPLAYED_LINE_COUNT: int = 22\n\n@export var _label: RichTextLabel\n@export var _up_button: Button\n@export var _down_button: Button\n\nvar _auto_scroll_to_newest: bool = true\nvar _displayed_max_index: int = 0\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tSettings.changed.connect(_on_settings_changed)\n\t_on_settings_changed()\n\t\n\tvar saved_pos_x: float = Settings.get_setting(Settings.COMBAT_LOG_X) as float\n\tvar saved_pos_y: float = Settings.get_setting(Settings.COMBAT_LOG_Y) as float\n\tglobal_position = Vector2(saved_pos_x, saved_pos_y)\n\n\nfunc _process(_delta: float):\n\tif !visible:\n\t\treturn\n\n\tvar combat_log_storage: Node = get_tree().get_root().get_node_or_null(\"GameScene/Gameplay/CombatLogStorage\")\n\n\tif combat_log_storage == null:\n\t\tpush_warning(\"CombatLogStorage is null. You can ignore this warning during game restart.\")\n\n\t\treturn\n\n\tvar text: String = \"\"\n\n\tvar displayed_min_index: int = _displayed_max_index - DISPLAYED_LINE_COUNT\n\t\n\tfor i in range(displayed_min_index, _displayed_max_index):\n\t\tvar entry_string: String = combat_log_storage.get_entry_string(i)\n\n\t\tif !entry_string.is_empty():\n\t\t\ttext += entry_string\n\t\t\ttext += \"\\n\"\n\t\telse:\n#\t\t\tPad lines which are out of bounds\n\t\t\ttext += \" \\n\"\n\n\t_label.clear()\n\t_label.append_text(text)\n\n#\tUpdate scrolling\n\tvar up_is_pressed: bool = _up_button.is_pressed()\n\tvar down_is_pressed: bool = _down_button.is_pressed()\n\n\tif up_is_pressed || down_is_pressed:\n\t\t_auto_scroll_to_newest = false\n\n\tif up_is_pressed:\n#\t\tAdd +1 so that at least one line is displayed at any\n#\t\ttime\n\t\t_displayed_max_index = max(combat_log_storage.get_min_index() + 1, _displayed_max_index - 1)\n\telif down_is_pressed:\n\t\t_displayed_max_index = min(combat_log_storage.get_max_index(), _displayed_max_index + 1)\n\n\t\tvar scrolled_to_bottom: bool = _displayed_max_index == combat_log_storage.get_max_index()\n\t\tif scrolled_to_bottom:\n\t\t\t_auto_scroll_to_newest = true\n\telif _auto_scroll_to_newest:\n\t\t_displayed_max_index = combat_log_storage.get_max_index()\n\n#\tCurrent display position can go out of bounds while\n#\tCombatLog erases messages which are too old. Move the\n#\tindex up in this case.\n\tif _displayed_max_index < combat_log_storage.get_min_index():\n\t\t_displayed_max_index = combat_log_storage.get_min_index() + 1\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_settings_changed():\n\tvar show_combat_log: bool = Settings.get_bool_setting(Settings.SHOW_COMBAT_LOG)\n\tvisible = show_combat_log\n\n\nfunc _on_auto_down_button_pressed():\n\t_auto_scroll_to_newest = true\n\n\nfunc _on_clear_button_pressed():\n\tEventBus.player_requested_to_clear_combatlog.emit()\n\t_auto_scroll_to_newest = true\n\n\nfunc _on_drag_finished():\n\tSettings.set_setting(Settings.COMBAT_LOG_X, global_position.x)\n\tSettings.set_setting(Settings.COMBAT_LOG_Y, global_position.y, )\n\tSettings.flush()\n"
  },
  {
    "path": "src/ui/hud/combat_log_window.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://bx5csta8pr8j0\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://b5c8ayamq02xc\" path=\"res://src/ui/hud/movable_window.tscn\" id=\"1_idb0e\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_0ysdc\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/combat_log_window.gd\" id=\"2_oel1x\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_1s8u8\"]\nbg_color = Color(0.2, 0.2, 0.2, 0.705882)\n\n[node name=\"CombatLogWindow\" node_paths=PackedStringArray(\"_label\", \"_up_button\", \"_down_button\") instance=ExtResource(\"1_idb0e\")]\ncustom_minimum_size = Vector2(1000, 600)\noffset_right = 500.0\noffset_bottom = 340.0\nmouse_filter = 0\nmouse_force_pass_scroll_events = false\ntheme = ExtResource(\"2_0ysdc\")\nscript = ExtResource(\"2_oel1x\")\n_label = NodePath(\"MarginContainer/HBoxContainer/PanelContainer2/RichTextLabel\")\n_up_button = NodePath(\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer/UpButton\")\n_down_button = NodePath(\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer/DownButton\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\" index=\"1\"]\nlayout_mode = 2\nsize_flags_vertical = 3\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer\" index=\"0\"]\nlayout_mode = 2\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"MarginContainer/HBoxContainer\" index=\"0\"]\nlayout_mode = 2\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/HBoxContainer/PanelContainer\" index=\"0\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\nalignment = 2\n\n[node name=\"ClearButton\" type=\"Button\" parent=\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer\" index=\"0\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_override_font_sizes/font_size = 30\ntext = \"🚮\"\n\n[node name=\"UpButton\" type=\"Button\" parent=\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer\" index=\"1\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_override_font_sizes/font_size = 30\ntext = \"🔼\"\n\n[node name=\"DownButton\" type=\"Button\" parent=\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer\" index=\"2\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_override_font_sizes/font_size = 30\ntext = \"🔽\"\n\n[node name=\"AutoDownButton\" type=\"Button\" parent=\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer\" index=\"3\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 8\ntooltip_text = \"COMBAT_LOG_TOOLTIP_AUTO_DOWN\"\nfocus_mode = 0\ntheme_override_font_sizes/font_size = 30\ntext = \"⏬\"\n\n[node name=\"PanelContainer2\" type=\"PanelContainer\" parent=\"MarginContainer/HBoxContainer\" index=\"1\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_styles/panel = SubResource(\"StyleBoxFlat_1s8u8\")\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"MarginContainer/HBoxContainer/PanelContainer2\" index=\"0\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nfocus_mode = 2\ntheme_override_font_sizes/bold_italics_font_size = 22\ntheme_override_font_sizes/italics_font_size = 22\ntheme_override_font_sizes/mono_font_size = 22\ntheme_override_font_sizes/normal_font_size = 22\ntheme_override_font_sizes/bold_font_size = 22\ntext = \"text\"\nscroll_active = false\nscroll_following = true\nselection_enabled = true\n\n[connection signal=\"drag_finished\" from=\".\" to=\".\" method=\"_on_drag_finished\"]\n[connection signal=\"pressed\" from=\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer/ClearButton\" to=\".\" method=\"_on_clear_button_pressed\"]\n[connection signal=\"pressed\" from=\"MarginContainer/HBoxContainer/PanelContainer/VBoxContainer/AutoDownButton\" to=\".\" method=\"_on_auto_down_button_pressed\"]\n"
  },
  {
    "path": "src/ui/hud/desync_indicator.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://wqmh2igy5bn4\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_nai01\"]\n\n[node name=\"DesyncIndicator\" type=\"PanelContainer\"]\ncustom_minimum_size = Vector2(400, 0)\noffset_right = 400.0\noffset_bottom = 220.0\ntheme = ExtResource(\"1_nai01\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"Label\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntext = \"Desync bug detected!\n \nThe worlds have diverged and you may encounter issues if you continue playing.\"\nautowrap_mode = 3\n"
  },
  {
    "path": "src/ui/hud/elements_menu.gd",
    "content": "class_name ElementsMenu extends PanelContainer\n\n\n@export var _ice_button: ElementButton\n@export var _fire_button: ElementButton\n@export var _nature_button: ElementButton\n@export var _darkness_button: ElementButton\n@export var _iron_button: ElementButton\n@export var _astral_button: ElementButton\n@export var _storm_button: ElementButton\n@export var _roll_towers_button: Button\n\n@onready var _button_map: Dictionary = {\n\tElement.enm.ICE: _ice_button,\n\tElement.enm.FIRE: _fire_button,\n\tElement.enm.NATURE: _nature_button,\n\tElement.enm.DARKNESS: _darkness_button,\n\tElement.enm.IRON: _iron_button,\n\tElement.enm.ASTRAL: _astral_button,\n\tElement.enm.STORM: _storm_button,\n}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar game_mode_is_build: bool = Globals.get_game_mode() == GameMode.enm.BUILD\n\tif game_mode_is_build:\n\t\t_hide_roll_towers_button()\n\n\tfor element in _button_map.keys():\n\t\tvar button: ElementButton = _button_map[element]\n\t\tbutton.set_level(0)\n\t\t\n\t\tbutton.mouse_entered.connect(_on_button_mouse_entered.bind(button, element))\n\t\tbutton.pressed.connect(_on_button_pressed.bind(element))\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\tlocal_player.element_level_changed.connect(_on_element_level_changed)\n\t_on_element_level_changed()\n\n\tlocal_player.roll_was_disabled.connect(_on_local_player_roll_was_disabled)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _hide_roll_towers_button():\n\t_roll_towers_button.hide()\n\n\nfunc _show_element_tooltip(button: Button, element: Element.enm):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar tooltip: String = RichTexts.get_research_text(element, local_player)\n\tButtonTooltip.show_tooltip(button, tooltip)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_local_player_roll_was_disabled():\n\t_hide_roll_towers_button()\n\n\nfunc _on_element_level_changed():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar element_levels: Dictionary = local_player.get_element_level_map()\n\t\n\tvar current_tooltip_target: Button = ButtonTooltip.get_current_target()\n\t\n\tfor element in element_levels.keys():\n\t\tvar button: ElementButton = _button_map[element]\n\t\tvar element_level: int = element_levels[element]\n\t\tbutton.set_level(element_level)\n\t\t\n#\t\tNOTE: need to manually refresh button tooltip,\n#\t\totherwise it will keep showing old element level\n#\t\twhich is confusing for the player\n\t\tif button == current_tooltip_target:\n\t\t\t_show_element_tooltip(button, element)\n\n\nfunc _on_button_mouse_entered(button: Button, element: Element.enm):\n\t_show_element_tooltip(button, element)\n\n\nfunc _on_button_pressed(element: Element.enm):\n\tEventBus.player_requested_to_research_element.emit(element)\n\n\nfunc _on_roll_towers_button_pressed():\n\tEventBus.player_requested_to_roll_towers.emit()\n\n\nfunc _on_close_button_pressed():\n\thide()\n\n\nfunc _on_roll_towers_button_mouse_entered():\n\tvar tooltip: String = tr(\"ROLL_TOWERS_BUTTON_TOOLTIP\")\n\tButtonTooltip.show_tooltip(_roll_towers_button, tooltip)\n"
  },
  {
    "path": "src/ui/hud/elements_menu.tscn",
    "content": "[gd_scene load_steps=16 format=3 uid=\"uid://bg77tobjy7jgy\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/elements_menu.gd\" id=\"2_ge6sb\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bpdanpr2im0gg\" path=\"res://src/ui/buttons/element_button.tscn\" id=\"2_w3jvl\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b7c8ugpn34iib\" path=\"res://resources/icons/elements/darkness.tres\" id=\"4_6xdvu\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bvhrjk28kmjxg\" path=\"res://resources/icons/elements/fire.tres\" id=\"5_7kvqd\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c14cl1op1y5wk\" path=\"res://resources/icons/elements/nature.tres\" id=\"7_ogjdt\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"7_yfjau\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://ofrvficsj8ih\" path=\"res://resources/icons/elements/storm.tres\" id=\"8_7t7v5\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"9_i2wqn\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://3aghxlv6b4hb\" path=\"res://resources/icons/elements/iron.tres\" id=\"9_kb0cq\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b58m66c4f8n2n\" path=\"res://resources/icons/elements/astral.tres\" id=\"10_41iut\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c7uoycvu5ii8v\" path=\"res://resources/icons/hud/dice.tres\" id=\"10_qe6ob\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dex1xjcdq1fv7\" path=\"res://resources/ui_textures/rect_container_m.tres\" id=\"10_wf4k3\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_touq2\"]\n\n[sub_resource type=\"StyleBoxTexture\" id=\"StyleBoxTexture_j6gup\"]\ncontent_margin_left = 20.0\ncontent_margin_right = 20.0\ncontent_margin_bottom = 5.0\ntexture = ExtResource(\"10_wf4k3\")\ntexture_margin_left = 13.9504\ntexture_margin_top = 14.0\ntexture_margin_right = 14.0\ntexture_margin_bottom = 13.9504\nregion_rect = Rect2(1283, 192, 139, 154)\nmodulate_color = Color(0.588235, 0.588235, 0.588235, 1)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wh5fy\"]\natlas = ExtResource(\"7_yfjau\")\nregion = Rect2(896, 0, 128, 128)\n\n[node name=\"ElementsMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_ice_button\", \"_fire_button\", \"_nature_button\", \"_darkness_button\", \"_iron_button\", \"_astral_button\", \"_storm_button\", \"_roll_towers_button\")]\ncustom_minimum_size = Vector2(400, 160)\noffset_right = 755.0\noffset_bottom = 160.0\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_touq2\")\nscript = ExtResource(\"2_ge6sb\")\n_ice_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/IceButton\")\n_fire_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/FireButton\")\n_nature_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/NatureButton\")\n_darkness_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/DarknessButton\")\n_iron_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/IronButton\")\n_astral_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/AstralButton\")\n_storm_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/StormButton\")\n_roll_towers_button = NodePath(\"TabContainer/MainTab/MarginContainer2/GridContainer/RollTowersButton\")\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\".\"]\nlayout_mode = 2\ncurrent_tab = 0\ntabs_visible = false\n\n[node name=\"MainTab\" type=\"VBoxContainer\" parent=\"TabContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\ntheme_override_constants/separation = 20\nmetadata/_tab_index = 0\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"TabContainer/MainTab\"]\nlayout_mode = 2\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"TabContainer/MainTab/MarginContainer2\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 10\ncolumns = 8\n\n[node name=\"RollTowersButton\" type=\"Button\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\"]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\nfocus_mode = 0\ntheme = ExtResource(\"9_i2wqn\")\ntheme_type_variation = &\"TinyUnitButton\"\nicon = ExtResource(\"10_qe6ob\")\nicon_alignment = 1\nexpand_icon = true\n\n[node name=\"DarknessButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\nicon = ExtResource(\"4_6xdvu\")\n\n[node name=\"FireButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\nicon = ExtResource(\"5_7kvqd\")\n\n[node name=\"NatureButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\nicon = ExtResource(\"7_ogjdt\")\n\n[node name=\"IronButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\nicon = ExtResource(\"9_kb0cq\")\n\n[node name=\"StormButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\nicon = ExtResource(\"8_7t7v5\")\n\n[node name=\"AstralButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\nicon = ExtResource(\"10_41iut\")\n\n[node name=\"IceButton\" parent=\"TabContainer/MainTab/MarginContainer2/GridContainer\" instance=ExtResource(\"2_w3jvl\")]\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -15\n\n[node name=\"TitleLabel\" type=\"Label\" parent=\"MarginContainer\"]\ncustom_minimum_size = Vector2(200, 0)\nlayout_mode = 2\ntheme_override_font_sizes/font_size = 26\ntheme_override_styles/normal = SubResource(\"StyleBoxTexture_j6gup\")\ntext = \"ELEMENTS_MENU_TITLE\"\nhorizontal_alignment = 1\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nicon = SubResource(\"AtlasTexture_wh5fy\")\nicon_alignment = 1\nexpand_icon = true\n\n[connection signal=\"mouse_entered\" from=\"TabContainer/MainTab/MarginContainer2/GridContainer/RollTowersButton\" to=\".\" method=\"_on_roll_towers_button_mouse_entered\"]\n[connection signal=\"pressed\" from=\"TabContainer/MainTab/MarginContainer2/GridContainer/RollTowersButton\" to=\".\" method=\"_on_roll_towers_button_pressed\"]\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/hud/floating_text.gd",
    "content": "class_name FloatingText extends Node2D\n\n\nconst SEC_TO_MSEC: float = 1000\n\n\n@export var label: Label\n\n# NOTE: customize these values before calling adding\n# floating text to scene\nvar text: String = \"placeholder\"\n# The amount of time in seconds, after which floating text disappears\nvar duration: float = 4.0\n# The amount of time in seconds, after which floating text starts fading\nvar fadepoint: float = 2.0\n# NOTE: velocity is in pixels/ms\nvar velocity: Vector2 = Vector2(0, -0.05)\nvar color: Color = Color.WHITE\n# This random offset is applied to the initial position of\n# the floating text, both x and y coordinates.\nvar random_offset: float = 0.0\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tlabel.text = text\n\tmodulate = color\n\n\tposition += Vector2(Globals.local_rng.randf_range(-random_offset, random_offset), Globals.local_rng.randf_range(-random_offset, random_offset))\n\n# \tText bounces up and right\n\tvar pos_tween = create_tween()\n\tvar duration_msec: float = duration * SEC_TO_MSEC\n\tvar offset: Vector2 = velocity * duration_msec\n\tpos_tween.tween_property(self, \"position\",\n\t\tposition + offset,\n\t\t1.0 * duration).set_trans(Tween.TRANS_LINEAR)\n\n# \tText fades away to nothing at the end\n\tif fadepoint < duration:\n\t\tvar modulate_tween = create_tween()\n\t\tvar fade_duration: float = duration - fadepoint\n\t\tmodulate_tween.tween_property(self, \"modulate\",\n\t\t\tColor(modulate.r, modulate.g, modulate.b, 0),\n\t\t\tfade_duration).set_trans(Tween.TRANS_LINEAR).set_delay(fadepoint)\n\n\tvar queue_free_tween = create_tween()\n\tqueue_free_tween.tween_callback(queue_free).set_delay(duration)\n\n\tvar enable_floating_text: bool = Settings.get_bool_setting(Settings.ENABLE_FLOATING_TEXT)\n\tvisible = enable_floating_text\n"
  },
  {
    "path": "src/ui/hud/floating_text.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://vgeirnu7ramn\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/floating_text.gd\" id=\"2\"]\n\n[node name=\"FloatingText\" type=\"Node2D\" node_paths=PackedStringArray(\"label\")]\nscript = ExtResource(\"2\")\nlabel = NodePath(\"Label\")\n\n[node name=\"Label\" type=\"Label\" parent=\".\"]\noffset_right = 40.0\noffset_bottom = 14.0\ntheme_override_font_sizes/font_size = 40\ntext = \"TEST\"\n"
  },
  {
    "path": "src/ui/hud/flying_item.gd",
    "content": "class_name FlyingItem extends Control\n\n\n# Visual effect for item flying from the ground into item\n# stash. Has to be a Control because visual's position needs\n# to be unaffected by camera movement. Note that item stays\n# inside an invisible item during flying.\n\n# NOTE: flying item doesn't affect game state so it's okay\n# to use tweens here.\n\n\nvar _item_id: int = 0\nvar _end_pos: Vector2 = Vector2.ZERO\n\n@export var _button: Button\n@export var _rarity_background: RarityBackground\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# Called when the node enters the scene tree for the first time.\nfunc _ready():\n\tvar icon: Texture2D = ItemProperties.get_icon(_item_id)\n\tvar rarity: Rarity.enm = ItemProperties.get_rarity(_item_id)\n\t_button.set_button_icon(icon)\n\t_rarity_background.set_rarity(rarity)\n\n\tvar game_speed: int = Globals.get_update_ticks_per_physics_tick()\n\tvar fly_duration_actual: float = Item.FLY_DURATION / float(game_speed)\n\n\tvar pos_tween = create_tween()\n\tpos_tween.tween_property(self, \"position\",\n\t\t_end_pos,\n\t\tfly_duration_actual).set_trans(Tween.TRANS_SINE)\n\n\tvar scale_tween = create_tween()\n\tscale_tween.tween_property(self, \"scale\",\n\t\tVector2(0, 0),\n\t\t0.3 * fly_duration_actual).set_delay(0.7 * fly_duration_actual)\n\n\tvar finished_tween = create_tween()\n\tfinished_tween.tween_callback(_on_tween_finished).set_delay(fly_duration_actual)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_tween_finished():\n\tqueue_free()\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func create(item_id: int, start_pos: Vector2, end_pos: Vector2) -> FlyingItem:\n\tvar flying_item: FlyingItem = Preloads.flying_item_scene.instantiate()\n\tflying_item.position = start_pos\n\tflying_item._end_pos = end_pos\n\tflying_item._item_id = item_id\n\n\treturn flying_item\n"
  },
  {
    "path": "src/ui/hud/flying_item.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://cfkqoriruwxt8\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/flying_item.gd\" id=\"1_5ump5\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"3_vx2oo\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bbax2xlr25ajb\" path=\"res://resources/icons/mechanical/compass.tres\" id=\"4_42i2u\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8mjwtvwfpjf5\" path=\"res://src/ui/buttons/rarity_background.tscn\" id=\"4_jqp1b\"]\n\n[node name=\"FlyingItem\" type=\"Control\" node_paths=PackedStringArray(\"_button\", \"_rarity_background\")]\nlayout_mode = 3\nanchors_preset = 0\nscript = ExtResource(\"1_5ump5\")\n_button = NodePath(\"Button\")\n_rarity_background = NodePath(\"Button/RarityBackground\")\n\n[node name=\"Button\" type=\"Button\" parent=\".\"]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 1\noffset_right = 80.0\noffset_bottom = 80.0\nfocus_mode = 0\nmouse_filter = 2\ntheme = ExtResource(\"3_vx2oo\")\ntheme_type_variation = &\"TinyUnitButton\"\nicon = ExtResource(\"4_42i2u\")\nicon_alignment = 1\nexpand_icon = true\n\n[node name=\"RarityBackground\" parent=\"Button\" instance=ExtResource(\"4_jqp1b\")]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 2\ngrow_vertical = 2\n"
  },
  {
    "path": "src/ui/hud/game_speed_controller.gd",
    "content": "extends HBoxContainer\n\n\n# NOTE: disable game speed controls in multiplayer.\n# Gamespeed can still be altered via /gamespeed command but\n# this UI should be hidden to prevent host from using it too\n# often.\nfunc _ready():\n\tvar game_player_mode: PlayerMode.enm = Globals.get_player_mode()\n\tvar game_is_singleplayer: bool = game_player_mode == PlayerMode.enm.SINGLEPLAYER\n\n\tif !game_is_singleplayer:\n\t\thide()\n\t\t\n\t\tvar button_list: Array[Node] = get_children()\n\t\tfor button in button_list:\n\t\t\tbutton.disabled = true\n\n\n#########################\n###     Callbacks     ###\n#########################\n\n\nfunc _on_speed_normal_toggled(button_pressed: bool):\n\tif button_pressed:\n\t\tGlobals.set_update_ticks_per_physics_tick(Constants.GAME_SPEED_NORMAL)\n\n\nfunc _on_speed_fast_toggled(button_pressed: bool):\n\tif button_pressed:\n\t\tGlobals.set_update_ticks_per_physics_tick(Constants.GAME_SPEED_FAST)\n\n\nfunc _on_speed_fastest_toggled(button_pressed: bool):\n\tif button_pressed:\n\t\tGlobals.set_update_ticks_per_physics_tick(Constants.GAME_SPEED_FASTEST)\n"
  },
  {
    "path": "src/ui/hud/game_speed_controller.tscn",
    "content": "[gd_scene load_steps=12 format=3 uid=\"uid://n8326r4m33s3\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/game_speed_controller.gd\" id=\"1_ak56x\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dq1y6eowvvl45\" path=\"res://src/ui/buttons/speed_button.tscn\" id=\"1_vx7on\"]\n[ext_resource type=\"ButtonGroup\" uid=\"uid://5mj7ntug0txa\" path=\"res://resources/button_groups/speed_button_group.tres\" id=\"2_3te4o\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://cny5e3y68r18y\" path=\"res://resources/ui_textures/speed_fast.tres\" id=\"3_co8ko\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://c1cbjc01sbgsu\" path=\"res://resources/ui_textures/speed_fastest.tres\" id=\"4_5fx06\"]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_6ubjv\"]\ndevice = -1\nkeycode = 49\nunicode = 49\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_8c3lr\"]\nevents = [SubResource(\"InputEventKey_6ubjv\")]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_6jvxc\"]\ndevice = -1\nkeycode = 50\nunicode = 50\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_5psg1\"]\nevents = [SubResource(\"InputEventKey_6jvxc\")]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_26jvu\"]\ndevice = -1\nkeycode = 51\nunicode = 51\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_uebri\"]\nevents = [SubResource(\"InputEventKey_26jvu\")]\n\n[node name=\"GameSpeedController\" type=\"HBoxContainer\"]\nscript = ExtResource(\"1_ak56x\")\n\n[node name=\"SpeedNormal\" parent=\".\" instance=ExtResource(\"1_vx7on\")]\nlayout_mode = 2\ntooltip_text = \"GAMESPEED_TOOLTIP_NORMAL\"\nbutton_pressed = true\nbutton_group = ExtResource(\"2_3te4o\")\nshortcut = SubResource(\"Shortcut_8c3lr\")\n\n[node name=\"SpeedFast\" parent=\".\" instance=ExtResource(\"1_vx7on\")]\nlayout_mode = 2\ntooltip_text = \"GAMESPEED_TOOLTIP_FAST\"\nbutton_group = ExtResource(\"2_3te4o\")\nshortcut = SubResource(\"Shortcut_5psg1\")\nicon = ExtResource(\"3_co8ko\")\n\n[node name=\"SpeedFastest\" parent=\".\" instance=ExtResource(\"1_vx7on\")]\nlayout_mode = 2\ntooltip_text = \"GAMESPEED_TOOLTIP_FASTEST\"\nbutton_group = ExtResource(\"2_3te4o\")\nshortcut = SubResource(\"Shortcut_uebri\")\nicon = ExtResource(\"4_5fx06\")\n\n[connection signal=\"toggled\" from=\"SpeedNormal\" to=\".\" method=\"_on_speed_normal_toggled\"]\n[connection signal=\"toggled\" from=\"SpeedFast\" to=\".\" method=\"_on_speed_fast_toggled\"]\n[connection signal=\"toggled\" from=\"SpeedFastest\" to=\".\" method=\"_on_speed_fastest_toggled\"]\n"
  },
  {
    "path": "src/ui/hud/hud.gd",
    "content": "class_name HUD extends Control\n\n\n@export var _error_message_container: VBoxContainer\n@export var _normal_message_container: VBoxContainer\n@export var _game_over_label: RichTextLabel\n@export var _elements_menu: ElementsMenu\n@export var _tower_stash_menu: TowerStashMenu\n@export var _item_stash_menu: ItemStashMenu\n@export var _tower_stash_button: MenuExpandingButton\n@export var _item_stash_button: MenuExpandingButton\n@export var _top_left_menu: TopLeftMenu\n@export var _unit_menu: UnitMenu\n@export var _chat_line_edit: LineEdit\n@export var _desync_indicator: PanelContainer\n@export var _button_tooltip_top: ButtonTooltip\n@export var _button_tooltip_bottom: ButtonTooltip\n@export var _tower_details: TowerDetails\n@export var _creep_details: CreepDetails\n@export var _ping_label: Label\n@export var _players_are_lagging_indicator: MarginContainer\n@export var _lagging_player_list_label: Label\n@export var _multiplayer_pause_indicator: Control\n@export var _mission_tracker_container: MissionTrackerContainer\n@export var _one_time_help_popup: OneTimeHelpPopup\n\n# NOTE: this list is ordered by priority of closure. If\n# multiple windows are open, then the first window in the\n# list will be closed, others will stay.\n@onready var _window_list: Array = [_tower_details, _creep_details, _elements_menu, _tower_stash_menu, _item_stash_menu]\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tif OS.is_debug_build() && Config.dev_controls_enabled():\n\t\t$DevControls.call_deferred(\"create_instance\")\n\t\n\tEventBus.item_started_flying_to_item_stash.connect(_on_item_started_flying_to_item_stash)\n\n\tButtonTooltip.setup_tooltip_instances(_button_tooltip_top, _button_tooltip_bottom)\n\n\tvar showed_one_time_help_popup: bool = Settings.get_bool_setting(Settings.SHOWED_ONE_TIME_HELP_POPUP)\n\t_one_time_help_popup.visible = !showed_one_time_help_popup\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_multiplayer_pause_indicator_visible(value: bool):\n\t_multiplayer_pause_indicator.visible = value\n\n\nfunc toggle_ping_indicator_visibility():\n\t_ping_label.visible = !_ping_label.visible\n\n\nfunc set_waiting_for_lagging_players_indicator_visible(indicator_visible: bool):\n\t_players_are_lagging_indicator.visible = indicator_visible\n\n\nfunc set_waiting_for_lagging_players_indicator_player_list(lagging_player_list: Array):\n\tvar lagging_player_list_text: String = \"\"\n\t\n\tfor player_name in lagging_player_list:\n\t\tlagging_player_list_text += \"%s\\n\" % player_name\n\n\t_lagging_player_list_label.text = lagging_player_list_text\n\n\nfunc set_ping_time(ping_time_ms: float):\n\t_ping_label.text = tr(\"HUD_PING_DISPLAY\").format({TIME_MS = ceil(ping_time_ms)})\n\n\nfunc show_desync_indicator():\n\t_desync_indicator.show()\n\n\nfunc start_editing_chat():\n\t_chat_line_edit.show()\n\t_chat_line_edit.grab_focus()\n\n\nfunc finish_editing_chat():\n\t_chat_line_edit.clear()\n\t_chat_line_edit.hide()\n\n\nfunc enter_slash_into_chat():\n\t_chat_line_edit.text = \"/\"\n\t_chat_line_edit.caret_column = 1\n\n\nfunc editing_chat() -> bool:\n\treturn _chat_line_edit.visible\n\n\nfunc get_chat_edit_text() -> String:\n\tvar text: String = _chat_line_edit.text\n\n\treturn text\n\n\nfunc add_chat_message(player: Player, message: String):\n\tvar player_is_ignored: bool = player.get_chat_ignored()\n\tif player_is_ignored:\n\t\tprint_verbose(\"Skipping chat message from ignored player %s: %s\" % [player.get_player_name(), message])\n\n\t\treturn\n\n#\tNOTE: don't need to sanitize player name here because it\n#\talready is sanitized.\n\tvar player_color: Color = player.get_color()\n\tvar player_name: String = player.get_player_name()\n\n#\tNOTE: chat message input field has a length limit but we\n#\tstill need to limit the length here as well just in\n#\tcase.\n\tmessage = message.substr(0, Constants.MAX_CHAT_MESSAGE_LENGTH)\n\tmessage = Utils.escape_bbcode(message)\n\n\tvar complete_message: String = \"[color=%s]%s:[/color] %s\" % [player_color.to_html(), player_name, message]\n\t\n\tMessages.add_normal(null, complete_message)\n\n\n# Set tower or creep which should be displayed in unit menus\n# NOTE: the callback for set_pressed() which make tower menu\n# or creep menu visible.\nfunc set_menu_unit(unit: Unit):\n\t_unit_menu.set_unit(unit)\n\t_unit_menu.visible = unit != null\n\t\n\tvar tower: Tower = unit as Tower\n\tvar creep: Creep = unit as Creep\n\t_tower_details.set_tower(tower)\n\t_creep_details.set_creep(creep)\n\n\tif tower == null:\n\t\t_tower_details.hide()\n\tif creep == null:\n\t\t_creep_details.hide()\n\n\nfunc connect_to_local_player(local_player: Player):\n\tlocal_player.rolled_starting_towers.connect(_on_local_player_rolled_towers)\n\t\n\t_item_stash_menu.connect_to_local_player(local_player)\n\t_tower_stash_menu.connect_to_local_player(local_player)\n\t_elements_menu.connect_to_local_player(local_player)\n\t_top_left_menu.connect_to_local_player(local_player)\n\n\tvar local_team: Team = local_player.get_team()\n\tlocal_team.game_lose.connect(_on_local_game_lose)\n\n\nfunc set_game_start_timer(timer: ManualTimer):\n\t_top_left_menu.set_game_start_timer(timer)\n\n\nfunc close_one_window():\n\tfor window in _window_list:\n\t\tif window.visible:\n\t\t\twindow.hide()\n\t\t\tbreak\n\n\nfunc set_mission_track_state(mission_id: int, state: MissionTrackIndicator.State):\n\t_mission_tracker_container.set_mission_track_state(mission_id, state)\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc get_error_message_container() -> VBoxContainer:\n\treturn _error_message_container\n\n\nfunc get_normal_message_container() -> VBoxContainer:\n\treturn _normal_message_container\n\n\nfunc any_window_is_open() -> bool:\n\tfor window in _window_list:\n\t\tif window.visible:\n\t\t\treturn true\n\t\n\treturn false\n\n\n# Manually press status button for tower stash menu to\n# switch to tower stash menu after rolling towers.\nfunc _on_local_player_rolled_towers():\n\t_tower_stash_button.set_pressed(true)\n\n\nfunc _on_item_started_flying_to_item_stash(item: Item, canvas_pos: Vector2):\n\tif !item.belongs_to_local_player():\n\t\treturn\n\n\tvar item_stash_button_pos: Vector2 = _item_stash_button.global_position + Vector2(45, 45)\n\tvar item_id: int = item.get_id()\n\n\tvar flying_item: FlyingItem = FlyingItem.create(item_id, canvas_pos, item_stash_button_pos)\n\tflying_item.visible = item.is_visible()\n\tadd_child(flying_item)\n\n\nfunc _on_unit_menu_details_pressed():\n\tvar current_unit: Unit = _unit_menu.get_unit()\n\t\n\tif current_unit is Tower:\n\t\t_tower_details.visible = !_tower_details.visible\n\t\t_creep_details.visible = false\n\t\n\t\t_tower_details.update_text()\n\telif current_unit is Creep:\n\t\t_tower_details.visible = false\n\t\t_creep_details.visible = !_creep_details.visible\n\t\n\t\t_creep_details.update_text()\n\telse:\n\t\t_tower_details.visible = false\n\t\t_creep_details.visible = false\n\n\nfunc _on_local_game_lose():\n\t_game_over_label.show()\n\n\nfunc _on_quit_button_pressed():\n\tEventBus.player_requested_quit_to_title.emit()\n\n\nfunc _on_one_time_help_popup_close_pressed() -> void:\n\t_one_time_help_popup.visible = false\n\tSettings.set_setting(Settings.SHOWED_ONE_TIME_HELP_POPUP, true)\n\tSettings.flush()\n"
  },
  {
    "path": "src/ui/hud/hud.tscn",
    "content": "[gd_scene load_steps=27 format=3 uid=\"uid://cngv1rgplre2c\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_xs0tv\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bakuxdbe6a7f0\" path=\"res://src/ui/hud/mission_tracker_container.tscn\" id=\"5_n7x4d\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cbp7l1tdfvept\" path=\"res://src/ui/hud/OneTimeHelpPopup.tscn\" id=\"6_05w81\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dwexxkjguqohm\" path=\"res://src/ui/buttons/menu_expanding_button.tscn\" id=\"7_2qbjb\"]\n[ext_resource type=\"ButtonGroup\" uid=\"uid://deklccjgbh0k0\" path=\"res://resources/button_groups/menu_cards_button_group.tres\" id=\"7_8m5sl\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://n8326r4m33s3\" path=\"res://src/ui/hud/game_speed_controller.tscn\" id=\"9_ilyra\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b3grhp7bp5t54\" path=\"res://src/ui/top_left_menu/top_left_menu.tscn\" id=\"10_agdn3\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://1sklksk2awnr\" path=\"res://resources/icons/hud/research_elements.tres\" id=\"10_ylm6g\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/hud.gd\" id=\"11\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ino0lr2m12uh\" path=\"res://src/ui/item_stash_menu/item_stash_menu.tscn\" id=\"11_5i6a2\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://nl0pvhb4rasi\" path=\"res://src/ui/buttons/button_tooltip.tscn\" id=\"11_ka7k1\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://boxxhen27xatf\" path=\"res://resources/icons/hud/item_stash.tres\" id=\"12_vixmf\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bx5csta8pr8j0\" path=\"res://src/ui/hud/combat_log_window.tscn\" id=\"14_g64vx\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://donslrrviy807\" path=\"res://src/ui/tower_stash_menu/tower_stash_menu.tscn\" id=\"15_eivr8\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cc70ktmpmbjts\" path=\"res://src/ui/player_resource_display/player_resource_display.tscn\" id=\"15_ir4hq\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b6l4hi00yx7js\" path=\"res://src/ui/unit_menu/tower_details.tscn\" id=\"17_12w0v\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bg77tobjy7jgy\" path=\"res://src/ui/hud/elements_menu.tscn\" id=\"17_bxii1\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b1l5uiun5nhhx\" path=\"res://src/ui/unit_menu/creep_details.tscn\" id=\"18_acgvt\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dcqjart40vpjy\" path=\"res://src/ui/unit_menu/unit_menu.tscn\" id=\"19_bqmfs\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://wqmh2igy5bn4\" path=\"res://src/ui/hud/desync_indicator.tscn\" id=\"19_mcs2s\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://c4jswu0s2yq2o\" path=\"res://src/ui/hud/multiplayer_pause_indicator.tscn\" id=\"20_cbamn\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://i0b3uilwt2as\" path=\"res://src/ui/hud/build_version_label.tscn\" id=\"21_ko2ou\"]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_hfkwl\"]\nphysical_keycode = 84\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_ejtke\"]\nevents = [SubResource(\"InputEventKey_hfkwl\")]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_cgjl0\"]\ndevice = -1\nphysical_keycode = 73\nunicode = 105\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_ree63\"]\nevents = [SubResource(\"InputEventKey_cgjl0\")]\n\n[node name=\"HUD\" type=\"Control\" node_paths=PackedStringArray(\"_error_message_container\", \"_normal_message_container\", \"_game_over_label\", \"_elements_menu\", \"_tower_stash_menu\", \"_item_stash_menu\", \"_tower_stash_button\", \"_item_stash_button\", \"_top_left_menu\", \"_unit_menu\", \"_chat_line_edit\", \"_desync_indicator\", \"_button_tooltip_top\", \"_button_tooltip_bottom\", \"_tower_details\", \"_creep_details\", \"_ping_label\", \"_players_are_lagging_indicator\", \"_lagging_player_list_label\", \"_multiplayer_pause_indicator\", \"_mission_tracker_container\", \"_one_time_help_popup\")]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 4\ntheme = ExtResource(\"1_xs0tv\")\nscript = ExtResource(\"11\")\n_error_message_container = NodePath(\"MarginContainer8/ErrorMessageContainer\")\n_normal_message_container = NodePath(\"MarginContainer/VBoxContainer/NormalMessageContainer\")\n_game_over_label = NodePath(\"GameOverLabel\")\n_elements_menu = NodePath(\"MarginContainer7/MarginContainer3/VBoxContainer/ElementsMenu\")\n_tower_stash_menu = NodePath(\"MarginContainer7/MarginContainer2/HBoxContainer/TowerStashMenu\")\n_item_stash_menu = NodePath(\"MarginContainer7/MarginContainer2/HBoxContainer/ItemStashMenu\")\n_tower_stash_button = NodePath(\"MarginContainer7/MarginContainer/VBoxContainer/TowerStashButton\")\n_item_stash_button = NodePath(\"MarginContainer7/MarginContainer/VBoxContainer/ItemStashButton\")\n_top_left_menu = NodePath(\"MarginContainer2/TopLeftMenu\")\n_unit_menu = NodePath(\"MarginContainer5/VBoxContainer2/UnitMenu\")\n_chat_line_edit = NodePath(\"MarginContainer/VBoxContainer/MarginContainer/ChatLineEdit\")\n_desync_indicator = NodePath(\"DesyncIndicator\")\n_button_tooltip_top = NodePath(\"MarginContainer7/MarginContainer2/HBoxContainer/MarginContainer/ButtonTooltipTop\")\n_button_tooltip_bottom = NodePath(\"MarginContainer5/VBoxContainer2/ButtonTooltipBottom\")\n_tower_details = NodePath(\"MarginContainer4/TowerDetails\")\n_creep_details = NodePath(\"MarginContainer4/CreepDetails\")\n_ping_label = NodePath(\"MarginContainer10/VBoxContainer/PingLabel\")\n_players_are_lagging_indicator = NodePath(\"PlayersAreLaggingIndicator\")\n_lagging_player_list_label = NodePath(\"PlayersAreLaggingIndicator/PanelContainer/VBoxContainer/VBoxContainer2/LaggingPlayerListLabel\")\n_multiplayer_pause_indicator = NodePath(\"MultiplayerPauseIndicator\")\n_mission_tracker_container = NodePath(\"MarginContainer3/VBoxContainer/MissionTrackerContainer\")\n_one_time_help_popup = NodePath(\"MarginContainer3/VBoxContainer/OneTimeHelpPopup\")\nmetadata/_edit_vertical_guides_ = [960.0]\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(1000, 0)\nlayout_mode = 1\nanchors_preset = 2\nanchor_top = 1.0\nanchor_bottom = 1.0\noffset_top = -1454.0\noffset_right = 1000.0\ngrow_vertical = 0\nsize_flags_horizontal = 0\nsize_flags_vertical = 3\nmouse_filter = 2\ntheme_override_constants/margin_left = 80\ntheme_override_constants/margin_bottom = 350\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\nmouse_filter = 2\nalignment = 2\n\n[node name=\"NormalMessageContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 1050)\nlayout_mode = 2\nmouse_filter = 2\nalignment = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"MarginContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 50)\nlayout_mode = 2\nmouse_filter = 2\n\n[node name=\"ChatLineEdit\" type=\"LineEdit\" parent=\"MarginContainer/VBoxContainer/MarginContainer\"]\nvisible = false\nlayout_mode = 2\nmax_length = 200\ncontext_menu_enabled = false\nvirtual_keyboard_enabled = false\nshortcut_keys_enabled = false\nmiddle_mouse_paste_enabled = false\nselecting_enabled = false\ncaret_blink = true\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\noffset_right = 730.0\noffset_bottom = 388.0\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_top = 15\n\n[node name=\"TopLeftMenu\" parent=\"MarginContainer2\" instance=ExtResource(\"10_agdn3\")]\nlayout_mode = 2\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 5\nanchor_left = 0.5\nanchor_right = 0.5\noffset_left = -287.0\noffset_right = 287.0\noffset_bottom = 61.0\ngrow_horizontal = 2\ntheme_override_constants/margin_top = 15\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer3\"]\nlayout_mode = 2\n\n[node name=\"PlayerResourceDisplay\" parent=\"MarginContainer3/VBoxContainer\" instance=ExtResource(\"15_ir4hq\")]\nunique_name_in_owner = true\nlayout_mode = 2\nsize_flags_horizontal = 4\nmetadata/_edit_vertical_guides_ = []\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"MarginContainer3/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 20)\nlayout_mode = 2\n\n[node name=\"MissionTrackerContainer\" parent=\"MarginContainer3/VBoxContainer\" instance=ExtResource(\"5_n7x4d\")]\nlayout_mode = 2\n\n[node name=\"OneTimeHelpPopup\" parent=\"MarginContainer3/VBoxContainer\" instance=ExtResource(\"6_05w81\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"MarginContainer4\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\noffset_left = 15.0\noffset_top = 15.0\noffset_right = 15.0\noffset_bottom = 95.0\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_top = 80\n\n[node name=\"TowerDetails\" parent=\"MarginContainer4\" instance=ExtResource(\"17_12w0v\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"CreepDetails\" parent=\"MarginContainer4\" instance=ExtResource(\"18_acgvt\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"MarginContainer5\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 7\nanchor_left = 0.5\nanchor_top = 1.0\nanchor_right = 0.5\nanchor_bottom = 1.0\noffset_left = -20.0\noffset_top = -40.0\noffset_right = 20.0\ngrow_horizontal = 2\ngrow_vertical = 0\ntheme_override_constants/margin_bottom = 15\n\n[node name=\"VBoxContainer2\" type=\"VBoxContainer\" parent=\"MarginContainer5\"]\nlayout_mode = 2\n\n[node name=\"ButtonTooltipBottom\" parent=\"MarginContainer5/VBoxContainer2\" instance=ExtResource(\"11_ka7k1\")]\nvisible = false\nz_index = 1\nlayout_mode = 2\nsize_flags_horizontal = 4\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"MarginContainer5/VBoxContainer2\"]\ncustom_minimum_size = Vector2(0, 50)\nlayout_mode = 2\nmouse_filter = 2\n\n[node name=\"UnitMenu\" parent=\"MarginContainer5/VBoxContainer2\" instance=ExtResource(\"19_bqmfs\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"MarginContainer6\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 3\nanchor_left = 1.0\nanchor_top = 1.0\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_left = -40.0\noffset_top = -40.0\ngrow_horizontal = 0\ngrow_vertical = 0\ntheme_override_constants/margin_right = 15\ntheme_override_constants/margin_bottom = 15\n\n[node name=\"GameSpeedController\" parent=\"MarginContainer6\" instance=ExtResource(\"9_ilyra\")]\nlayout_mode = 2\n\n[node name=\"MarginContainer7\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 1\nanchor_left = 1.0\nanchor_right = 1.0\noffset_left = -130.0\noffset_bottom = 418.0\ngrow_horizontal = 0\nmouse_filter = 2\ntheme_override_constants/margin_top = 15\ntheme_override_constants/margin_right = 15\n\n[node name=\"MarginContainer4\" type=\"MarginContainer\" parent=\"MarginContainer7\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = 50\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer7/MarginContainer4\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\n\n[node name=\"ElementsMenuButton\" parent=\"MarginContainer7/MarginContainer4/VBoxContainer\" node_paths=PackedStringArray(\"_menu\") instance=ExtResource(\"7_2qbjb\")]\nlayout_mode = 2\ntooltip_text = \"HUD_TOOLTIP_ELEMENTS\"\nicon = ExtResource(\"10_ylm6g\")\n_menu = NodePath(\"../../../MarginContainer3/VBoxContainer/ElementsMenu\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"MarginContainer7\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = 250\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer7/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\n\n[node name=\"TowerStashButton\" parent=\"MarginContainer7/MarginContainer/VBoxContainer\" node_paths=PackedStringArray(\"_menu\") instance=ExtResource(\"7_2qbjb\")]\nlayout_mode = 2\ntooltip_text = \"HUD_TOOLTIP_TOWER_STASH\"\nbutton_group = ExtResource(\"7_8m5sl\")\nshortcut = SubResource(\"Shortcut_ejtke\")\n_menu = NodePath(\"../../../MarginContainer2/HBoxContainer/TowerStashMenu\")\n\n[node name=\"ItemStashButton\" parent=\"MarginContainer7/MarginContainer/VBoxContainer\" node_paths=PackedStringArray(\"_menu\") instance=ExtResource(\"7_2qbjb\")]\nlayout_mode = 2\ntooltip_text = \"HUD_TOOLTIP_ITEM_STASH\"\nbutton_group = ExtResource(\"7_8m5sl\")\nshortcut = SubResource(\"Shortcut_ree63\")\nicon = ExtResource(\"12_vixmf\")\n_menu = NodePath(\"../../../MarginContainer2/HBoxContainer/ItemStashMenu\")\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\"MarginContainer7\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = 20\ntheme_override_constants/margin_right = 120\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer7/MarginContainer3\"]\nlayout_mode = 2\n\n[node name=\"ElementsMenu\" parent=\"MarginContainer7/MarginContainer3/VBoxContainer\" instance=ExtResource(\"17_bxii1\")]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"MarginContainer7\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = 210\ntheme_override_constants/margin_right = 120\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer7/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_vertical = 3\nmouse_filter = 2\ntheme_override_constants/separation = 30\nalignment = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"MarginContainer7/MarginContainer2/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 0\nmouse_filter = 2\ntheme_override_constants/margin_top = 40\n\n[node name=\"ButtonTooltipTop\" parent=\"MarginContainer7/MarginContainer2/HBoxContainer/MarginContainer\" instance=ExtResource(\"11_ka7k1\")]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\n\n[node name=\"ItemStashMenu\" parent=\"MarginContainer7/MarginContainer2/HBoxContainer\" instance=ExtResource(\"11_5i6a2\")]\nvisible = false\nlayout_mode = 2\nsize_flags_vertical = 0\n\n[node name=\"TowerStashMenu\" parent=\"MarginContainer7/MarginContainer2/HBoxContainer\" instance=ExtResource(\"15_eivr8\")]\nvisible = false\nlayout_mode = 2\nsize_flags_vertical = 0\n\n[node name=\"MarginContainer8\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 5\nanchor_left = 0.5\nanchor_right = 0.5\noffset_left = -350.0\noffset_right = 350.0\noffset_bottom = 300.0\ngrow_horizontal = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\nmouse_filter = 2\ntheme_override_constants/margin_top = 200\n\n[node name=\"ErrorMessageContainer\" type=\"VBoxContainer\" parent=\"MarginContainer8\"]\ncustom_minimum_size = Vector2(700, 200)\nlayout_mode = 2\nmouse_filter = 2\nalignment = 2\n\n[node name=\"DevControls\" parent=\".\" instance_placeholder=\"res://src/ui/dev_controls/dev_controls.tscn\"]\nvisible = false\nlayout_mode = 1\nmouse_filter = 2\n\n[node name=\"CombatLogWindow\" parent=\".\" instance=ExtResource(\"14_g64vx\")]\nclip_contents = true\ncustom_minimum_size = Vector2(0, 0)\nlayout_mode = 1\nanchors_preset = 4\nanchor_top = 0.5\nanchor_bottom = 0.5\noffset_top = -251.5\noffset_right = 1000.0\noffset_bottom = 251.5\ngrow_vertical = 2\n\n[node name=\"MarginContainer10\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 2\nanchor_top = 1.0\nanchor_bottom = 1.0\noffset_top = -40.0\noffset_right = 107.0\ngrow_vertical = 0\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer10\"]\nlayout_mode = 2\n\n[node name=\"PingLabel\" type=\"Label\" parent=\"MarginContainer10/VBoxContainer\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"LabelSmall\"\ntext = \"Ping: 123ms\"\n\n[node name=\"BuildVersionLabel\" parent=\"MarginContainer10/VBoxContainer\" instance=ExtResource(\"21_ko2ou\")]\nlayout_mode = 2\ntext = \"Version: 1.2.3\"\n\n[node name=\"GameOverLabel\" type=\"RichTextLabel\" parent=\".\"]\nvisible = false\ncustom_minimum_size = Vector2(600, 0)\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -300.0\noffset_top = -56.0\noffset_right = 300.0\noffset_bottom = 56.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme_override_font_sizes/normal_font_size = 80\nbbcode_enabled = true\ntext = \"[center][color=RED]GAME OVER[/color]\n[font_size=30][color=RED]Press Escape and Quit to Title to Restart[/color][/font_size][/center]\"\nfit_content = true\n\n[node name=\"DesyncIndicator\" parent=\".\" instance=ExtResource(\"19_mcs2s\")]\nvisible = false\nlayout_mode = 1\nanchors_preset = 3\nanchor_left = 1.0\nanchor_top = 1.0\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_left = -400.0\noffset_top = -220.0\noffset_right = 0.0\noffset_bottom = 0.0\ngrow_horizontal = 0\ngrow_vertical = 0\n\n[node name=\"PlayersAreLaggingIndicator\" type=\"MarginContainer\" parent=\".\"]\nvisible = false\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_filter = 0\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"PlayersAreLaggingIndicator\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 4\ntheme = ExtResource(\"1_xs0tv\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PlayersAreLaggingIndicator/PanelContainer\"]\nlayout_mode = 2\n\n[node name=\"VBoxContainer2\" type=\"VBoxContainer\" parent=\"PlayersAreLaggingIndicator/PanelContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PlayersAreLaggingIndicator/PanelContainer/VBoxContainer/VBoxContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"WAIT_FOR_LAG\"\n\n[node name=\"LaggingPlayerListLabel\" type=\"Label\" parent=\"PlayersAreLaggingIndicator/PanelContainer/VBoxContainer/VBoxContainer2\"]\nlayout_mode = 2\ntext = \"Dave\nAlice\"\nhorizontal_alignment = 1\n\n[node name=\"QuitButton\" type=\"Button\" parent=\"PlayersAreLaggingIndicator/PanelContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"Quit to Title\"\n\n[node name=\"MultiplayerPauseIndicator\" parent=\".\" instance=ExtResource(\"20_cbamn\")]\nvisible = false\nlayout_mode = 1\n\n[connection signal=\"close_pressed\" from=\"MarginContainer3/VBoxContainer/OneTimeHelpPopup\" to=\".\" method=\"_on_one_time_help_popup_close_pressed\"]\n[connection signal=\"details_pressed\" from=\"MarginContainer5/VBoxContainer2/UnitMenu\" to=\".\" method=\"_on_unit_menu_details_pressed\"]\n[connection signal=\"pressed\" from=\"PlayersAreLaggingIndicator/PanelContainer/VBoxContainer/QuitButton\" to=\".\" method=\"_on_quit_button_pressed\"]\n"
  },
  {
    "path": "src/ui/hud/label_with_rich_tooltip.gd",
    "content": "class_name LabelWithRichTooltip extends Label\n\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n"
  },
  {
    "path": "src/ui/hud/mission_track_indicator.gd",
    "content": "class_name MissionTrackIndicator extends HBoxContainer\n\n\n# Shows status of tracked mission to the player during game match.\n\n\nenum State {\n\tIN_PROGRESS,\n\tFAILED,\n\tCOMPLETED,\n}\n\nvar _mission_id: int\n\n@export var _description_label: Label\n@export var _in_progress_label: Label\n@export var _failed_label: Label\n@export var _completed_label: Label\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar description: String = MissionProperties.get_description(_mission_id)\n\t_description_label.text = description\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_state(state: MissionTrackIndicator.State):\n\t_in_progress_label.visible = state == MissionTrackIndicator.State.IN_PROGRESS\n\t_failed_label.visible = state == MissionTrackIndicator.State.FAILED\n\t_completed_label.visible = state == MissionTrackIndicator.State.COMPLETED\n\n\nstatic func make(mission_id: int) -> MissionTrackIndicator:\n\tvar mission_track_indicator: MissionTrackIndicator = Preloads.mission_track_indicator_scene.instantiate()\n\tmission_track_indicator._mission_id = mission_id\n\t\n\treturn mission_track_indicator\n"
  },
  {
    "path": "src/ui/hud/mission_track_indicator.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://ci8lnw401fw5k\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/mission_track_indicator.gd\" id=\"1_5faqm\"]\n\n[node name=\"MissionTrackIndicator\" type=\"HBoxContainer\" node_paths=PackedStringArray(\"_description_label\", \"_in_progress_label\", \"_failed_label\", \"_completed_label\")]\ncustom_minimum_size = Vector2(800, 0)\nmouse_filter = 2\nscript = ExtResource(\"1_5faqm\")\n_description_label = NodePath(\"DescriptionLabel\")\n_in_progress_label = NodePath(\"InProgressLabel\")\n_failed_label = NodePath(\"FailedLabel\")\n_completed_label = NodePath(\"CompletedLabel\")\n\n[node name=\"DescriptionLabel\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Beat 240 Medium Upgrade while never going above 35 food\"\nautowrap_mode = 2\n\n[node name=\"BarCharacterLabel\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"-\"\n\n[node name=\"InProgressLabel\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"IN PROGRESS\"\n\n[node name=\"FailedLabel\" type=\"Label\" parent=\".\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntheme_override_colors/font_color = Color(0.941176, 0, 0, 1)\ntext = \"FAILED\"\n\n[node name=\"CompletedLabel\" type=\"Label\" parent=\".\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"COMPLETED\"\n"
  },
  {
    "path": "src/ui/hud/mission_tracker_container.gd",
    "content": "class_name MissionTrackerContainer extends VBoxContainer\n\n\n# Contains mission trackers which is shown in HUD.\n\n\nvar _indicator_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready() -> void:\n\tvar mission_id_list: Array = MissionProperties.get_id_list()\n\t\n\tvar added_mission_count: int = 0\n\t\n\tfor mission_id in mission_id_list:\n\t\tvar mission_is_tracked: bool = MissionTracking.get_mission_is_tracked(mission_id)\n\t\tvar mission_is_completed: bool = MissionStatus.get_mission_is_complete(mission_id)\n\t\t\n\t\tif mission_is_completed:\n\t\t\tcontinue\n\t\t\n\t\tif mission_is_tracked:\n\t\t\tvar mission_track_indicator: MissionTrackIndicator = MissionTrackIndicator.make(mission_id)\n\t\t\t_indicator_map[mission_id] = mission_track_indicator\n\t\t\tadd_child(mission_track_indicator)\n\t\t\tadded_mission_count += 1\n\t\t\t\n\t\t\tif added_mission_count >= MissionTracking.MAX_TRACKED_COUNT:\n\t\t\t\tbreak\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_mission_track_state(mission_id: int, state: MissionTrackIndicator.State):\n\tif !_indicator_map.has(mission_id):\n\t\treturn\n\n\tvar indicator: MissionTrackIndicator = _indicator_map.get(mission_id)\n\tindicator.set_state(state)\n"
  },
  {
    "path": "src/ui/hud/mission_tracker_container.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://bakuxdbe6a7f0\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/mission_tracker_container.gd\" id=\"1_ey1nt\"]\n\n[node name=\"MissionTrackerContainer\" type=\"VBoxContainer\"]\nscript = ExtResource(\"1_ey1nt\")\n"
  },
  {
    "path": "src/ui/hud/movable_window.gd",
    "content": "class_name MovableWindow extends VBoxContainer\n\n\n# Window which can be moved by dragging the title label.\n# It's a partial reimplementation of Godot's built-in Window\n# class but without having using a separate Viewport which\n# avoids some problems like splitting input focus.\n\n\nsignal drag_finished()\n\n\nenum State {\n\tIDLE,\n\tDRAGGING,\n}\n\n@export var _title_panel: PanelContainer\n\nvar _drag_state: State = State.IDLE\nvar _drag_offset: Vector2 = Vector2.ZERO\n\n\nfunc _input(event: InputEvent):\n\tif !event is InputEventMouse:\n\t\treturn\n\n\tvar viewport_scale: Vector2 = get_viewport_transform().get_scale()\n\tvar input_pos: Vector2 = event.global_position / viewport_scale\n\tvar title_pos: Vector2 = _title_panel.global_position\n\tvar title_size: Vector2 = _title_panel.get_size()\n\tvar title_rect: Rect2 = Rect2(title_pos, title_size)\n\tvar clicked_on_title_label: bool = event.is_action_pressed(\"left_click\") && title_rect.has_point(input_pos)\n\t\n\tif event.is_action_released(\"left_click\"):\n\t\t_drag_state = State.IDLE\n\n\t\treturn\n\n\tif clicked_on_title_label:\n\t\t_drag_state = State.DRAGGING\n\t\t_drag_offset = global_position - input_pos\n\t\n\tvar drag_is_in_progress: bool = event is InputEventMouseMotion && _drag_state == State.DRAGGING\n\t\n\tif drag_is_in_progress:\n\t\tglobal_position = input_pos + _drag_offset\n\t\tdrag_finished.emit()\n"
  },
  {
    "path": "src/ui/hud/movable_window.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b5c8ayamq02xc\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/movable_window.gd\" id=\"1_kbggf\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_607to\"]\ncontent_margin_left = 5.0\ncontent_margin_top = 5.0\ncontent_margin_right = 5.0\ncontent_margin_bottom = 5.0\nbg_color = Color(0.0901961, 0.0901961, 0.0901961, 1)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\ncorner_radius_top_left = 5\ncorner_radius_top_right = 5\ncorner_radius_bottom_right = 5\ncorner_radius_bottom_left = 5\n\n[node name=\"MovableWindow\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_title_panel\")]\ncustom_minimum_size = Vector2(500, 300)\nscript = ExtResource(\"1_kbggf\")\n_title_panel = NodePath(\"TitlePanel\")\n\n[node name=\"TitlePanel\" type=\"PanelContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\ntheme_override_styles/panel = SubResource(\"StyleBoxFlat_607to\")\n\n[node name=\"TitleLabel\" type=\"Label\" parent=\"TitlePanel\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\ntext = \"Combat Log\"\n"
  },
  {
    "path": "src/ui/hud/multiplayer_pause_indicator.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://c4jswu0s2yq2o\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_6cjgb\"]\n\n[node name=\"MultiplayerPauseIndicator\" type=\"Control\"]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"ColorRect\" type=\"ColorRect\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_force_pass_scroll_events = false\ncolor = Color(0, 0, 0, 0.392157)\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(350, 0)\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -2.5\noffset_top = -14.5\noffset_right = 2.5\noffset_bottom = 14.5\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme = ExtResource(\"1_6cjgb\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"PAUSED\"\nhorizontal_alignment = 1\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"Game was paused by host. Unpause by typing \\\"/unpause\\\".\"\nautowrap_mode = 2\n"
  },
  {
    "path": "src/ui/hud/one_time_help_popup.gd",
    "content": "class_name OneTimeHelpPopup extends PanelContainer\n\n\n# This is a one time popup which is shown when player starts\n# up the game for the first time. It tells the player the\n# basics about how to pause the game and that there's a Help\n# menu. It's need to make sure that players learn about\n# Pause and Help menu (even though the Tutorial also teaches\n# about this).\n\n\nsignal close_pressed()\n\n\nfunc _on_close_button_pressed() -> void:\n\tclose_pressed.emit()\n"
  },
  {
    "path": "src/ui/hud/rich_text_label_with_rich_tooltip.gd",
    "content": "class_name RichTextLabelWithRichTooltip extends RichTextLabel\n\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n"
  },
  {
    "path": "src/ui/hud/texture_rect_with_rich_tooltip.gd",
    "content": "class_name TextureRectWithRichTooltip extends TextureRect\n\n\n# This TextureRect has a RichTextLabel tooltip. Normal\n# TextureRect class supports only Label tooltips.\n\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n"
  },
  {
    "path": "src/ui/hud/tutorial_menu.gd",
    "content": "class_name TutorialMenu extends PanelContainer\n\n\n@export var _text_label: RichTextLabel\n@export var _display_tutorial_check_box: CheckBox\n\n\nvar _tutorial_id: int = -1\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_tutorial_id(tutorial_id: int):\n\t_tutorial_id = tutorial_id\n\n\tvar tutorial_title: String = TutorialProperties.get_title(tutorial_id)\n\tvar tutorial_text: String = TutorialProperties.get_text(tutorial_id)\n\tvar text: String = \"[color=GOLD]%s[/color]\\n \\n%s\" % [tutorial_title, tutorial_text]\n\t\n\t_text_label.clear()\n\t_text_label.append_text(text)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_okay_button_pressed():\n\tvar display_tutorial_checkbox_is_checked: bool = _display_tutorial_check_box.is_pressed()\n\tif !display_tutorial_checkbox_is_checked:\n\t\tSettings.set_setting(Settings.SHOW_TUTORIAL_ON_START, false)\n\t\tSettings.flush()\n\n\thide()\n\n\tEventBus.finished_tutorial_section.emit()\n"
  },
  {
    "path": "src/ui/hud/tutorial_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://u1yl8rbswhtp\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_hsqnm\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/tutorial_menu.gd\" id=\"2_a3117\"]\n\n[node name=\"TutorialMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_text_label\", \"_display_tutorial_check_box\")]\nprocess_mode = 1\noffset_right = 700.0\noffset_bottom = 502.0\nsize_flags_horizontal = 3\nsize_flags_vertical = 0\ntheme = ExtResource(\"1_hsqnm\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_a3117\")\n_text_label = NodePath(\"MarginContainer/VBoxContainer/TextLabel\")\n_display_tutorial_check_box = NodePath(\"MarginContainer/VBoxContainer/HBoxContainer/DisplayTutorialCheckBox\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"TextLabel\" type=\"RichTextLabel\" parent=\"MarginContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(600, 200)\nlayout_mode = 2\nbbcode_enabled = true\ntext = \"[center][img]res://assets/tutorial_pictures/research_element.png[/img][/center]\n \nBefore you can start building towers, you need to research elements. You can research elements in the Elements menu.\\\"\"\nfit_content = true\nscroll_active = false\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"DisplayTutorialCheckBox\" type=\"CheckBox\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntheme = ExtResource(\"1_hsqnm\")\nbutton_pressed = true\ntext = \"DISPLAY_TUTORIAL_BUTTON\"\n\n[node name=\"Spacer\" type=\"HBoxContainer\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"OkayButton\" type=\"Button\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Okay\"\n\n[connection signal=\"pressed\" from=\"MarginContainer/VBoxContainer/HBoxContainer/OkayButton\" to=\".\" method=\"_on_okay_button_pressed\"]\n"
  },
  {
    "path": "src/ui/item_stash_menu/item_stash_menu.gd",
    "content": "@tool\nclass_name ItemStashMenu extends PanelContainer\n\n\n# NOTE: these are visible counts, not total possible counts\n# NOTE: set min row count to 6 to have one row extra at\n# startup. Otherwise item stash would go from having no\n# scroll bar to having a scroll bar which is weird behavior.\nconst MIN_ROW_COUNT: int = 6\nconst COLUMN_COUNT: int = 6\n\n\n# This UI element displays items which are currently in the\n# item stash.\n@export var _rarity_filter: RarityFilter\n@export var _item_type_filter_container: VBoxContainer\n@export var _background_grid: GridContainer\n@export var _item_grid: GridContainer\n@export var _item_scroll_container: ScrollContainer\n\n@export var _backpacker_recipes: GridContainer\n@export var _horadric_item_container_panel: ItemContainerPanel\n@export var _transmute_button: Button\n\n@export var _horadric_cube_avg_item_level_label: Label\n@export var _lock_filter_button: Button\n\n#########################\n### Code starts here  ###\n#########################\n\n# NOTE: the background buttons are also added while the scene is open in editor, to check how it looks visually.\nfunc _ready():\n\tvar min_slot_count: int = MIN_ROW_COUNT * COLUMN_COUNT\n\t\n\tfor i in range(0, min_slot_count):\n\t\tvar slot_button: Button = _make_slot_button()\n\t\tslot_button.modulate = Color.WHITE\n\t\t_background_grid.add_child(slot_button)\n\t\n\tif Engine.is_editor_hint():\n\t\treturn\n\t\n\tvar recipe_buttons: Array[Node] = get_tree().get_nodes_in_group(\"recipe_buttons\")\n\tfor node in recipe_buttons:\n\t\tvar recipe_button: RecipeButton = node as RecipeButton\n\t\tvar recipe: HoradricCube.Recipe = recipe_button.recipe\n\t\trecipe_button.pressed.connect(_on_recipe_button_pressed.bind(recipe))\n\t\t\n#\t\tNOTE: recipe buttons start out disabled until items\n#\t\tare added to item stash\n\t\trecipe_button.disabled = true\n\t\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\tvar horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\t_horadric_item_container_panel.set_item_container(horadric_stash)\n\t\n\thoradric_stash.items_changed.connect(_on_horadric_stash_items_changed)\n\t_on_horadric_stash_items_changed()\n\n\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\titem_stash.items_changed.connect(_on_item_stash_changed)\n\t_on_item_stash_changed()\n\n\tlocal_player.selected_builder.connect(_on_local_player_selected_builder)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _make_slot_button() -> EmptyUnitButton:\n\tvar button: Button = EmptyUnitButton.make()\n\tbutton.custom_minimum_size = Constants.ITEM_BUTTON_SIZE\n\tbutton.pressed.connect(_on_slot_button_pressed.bind(button))\n\tbutton.modulate = Color.TRANSPARENT\n\t\n\treturn button\n\n\nfunc _make_item_button(item: Item) -> ItemButton:\n\tvar item_button: ItemButton = ItemButton.make()\n\titem_button.set_item(item)\n\titem_button.set_horadric_lock_visible(true)\n\titem_button.pressed.connect(_on_item_button_pressed.bind(item_button))\n\titem_button.right_clicked.connect(_on_item_button_right_clicked.bind(item_button))\n\titem_button.ctrl_right_clicked.connect(_on_item_button_ctrl_right_clicked.bind(item_button))\n\titem_button.horadric_lock_changed.connect(_on_item_button_horadric_lock_changed)\n\t\n\treturn item_button\n\n\nfunc _get_filter_is_none() -> bool:\n\tvar rarity_filter: Array[Rarity.enm] = _rarity_filter.get_filter()\n\tvar item_type_filter: Array = _item_type_filter_container.get_filter()\n\tvar lock_filter: bool = _lock_filter_button.is_pressed()\n\t\n\tvar filter_is_none: bool = rarity_filter.size() == Rarity.get_list().size() \\\n\t && item_type_filter.size() == ItemType.get_list().size() && \\\n\t!lock_filter\n\n\treturn filter_is_none\n\n\nfunc _load_current_filter():\n\tvar filter_is_none: bool = _get_filter_is_none()\n\n\tif filter_is_none:\n\t\tfor child in _item_grid.get_children():\n\t\t\tchild.show()\n\t\t\n\t\treturn\n\n#\tNOTE: reset scroll position when a filter is defined. If\n#\tthis is not done, a player may scroll down, turn on a\n#\tfilter and then see empty stash even though there are\n#\titems at the beginning, before visible scrolled area.\n\tUtils.reset_scroll_container(_item_scroll_container)\n\n#\tShow/hide item buttons depending on whether they match\n#\tcurrent filter\n\tvar rarity_filter: Array[Rarity.enm] = _rarity_filter.get_filter()\n\tvar item_type_filter: Array = _item_type_filter_container.get_filter()\n\tvar lock_filter: bool = _lock_filter_button.is_pressed()\n\t\n#\tWhen there's a filter, hide all empty slots and show\n#\titem buttons which match the filter\n\tfor child in _item_grid.get_children():\n\t\tvar button: ItemButton = child as ItemButton\n\t\tvar item: Item = button.get_item()\n\n#\t\tNOTE: item buttons become transparent if the item is\n#\t\tnull but still need to hide the button to make item\n#\t\tgrid contiguous\n\t\tif item == null:\n\t\t\tbutton.hide()\n\n\t\t\tcontinue\n\n\t\tvar rarity: Rarity.enm = item.get_rarity()\n\t\tvar item_type: ItemType.enm = item.get_item_type()\n\t\tvar lock_enabled: bool = item.get_horadric_lock_is_enabled()\n\t\t\n\t\tvar rarity_match: bool = rarity_filter.has(rarity) || rarity_filter.is_empty()\n\t\tvar item_type_match: bool = item_type_filter.has(item_type) || item_type_filter.is_empty()\n\t\tvar lock_match: bool = lock_enabled || !lock_filter\n\t\t\n\t\tvar filter_match: bool = rarity_match && item_type_match && lock_match\n\n\t\tbutton.visible = filter_match\n\n\n# Enable/disable autofill buttons based on which items are\n# currently available for autofill\nfunc _update_autofill_buttons():\n\tvar recipe_buttons: Array[Node] = get_tree().get_nodes_in_group(\"recipe_buttons\")\n\tvar visible_items_in_item_stash: Array[Item] = _get_visible_item_list()\n\t\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\tvar items_in_horadric_stash: Array[Item] = horadric_stash.get_item_list()\n\n\tvar available_items: Array[Item] = []\n\tavailable_items.append_array(visible_items_in_item_stash)\n\tavailable_items.append_array(items_in_horadric_stash)\n\n\tfor node in recipe_buttons:\n\t\tvar recipe_button: RecipeButton = node as RecipeButton\n\t\tvar recipe: HoradricCube.Recipe = recipe_button.recipe\n\t\tvar autofill_is_possible: bool = HoradricCube.has_recipe_ingredients(recipe, available_items)\n\t\t\n\t\trecipe_button.disabled = !autofill_is_possible\n\n\nfunc _get_visible_item_list() -> Array[Item]:\n\tvar list: Array[Item] = []\n\t\n\tvar item_button_list: Array = _item_grid.get_children()\n\tfor item_button in item_button_list:\n\t\tif item_button.visible:\n\t\t\tvar item: Item = item_button.get_item()\n\t\t\t\n\t\t\tif item != null:\n\t\t\t\tlist.append(item)\n\n\treturn list\n\n\nfunc _set_horadric_cube_average_level():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\tvar items_in_horadric_stash: Array[Item] = horadric_stash.get_item_list()\n\t\n\tvar avg_level: int = HoradricCube._get_average_ingredient_level(items_in_horadric_stash)\n\t\n\tvar text: String = tr(\"ITEM_STASH_AVG_LEVEL\").format({AVG_LEVEL = avg_level})\n\n\t_horadric_cube_avg_item_level_label.text = text\n\t\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_local_player_selected_builder():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar builder: Builder = local_player.get_builder()\n\tvar builder_adds_extra_recipes: bool = builder.get_adds_extra_recipes()\n\t\n\tif builder_adds_extra_recipes:\n\t\t_backpacker_recipes.show()\n\n\nfunc _on_slot_button_pressed(button: EmptyUnitButton):\n\tvar index: int = button.get_index()\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\n\tEventBus.player_clicked_in_item_container.emit(item_stash, index)\n\n\nfunc _on_transmute_button_pressed():\n\tEventBus.player_requested_transmute.emit()\n\n\nfunc _on_item_button_pressed(item_button: ItemButton):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\tvar item_index: int = item_button.get_index()\n\tEventBus.player_clicked_in_item_container.emit(item_stash, item_index)\n\n\nfunc _on_item_button_right_clicked(item_button: ItemButton):\n\tvar item: Item = item_button.get_item()\n\tEventBus.player_right_clicked_item.emit(item)\n\n\nfunc _on_item_button_ctrl_right_clicked(item_button: ItemButton):\n\tvar item: Item = item_button.get_item()\n\titem.toggle_horadric_lock()\n\n\nfunc _on_recipe_button_pressed(recipe: HoradricCube.Recipe):\n\tvar rarity_filter: Array = _rarity_filter.get_filter()\n\tEventBus.player_requested_autofill.emit(recipe, rarity_filter)\n\n\nfunc _on_close_button_pressed():\n\thide()\n\n\nfunc _on_rarity_filter_filter_changed():\n\t_load_current_filter()\n\t_update_autofill_buttons()\n\n\nfunc _on_item_type_filter_container_filter_changed():\n\t_load_current_filter()\n\t_update_autofill_buttons()\n\n\n# NOTE: need to update recipe buttons when an item locked\n# state changes because that changes the item list for\n# autofill\nfunc _on_item_button_horadric_lock_changed():\n\t_update_autofill_buttons()\n\n\nfunc _on_return_button_pressed():\n\tEventBus.player_requested_return_from_horadric_cube.emit()\n\n\nfunc _on_item_stash_changed():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\tvar highest_index: int = item_stash.get_highest_index()\n\t\n#\tAdd new rows to give the player space to organize items.\n#\tThe amount of rows depends on the highest occupied\n#\tindex, not total item count because item stash can have\n#\tempty slots between items. Always add one extra empty\n#\trow to prevent the item stash from feeling confined.\n\tvar required_row_count: int = ceili((highest_index + 1) / float(COLUMN_COUNT)) + 1\n\trequired_row_count = max(required_row_count, MIN_ROW_COUNT)\n\tvar required_slot_count: int = required_row_count * COLUMN_COUNT\n\tvar current_slot_count: int = _item_grid.get_child_count()\n\tvar need_more_slots: bool = required_slot_count > current_slot_count\n\n\tif need_more_slots:\n\t\twhile _background_grid.get_child_count() < required_slot_count:\n\t\t\tvar slot_button: EmptyUnitButton = _make_slot_button()\n\t\t\tslot_button.modulate = Color.WHITE\n\t\t\t_background_grid.add_child(slot_button)\n\t\t\n\t\twhile _item_grid.get_child_count() < required_slot_count:\n\t\t\tvar item_button: ItemButton = _make_item_button(null)\n\t\t\t_item_grid.add_child(item_button)\n\t\n\tvar item_button_list: Array = _item_grid.get_children()\n\tfor item_button in item_button_list:\n\t\tvar index: int = item_button.get_index()\n\t\tvar new_item: Item = item_stash.get_item_at_index(index)\n\n\t\titem_button.set_item(new_item)\n\n\t_load_current_filter()\n\t_update_autofill_buttons()\n\n\nfunc _on_horadric_stash_items_changed():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar horadric_stash: ItemContainer = local_player.get_horadric_stash()\n\tvar item_list: Array[Item] = horadric_stash.get_item_list()\n\t\n\tvar can_transmute: bool = HoradricCube.can_transmute(local_player, item_list)\n\t_transmute_button.set_disabled(!can_transmute)\n\n#\tNOTE: need to update autofill buttons both after changes\n#\tin item stash and horadric stash. If an item is moved\n#\tfrom item stash to horadric stash, then it will\n#\ttemporarily be unavailable during the move process, so\n#\tupdating only after item stash change is not enough.\n\t_update_autofill_buttons()\n\t_set_horadric_cube_average_level()\n\n\n# NOTE: this callback is needed to implement \"move item from\n# horadric cube to item stash while filtering item stash\".\n# Normal movement doesn't work because filtered item stash\n# has no empty slots to click on and in filtered state the\n# item stash is contiguous anyway. Also, this callback is a\n# bit bad because it gets triggered on clicks between\n# buttons, so do it only for filtered case. Otherwise, it\n# would be possible for player to misclick and move item to\n# wrong place.\nfunc _on_item_grid_gui_input(event):\n\tvar left_click: bool = event.is_action_released(\"left_click\")\n\t\n\tif left_click:\n\t\tvar filter_is_none: bool = _get_filter_is_none()\n\n\t\tif filter_is_none:\n\t\t\treturn\n\n\t\tvar local_player: Player = PlayerManager.get_local_player()\n\t\tvar item_stash: ItemContainer = local_player.get_item_stash()\n\n\t\tEventBus.player_clicked_in_item_container.emit(item_stash, -1)\n\n\nfunc _on_sort_button_pressed():\n\tEventBus.player_requested_to_sort_item_stash.emit()\n\n\nfunc _on_lock_filter_button_toggled(_toggled_on: bool):\n\t_load_current_filter()\n\t_update_autofill_buttons()\n"
  },
  {
    "path": "src/ui/item_stash_menu/item_stash_menu.tscn",
    "content": "[gd_scene load_steps=21 format=3 uid=\"uid://ino0lr2m12uh\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/item_stash_menu/item_stash_menu.gd\" id=\"2_7jmcp\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dl22jvey8l5fo\" path=\"res://assets/hud/hud_atlas.png\" id=\"3_8ah5h\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://cwmhuo2ppjfx2\" path=\"res://resources/theme/common/rect_container_m.tres\" id=\"3_tvpws\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://c1ccsqvpyqd4i\" path=\"res://src/ui/buttons/recipe_button.tscn\" id=\"7_4dttm\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b1oind72lxrm4\" path=\"res://resources/icons/hud/recipe_rebrew.tres\" id=\"8_aeibv\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://dfqns87v0xu7x\" path=\"res://resources/icons/hud/recipe_distill.tres\" id=\"9_nqpec\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bk4dvb16ukwx8\" path=\"res://resources/icons/hud/recipe_reassemble.tres\" id=\"10_yki42\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bqsnuywmbb5c1\" path=\"res://resources/icons/mechanical/alchemy_kit_03.tres\" id=\"11_vmis2\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bvclahxp4mvge\" path=\"res://resources/icons/hud/recipe_perfect.tres\" id=\"11_vtu31\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://b30yt0bkbmhsj\" path=\"res://resources/icons/mechanical/alchemy_kit_01.tres\" id=\"12_b1vp8\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://beu73m131qhyk\" path=\"res://src/ui/unit_menu/item_container_panel.tscn\" id=\"12_f1ua4\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ib3y0a6h0v46\" path=\"res://src/ui/filter_buttons/item_type_filter.tscn\" id=\"13_1dykx\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bkmyw11w5jqjw\" path=\"res://resources/icons/magic/magic_stone.tres\" id=\"13_hyx2e\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"13_xnxpr\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://qcct52drete4\" path=\"res://src/ui/filter_buttons/rarity_filter.tscn\" id=\"14_bh43e\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"17_ba6s8\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_od67h\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_1vi8g\"]\natlas = ExtResource(\"17_ba6s8\")\nregion = Rect2(512, 128, 128, 128)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_qiyn0\"]\natlas = ExtResource(\"3_8ah5h\")\nregion = Rect2(10, 11, 110, 109)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wh5fy\"]\natlas = ExtResource(\"17_ba6s8\")\nregion = Rect2(896, 0, 128, 128)\n\n[node name=\"ItemStashMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_rarity_filter\", \"_item_type_filter_container\", \"_background_grid\", \"_item_grid\", \"_item_scroll_container\", \"_backpacker_recipes\", \"_horadric_item_container_panel\", \"_transmute_button\", \"_horadric_cube_avg_item_level_label\", \"_lock_filter_button\")]\ncustom_minimum_size = Vector2(630, 850)\noffset_right = 693.0\noffset_bottom = 842.0\nmouse_force_pass_scroll_events = false\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_od67h\")\nscript = ExtResource(\"2_7jmcp\")\n_rarity_filter = NodePath(\"MarginContainer/VBoxContainer2/RarityFilter\")\n_item_type_filter_container = NodePath(\"MarginContainer/VBoxContainer2/ItemTypeFilter\")\n_background_grid = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer/MarginContainer/BackgroundGrid\")\n_item_grid = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer/MarginContainer/ItemGrid\")\n_item_scroll_container = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer\")\n_backpacker_recipes = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes\")\n_horadric_item_container_panel = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/MarginContainer2/VBoxContainer/HoradricItemContainerPanel\")\n_transmute_button = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer2/VBoxContainer/TransmuteButton\")\n_horadric_cube_avg_item_level_label = NodePath(\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/MarginContainer2/VBoxContainer/HoradricAvgItemLevelLabel\")\n_lock_filter_button = NodePath(\"MarginContainer3/VBoxContainer/LockFilterButton\")\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\".\"]\nlayout_mode = 2\ncurrent_tab = 0\ntabs_visible = false\ntab_focus_mode = 0\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer\"]\nlayout_mode = 2\nmetadata/_tab_index = 0\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"TabContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\ntheme_override_constants/margin_top = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\ntheme_override_constants/separation = 20\n\n[node name=\"ItemsPanel\" type=\"PanelContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -10\n\n[node name=\"Label\" type=\"Label\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelSectionTitle\"\ntext = \"ITEMS_PANEL_ITEMS\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel\"]\nlayout_mode = 2\nsize_flags_vertical = 0\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 15\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\ntheme_override_constants/margin_bottom = -1\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer\"]\ncustom_minimum_size = Vector2(0, 420)\nlayout_mode = 2\nhorizontal_scroll_mode = 0\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 6\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"BackgroundGrid\" type=\"GridContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 4\ntheme_override_constants/v_separation = 4\ncolumns = 6\n\n[node name=\"ItemGrid\" type=\"GridContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer/MarginContainer\"]\nlayout_mode = 2\nmouse_filter = 0\ntheme_override_constants/h_separation = 4\ntheme_override_constants/v_separation = 4\ncolumns = 6\n\n[node name=\"HoradricPanel\" type=\"PanelContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(2.08165e-12, 280)\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_stretch_ratio = 0.5\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -10\n\n[node name=\"Label\" type=\"Label\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/MarginContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelSectionTitle\"\ntext = \"HORADRIC_CUBE\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel\"]\nlayout_mode = 2\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_stretch_ratio = 0.3\nalignment = 1\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_top = 15\ntheme_override_constants/margin_right = 0\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"HBoxContainer\" type=\"GridContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\ncolumns = 2\n\n[node name=\"AspectRatioContainer\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 2\nalignment_vertical = 2\n\n[node name=\"RebrewButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/AspectRatioContainer\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"8_aeibv\")\nrecipe = 1\n\n[node name=\"AspectRatioContainer2\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 0\nalignment_vertical = 2\n\n[node name=\"DistillButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/AspectRatioContainer2\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"9_nqpec\")\nrecipe = 2\n\n[node name=\"AspectRatioContainer3\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 2\nalignment_vertical = 0\n\n[node name=\"ReassembleButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/AspectRatioContainer3\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"10_yki42\")\nrecipe = 3\n\n[node name=\"AspectRatioContainer4\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 0\nalignment_vertical = 0\n\n[node name=\"PerfectButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/AspectRatioContainer4\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"11_vtu31\")\nrecipe = 4\n\n[node name=\"BackpackerRecipes\" type=\"GridContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer\"]\nvisible = false\nlayout_mode = 2\nsize_flags_vertical = 3\nsize_flags_stretch_ratio = 0.4\ncolumns = 3\n\n[node name=\"AspectRatioContainer1\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 0\nalignment_vertical = 0\n\n[node name=\"LiquefyButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes/AspectRatioContainer1\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"11_vmis2\")\nrecipe = 5\n\n[node name=\"AspectRatioContainer2\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 0\nalignment_vertical = 0\n\n[node name=\"PrecipitateButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes/AspectRatioContainer2\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"12_b1vp8\")\nrecipe = 6\n\n[node name=\"AspectRatioContainer3\" type=\"AspectRatioContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nalignment_horizontal = 0\nalignment_vertical = 0\n\n[node name=\"ImbueButton\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/BackpackerRecipes/AspectRatioContainer3\" instance=ExtResource(\"7_4dttm\")]\nlayout_mode = 2\nicon = ExtResource(\"13_hyx2e\")\nrecipe = 7\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_bottom = 15\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer2\"]\nlayout_mode = 2\n\n[node name=\"TransmuteButton\" type=\"Button\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer2/VBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"ITEM_STASH_TOOLTIP_TRANSMUTE\"\nfocus_mode = 0\ntext = \"ITEMS_PANEL_MERGE\"\n\n[node name=\"ReturnButton\" type=\"Button\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer2/VBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"ITEM_STASH_TOOLTIP_RETURN_ITEMS\"\nfocus_mode = 0\ntext = \"ITEMS_PANEL_RETURN\"\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_stretch_ratio = 0.7\ntheme_override_constants/margin_left = 30\ntheme_override_constants/margin_top = 30\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/MarginContainer2\"]\nlayout_mode = 2\n\n[node name=\"HoradricItemContainerPanel\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/MarginContainer2/VBoxContainer\" instance=ExtResource(\"12_f1ua4\")]\nlayout_mode = 2\nsize_flags_vertical = 3\n_button_tooltip_location = 0\nshow_slot_borders = false\n\n[node name=\"HoradricAvgItemLevelLabel\" type=\"Label\" parent=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/MarginContainer2/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 6\ntext = \"Average item level: 0\"\nvertical_alignment = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\nmouse_filter = 2\ntheme_override_constants/margin_left = -30\ntheme_override_constants/margin_top = 40\n\n[node name=\"VBoxContainer2\" type=\"VBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nmouse_filter = 2\ntheme_override_constants/separation = 40\n\n[node name=\"ItemTypeFilter\" parent=\"MarginContainer/VBoxContainer2\" instance=ExtResource(\"13_1dykx\")]\nlayout_mode = 2\n\n[node name=\"RarityFilter\" parent=\"MarginContainer/VBoxContainer2\" instance=ExtResource(\"14_bh43e\")]\nlayout_mode = 2\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 8\nmouse_filter = 2\ntheme_override_constants/margin_left = -30\ntheme_override_constants/margin_top = 0\ntheme_override_constants/margin_bottom = 30\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer3\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"MarginContainer3/VBoxContainer\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_left = -3\n\n[node name=\"SortButton\" type=\"Button\" parent=\"MarginContainer3/VBoxContainer/MarginContainer\"]\ncustom_minimum_size = Vector2(70, 70)\nlayout_mode = 2\nsize_flags_horizontal = 10\ntooltip_text = \"ITEM_STASH_TOOLTIP_SORT\"\nfocus_mode = 0\ntheme = ExtResource(\"13_xnxpr\")\ntheme_type_variation = &\"FilterButton\"\nicon = SubResource(\"AtlasTexture_1vi8g\")\nexpand_icon = true\n\n[node name=\"LockFilterButton\" type=\"Button\" parent=\"MarginContainer3/VBoxContainer\"]\ncustom_minimum_size = Vector2(64, 64)\nlayout_mode = 2\ntooltip_text = \"ITEM_STASH_TOOLTIP_LOCK_FILTER\"\nfocus_mode = 0\ntheme_type_variation = &\"FilterButton\"\ntoggle_mode = true\nicon = SubResource(\"AtlasTexture_qiyn0\")\nexpand_icon = true\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nicon = SubResource(\"AtlasTexture_wh5fy\")\nicon_alignment = 1\nexpand_icon = true\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -15\n\n[node name=\"TitleLabel\" type=\"Label\" parent=\"MarginContainer2\"]\ncustom_minimum_size = Vector2(200, 0)\nlayout_mode = 2\ntheme_override_font_sizes/font_size = 26\ntheme_override_styles/normal = ExtResource(\"3_tvpws\")\ntext = \"ITEMS_PANEL_ITEM_STASH\"\nhorizontal_alignment = 1\n\n[connection signal=\"gui_input\" from=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/ItemsPanel/MarginContainer2/VBoxContainer/MarginContainer/ScrollContainer/MarginContainer/ItemGrid\" to=\".\" method=\"_on_item_grid_gui_input\"]\n[connection signal=\"pressed\" from=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer2/VBoxContainer/TransmuteButton\" to=\".\" method=\"_on_transmute_button_pressed\"]\n[connection signal=\"pressed\" from=\"TabContainer/VBoxContainer/MarginContainer/VBoxContainer/HoradricPanel/VBoxContainer/HBoxContainer/VBoxContainer/MarginContainer2/VBoxContainer/ReturnButton\" to=\".\" method=\"_on_return_button_pressed\"]\n[connection signal=\"filter_changed\" from=\"MarginContainer/VBoxContainer2/ItemTypeFilter\" to=\".\" method=\"_on_item_type_filter_container_filter_changed\"]\n[connection signal=\"filter_changed\" from=\"MarginContainer/VBoxContainer2/RarityFilter\" to=\".\" method=\"_on_rarity_filter_filter_changed\"]\n[connection signal=\"pressed\" from=\"MarginContainer3/VBoxContainer/MarginContainer/SortButton\" to=\".\" method=\"_on_sort_button_pressed\"]\n[connection signal=\"toggled\" from=\"MarginContainer3/VBoxContainer/LockFilterButton\" to=\".\" method=\"_on_lock_filter_button_toggled\"]\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/player_resource_display/player_resource_display.gd",
    "content": "class_name PlayerResourceDisplay extends PanelContainer\n\n\n# Displays the amounts of player resources.\n\n\n@export var _lives_status: ResourceStatusPanel\n@export var _tomes_status: ResourceStatusPanel\n@export var _gold_status: ResourceStatusPanel\n@export var _food_status: ResourceStatusPanel\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _process(_delta: float):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\n\tif local_player == null:\n\t\treturn\n\t\n\tvar local_team: Team = local_player.get_team()\n\tvar portal_lives: String = local_team.get_lives_string()\n\t_lives_status.set_label_text(portal_lives)\n\n\tvar gold: int = floori(local_player.get_gold())\n\tvar gold_string: String = TowerDetails.int_format(gold)\n\t_gold_status.set_label_text(gold_string)\n\n\tvar tomes: int = local_player.get_tomes()\n\tvar tomes_string: String = str(tomes)\n\t_tomes_status.set_label_text(tomes_string)\n\n\tvar food: int = local_player.get_food()\n\tvar food_cap: int = local_player.get_food_cap()\n\tvar food_string: String = \"%d/%d\" % [food, food_cap]\n\t_food_status.set_label_text(food_string)\n"
  },
  {
    "path": "src/ui/player_resource_display/player_resource_display.tscn",
    "content": "[gd_scene load_steps=10 format=3 uid=\"uid://cc70ktmpmbjts\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_mggw6\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/player_resource_display/player_resource_display.gd\" id=\"2_m57on\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://dt873umx4sexx\" path=\"res://resources/theme/player_resource_display/rect_container_top_menu.tres\" id=\"3_i5jws\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://1a6qmxkrspc8\" path=\"res://src/ui/player_resource_display/resource_status_panel.tscn\" id=\"4_ajusi\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bxqh2nddd7eni\" path=\"res://resources/icons/hud/gold.tres\" id=\"5_uvsoy\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://d1d4h6m0klgw1\" path=\"res://resources/icons/hud/knowledge_tome.tres\" id=\"6_6qkfi\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://baig85lpi88u\" path=\"res://resources/icons/hud/tower_food.tres\" id=\"7_rye6p\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://e21bpw6p1kok\" path=\"res://resources/icons/food/poultry.tres\" id=\"8_7hxjl\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_wrkv0\"]\n\n[node name=\"PlayerResourceDisplay\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_lives_status\", \"_tomes_status\", \"_gold_status\", \"_food_status\")]\nanchors_preset = 10\nanchor_right = 1.0\noffset_bottom = 73.0\ngrow_horizontal = 2\nsize_flags_horizontal = 3\nmouse_force_pass_scroll_events = false\ntheme = ExtResource(\"1_mggw6\")\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_wrkv0\")\nscript = ExtResource(\"2_m57on\")\n_lives_status = NodePath(\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu/LivesStatus\")\n_tomes_status = NodePath(\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu/TomesStatus\")\n_gold_status = NodePath(\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu/GoldStatus\")\n_food_status = NodePath(\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu/FoodStatus\")\nmetadata/_edit_vertical_guides_ = [1280.0]\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_vertical = 0\ntheme_override_constants/separation = -2\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"CenterMenu\" type=\"PanelContainer\" parent=\"HBoxContainer/MarginContainer\"]\nlayout_mode = 2\ntheme_override_styles/panel = ExtResource(\"3_i5jws\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/MarginContainer/CenterMenu\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\n\n[node name=\"CenterMenu\" type=\"HBoxContainer\" parent=\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer\"]\ncustom_minimum_size = Vector2(180, 0)\nlayout_mode = 2\nsize_flags_vertical = 4\ntheme_override_constants/separation = 6\nalignment = 1\n\n[node name=\"LivesStatus\" parent=\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu\" instance=ExtResource(\"4_ajusi\")]\nlayout_mode = 2\ntooltip_text = \"PLAYER_RESOURCE_TOOLTIP_LIVES\"\nicon_texture = ExtResource(\"7_rye6p\")\ndefault_label_text = \"0\"\n\n[node name=\"GoldStatus\" parent=\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu\" instance=ExtResource(\"4_ajusi\")]\ncustom_minimum_size = Vector2(160, 38)\nlayout_mode = 2\ntooltip_text = \"PLAYER_RESOURCE_TOOLTIP_GOLD\"\nicon_texture = ExtResource(\"5_uvsoy\")\ndefault_label_text = \"0\"\n\n[node name=\"TomesStatus\" parent=\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu\" instance=ExtResource(\"4_ajusi\")]\nlayout_mode = 2\ntooltip_text = \"PLAYER_RESOURCE_TOOLTIP_KNOWLEDGE_TOMES\"\nicon_texture = ExtResource(\"6_6qkfi\")\ndefault_label_text = \"0\"\n\n[node name=\"FoodStatus\" parent=\"HBoxContainer/MarginContainer/CenterMenu/MarginContainer/CenterMenu\" instance=ExtResource(\"4_ajusi\")]\nlayout_mode = 2\ntooltip_text = \"PLAYER_RESOURCE_TOOLTIP_FOOD\"\nicon_texture = ExtResource(\"8_7hxjl\")\ndefault_label_text = \"0/55\"\n"
  },
  {
    "path": "src/ui/player_resource_display/resource_status_panel.gd",
    "content": "@tool\nclass_name ResourceStatusPanel\nextends Panel\n\n\n# Displays a player resource as icon+number. Used in the resource panel to show gold, tomes, food.\n\n\n@export var icon_texture: Texture2D\n@export var default_label_text: String\n@export var _label: Label\n@export var _icon: TextureRect\n\n\nfunc _ready():\n\t_icon.texture = icon_texture\n\t_label.text = default_label_text\n\n\nfunc set_label_text(text: String):\n\t_label.text = text\n"
  },
  {
    "path": "src/ui/player_resource_display/resource_status_panel.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://1a6qmxkrspc8\"]\n\n[ext_resource type=\"StyleBox\" uid=\"uid://8o35dfhhk4km\" path=\"res://resources/theme/player_resource_display/resource_status_panel.tres\" id=\"1_ri1eg\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/player_resource_display/resource_status_panel.gd\" id=\"2_y71mw\"]\n\n[node name=\"ResourceStatusPanel\" type=\"Panel\" node_paths=PackedStringArray(\"_label\", \"_icon\")]\ncustom_minimum_size = Vector2(130, 38)\noffset_right = 120.0\noffset_bottom = 28.0\nsize_flags_horizontal = 3\ntheme_type_variation = &\"ResourceTab\"\ntheme_override_styles/panel = ExtResource(\"1_ri1eg\")\nscript = ExtResource(\"2_y71mw\")\n_label = NodePath(\"HBoxContainer/MarginContainer/Label\")\n_icon = NodePath(\"HBoxContainer/Icon\")\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"Icon\" type=\"TextureRect\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nexpand_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 8\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_right = 10\n\n[node name=\"Label\" type=\"Label\" parent=\"HBoxContainer/MarginContainer\"]\nlayout_mode = 2\ntheme_override_font_sizes/font_size = 28\nhorizontal_alignment = 2\nvertical_alignment = 2\n"
  },
  {
    "path": "src/ui/title_screen/configure_singleplayer_menu.gd",
    "content": "class_name ConfigureSinglePlayerMenu extends PanelContainer\n\n\nsignal cancel_pressed()\nsignal start_button_pressed()\n\n\n@export var _match_config_panel: MatchConfigPanel\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar cached_difficulty_string: String = Settings.get_setting(Settings.CACHED_GAME_DIFFICULTY)\n\tvar cached_difficulty: Difficulty.enm = Difficulty.from_string(cached_difficulty_string)\n\t\n\tvar cached_game_mode_string: String = Settings.get_setting(Settings.CACHED_GAME_MODE)\n\tvar cached_game_mode: GameMode.enm = GameMode.from_string(cached_game_mode_string)\n\t\n\tvar cached_game_length: int = Settings.get_setting(Settings.CACHED_GAME_LENGTH)\n\n\t_match_config_panel.set_difficulty(cached_difficulty)\n\t_match_config_panel.set_game_mode(cached_game_mode)\n\t_match_config_panel.set_game_length(cached_game_length)\n\t\n\t_match_config_panel.hide_team_mode_selector()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_difficulty() -> Difficulty.enm:\n\treturn _match_config_panel.get_difficulty()\n\n\nfunc get_game_length() -> int:\n\treturn _match_config_panel.get_game_length()\n\n\nfunc get_game_mode() -> GameMode.enm:\n\treturn _match_config_panel.get_game_mode()\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_start_button_pressed():\n\tstart_button_pressed.emit()\n\n\nfunc _on_cancel_button_pressed():\n\tcancel_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/configure_singleplayer_menu.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://eies0lnegrf6\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_70pqg\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/configure_singleplayer_menu.gd\" id=\"1_dgq16\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dc67simk1xfp4\" path=\"res://src/ui/title_screen/match_config_panel.tscn\" id=\"2_7m6il\"]\n\n[node name=\"ConfigureSingleplayerMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_match_config_panel\")]\ntheme = ExtResource(\"1_70pqg\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"1_dgq16\")\n_match_config_panel = NodePath(\"VBoxContainer/MatchConfigPanel\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"SINGLE_CHOOSE_GAME_SETTINGS\"\n\n[node name=\"MatchConfigPanel\" parent=\"VBoxContainer\" instance=ExtResource(\"2_7m6il\")]\nlayout_mode = 2\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nalignment = 2\n\n[node name=\"CancelButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"CANCEL_BUTTON\"\n\n[node name=\"StartButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"START_BUTTON\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CancelButton\" to=\".\" method=\"_on_cancel_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/StartButton\" to=\".\" method=\"_on_start_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/connecting_to_server_indicator.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://chegdechhho3d\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_v0wh7\"]\n\n[node name=\"ConnectingToServerIndicator\" type=\"Control\"]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -156.5\noffset_top = -54.0\noffset_right = 156.5\noffset_bottom = 54.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme = ExtResource(\"1_v0wh7\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"CONNECTING_TO_SERVER\"\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_generic_tab.gd",
    "content": "class_name EncyclopediaGenericTab extends VBoxContainer\n\n\nsignal filter_changed()\nsignal close_pressed()\n\n\n@export var _info_label: RichTextLabel\n@export var _button_grid: GridContainer\n@export var _selected_tower_button: TowerButton\n@export var _selected_item_button: ItemButton\n@export var _selected_name_label: Label\n@export var _search_text_edit: LineEdit\n\n@export var _item_type_filter_container: HBoxContainer\n@export var _regular_check: CheckBox\n@export var _oil_check: CheckBox\n@export var _consumable_check: CheckBox\n\n@export var _element_filter_container: HBoxContainer\n@export var _ice_check: CheckBox\n@export var _nature_check: CheckBox\n@export var _fire_check: CheckBox\n@export var _astral_check: CheckBox\n@export var _darkness_check: CheckBox\n@export var _iron_check: CheckBox\n@export var _storm_check: CheckBox\n\n@export var _ice_label: Label\n@export var _nature_label: Label\n@export var _fire_label: Label\n@export var _astral_label: Label\n@export var _darkness_label: Label\n@export var _iron_label: Label\n@export var _storm_label: Label\n\n@export var _common_check: CheckBox\n@export var _uncommon_check: CheckBox\n@export var _rare_check: CheckBox\n@export var _unique_check: CheckBox\n\n@export var _common_label: Label\n@export var _uncommon_label: Label\n@export var _rare_label: Label\n@export var _unique_label: Label\n\n@onready var _item_type_check_map: Dictionary = {\n\tItemType.enm.REGULAR: _regular_check,\n\tItemType.enm.OIL: _oil_check,\n\tItemType.enm.CONSUMABLE: _consumable_check,\n}\n\n@onready var _element_check_map: Dictionary = {\n\tElement.enm.ICE: _ice_check,\n\tElement.enm.NATURE: _nature_check,\n\tElement.enm.FIRE: _fire_check,\n\tElement.enm.ASTRAL: _astral_check,\n\tElement.enm.DARKNESS: _darkness_check,\n\tElement.enm.IRON: _iron_check,\n\tElement.enm.STORM: _storm_check,\n}\n\n@onready var _element_label_map: Dictionary = {\n\tElement.enm.ICE: _ice_label,\n\tElement.enm.NATURE: _nature_label,\n\tElement.enm.FIRE: _fire_label,\n\tElement.enm.ASTRAL: _astral_label,\n\tElement.enm.DARKNESS: _darkness_label,\n\tElement.enm.IRON: _iron_label,\n\tElement.enm.STORM: _storm_label,\n}\n\n@onready var _rarity_check_map: Dictionary = {\n\tRarity.enm.COMMON: _common_check,\n\tRarity.enm.UNCOMMON: _uncommon_check,\n\tRarity.enm.RARE: _rare_check,\n\tRarity.enm.UNIQUE: _unique_check,\n}\n\n@onready var _rarity_label_map: Dictionary = {\n\tRarity.enm.COMMON: _common_label,\n\tRarity.enm.UNCOMMON: _uncommon_label,\n\tRarity.enm.RARE: _rare_label,\n\tRarity.enm.UNIQUE: _unique_label,\n}\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready() -> void:\n\t_selected_tower_button.hide()\n\t_selected_tower_button.set_tooltip_is_enabled(false)\n\t_selected_tower_button.set_tier_visible(true)\n\t_selected_tower_button.hide_freshness_indicator()\n\t\n\t_info_label.clear()\n\t_selected_name_label.text = \"\"\n\t\n\tfor check in _item_type_check_map.values():\n\t\tcheck.toggled.connect(_on_item_type_check_toggled)\n\t\n\tfor check in _element_check_map.values():\n\t\tcheck.toggled.connect(_on_element_check_toggled)\n\t\n\tfor element in Element.get_list():\n\t\tvar element_color: Color = Element.get_color(element)\n\t\tvar element_label: Label = _element_label_map[element]\n\t\telement_label.set(\"theme_override_colors/font_color\", element_color)\n\n\tfor check in _rarity_check_map.values():\n\t\tcheck.toggled.connect(_on_rarity_check_toggled)\n\t\n\tfor rarity in Rarity.get_list():\n\t\tvar rarity_color: Color = Rarity.get_color(rarity)\n\t\tvar rarity_label: Label = _rarity_label_map[rarity]\n\t\trarity_label.set(\"theme_override_colors/font_color\", rarity_color)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_item_type_filters_visible(value: bool):\n\t_item_type_filter_container.visible = value\n\n\nfunc set_element_filters_visible(value: bool):\n\t_element_filter_container.visible = value\n\n\nfunc add_button_to_grid(button: Button):\n\t_button_grid.add_child(button)\n\n\nfunc set_selected_tower_id(tower_id: int):\n\t_selected_tower_button.set_tower_id(tower_id)\n\t_selected_tower_button.show()\n\t_selected_item_button.hide()\n\n\nfunc set_selected_item_id(item_id: int):\n\t_selected_item_button.setup_button_for_encyclopedia(item_id)\n\t_selected_item_button.show()\n\t_selected_tower_button.hide()\n\n\nfunc set_selected_name(selected_name: String):\n\t_selected_name_label.text = selected_name\n\n\nfunc set_info_text(text: String):\n\t_info_label.clear()\n\t_info_label.append_text(text)\n\n\nfunc get_item_type_filter() -> Array[ItemType.enm]:\n\tvar item_type_filter_list: Array[ItemType.enm] = []\n\t\n\tfor item_type in _item_type_check_map.keys():\n\t\tvar check: CheckBox = _item_type_check_map[item_type]\n\t\tvar item_type_is_included: bool = check.button_pressed\n\t\t\n\t\tif item_type_is_included:\n\t\t\titem_type_filter_list.append(item_type)\n\t\n\tif item_type_filter_list.is_empty():\n\t\treturn ItemType.get_list()\n\t\n\treturn item_type_filter_list\n\n\nfunc get_element_filter() -> Array[Element.enm]:\n\tvar element_filter_list: Array[Element.enm] = []\n\t\n\tfor element in _element_check_map.keys():\n\t\tvar check: CheckBox = _element_check_map[element]\n\t\tvar element_is_included: bool = check.button_pressed\n\t\t\n\t\tif element_is_included:\n\t\t\telement_filter_list.append(element)\n\t\n\tif element_filter_list.is_empty():\n\t\treturn Element.get_list()\n\t\n\treturn element_filter_list\n\n\nfunc get_rarity_filter() -> Array[Rarity.enm]:\n\tvar rarity_filter_list: Array[Rarity.enm] = []\n\t\n\tfor rarity in _rarity_check_map.keys():\n\t\tvar check: CheckBox = _rarity_check_map[rarity]\n\t\tvar rarity_is_included: bool = check.button_pressed\n\t\t\n\t\tif rarity_is_included:\n\t\t\trarity_filter_list.append(rarity)\n\t\n\tif rarity_filter_list.is_empty():\n\t\treturn Rarity.get_list()\n\t\n\treturn rarity_filter_list\n\n\nfunc get_search_text() -> String:\n\treturn _search_text_edit.text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_close_button_pressed() -> void:\n\tclose_pressed.emit()\n\n\nfunc _on_search_box_text_changed(_new_text: String) -> void:\n\tfilter_changed.emit()\n\n\nfunc _on_item_type_check_toggled(_toggled_on: bool) -> void:\n\tfilter_changed.emit()\n\n\nfunc _on_element_check_toggled(_toggled_on: bool):\n\tfilter_changed.emit()\n\n\nfunc _on_rarity_check_toggled(_toggled_on: bool):\n\tfilter_changed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_generic_tab.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://cqj4g0gfbrtev\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://ni34yd5liwbj\" path=\"res://src/ui/buttons/tower_button.tscn\" id=\"1_j8krt\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/encyclopedia_generic_tab.gd\" id=\"1_wu1sd\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cj8l153f630bb\" path=\"res://src/ui/buttons/item_button.tscn\" id=\"3_16rs4\"]\n\n[node name=\"EncyclopediaGenericTab\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_info_label\", \"_button_grid\", \"_selected_tower_button\", \"_selected_item_button\", \"_selected_name_label\", \"_search_text_edit\", \"_item_type_filter_container\", \"_regular_check\", \"_oil_check\", \"_consumable_check\", \"_element_filter_container\", \"_ice_check\", \"_nature_check\", \"_fire_check\", \"_astral_check\", \"_darkness_check\", \"_iron_check\", \"_storm_check\", \"_ice_label\", \"_nature_label\", \"_fire_label\", \"_astral_label\", \"_darkness_label\", \"_iron_label\", \"_storm_label\", \"_common_check\", \"_uncommon_check\", \"_rare_check\", \"_unique_check\", \"_common_label\", \"_uncommon_label\", \"_rare_label\", \"_unique_label\")]\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\ntheme_override_constants/separation = 10\nscript = ExtResource(\"1_wu1sd\")\n_info_label = NodePath(\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/InfoLabel\")\n_button_grid = NodePath(\"HBoxContainer/PanelContainer/MarginContainer/ScrollContainer/GridContainer\")\n_selected_tower_button = NodePath(\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HBoxContainer/SelectedTowerButton\")\n_selected_item_button = NodePath(\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HBoxContainer/SelectedItemButton\")\n_selected_name_label = NodePath(\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HBoxContainer/SelectedNameLabel\")\n_search_text_edit = NodePath(\"HBoxContainer2/SearchBox\")\n_item_type_filter_container = NodePath(\"ItemTypeFilterContainer\")\n_regular_check = NodePath(\"ItemTypeFilterContainer/RegularCheck\")\n_oil_check = NodePath(\"ItemTypeFilterContainer/OilCheck\")\n_consumable_check = NodePath(\"ItemTypeFilterContainer/ConsumableCheck\")\n_element_filter_container = NodePath(\"ElementFilterContainer\")\n_ice_check = NodePath(\"ElementFilterContainer/IceCheck\")\n_nature_check = NodePath(\"ElementFilterContainer/NatureCheck\")\n_fire_check = NodePath(\"ElementFilterContainer/FireCheck\")\n_astral_check = NodePath(\"ElementFilterContainer/AstralCheck\")\n_darkness_check = NodePath(\"ElementFilterContainer/DarknessCheck\")\n_iron_check = NodePath(\"ElementFilterContainer/IronCheck\")\n_storm_check = NodePath(\"ElementFilterContainer/StormCheck\")\n_ice_label = NodePath(\"ElementFilterContainer/IceLabel\")\n_nature_label = NodePath(\"ElementFilterContainer/NatureLabel\")\n_fire_label = NodePath(\"ElementFilterContainer/FireLabel\")\n_astral_label = NodePath(\"ElementFilterContainer/AstralLabel\")\n_darkness_label = NodePath(\"ElementFilterContainer/DarknessLabel\")\n_iron_label = NodePath(\"ElementFilterContainer/IronLabel\")\n_storm_label = NodePath(\"ElementFilterContainer/StormLabel\")\n_common_check = NodePath(\"RarityFilterContainer/CommonCheck\")\n_uncommon_check = NodePath(\"RarityFilterContainer/UncommonCheck\")\n_rare_check = NodePath(\"RarityFilterContainer/RareCheck\")\n_unique_check = NodePath(\"RarityFilterContainer/UniqueCheck\")\n_common_label = NodePath(\"RarityFilterContainer/CommonLabel\")\n_uncommon_label = NodePath(\"RarityFilterContainer/UncommonLabel\")\n_rare_label = NodePath(\"RarityFilterContainer/RareLabel\")\n_unique_label = NodePath(\"RarityFilterContainer/UniqueLabel\")\n\n[node name=\"HBoxContainer2\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 15\n\n[node name=\"Label\" type=\"Label\" parent=\"HBoxContainer2\"]\nlayout_mode = 2\ntext = \"Search:\"\n\n[node name=\"SearchBox\" type=\"LineEdit\" parent=\"HBoxContainer2\"]\ncustom_minimum_size = Vector2(400, 0)\nlayout_mode = 2\nfocus_mode = 1\n\n[node name=\"ItemTypeFilterContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"RegularCheck\" type=\"CheckBox\" parent=\"ItemTypeFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"Label\" type=\"Label\" parent=\"ItemTypeFilterContainer\"]\nlayout_mode = 2\ntext = \"Regular\"\n\n[node name=\"OilCheck\" type=\"CheckBox\" parent=\"ItemTypeFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"Label2\" type=\"Label\" parent=\"ItemTypeFilterContainer\"]\nlayout_mode = 2\ntext = \"Oils\"\n\n[node name=\"ConsumableCheck\" type=\"CheckBox\" parent=\"ItemTypeFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"Label3\" type=\"Label\" parent=\"ItemTypeFilterContainer\"]\nlayout_mode = 2\ntext = \"Consumables\"\n\n[node name=\"RarityFilterContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"CommonCheck\" type=\"CheckBox\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"CommonLabel\" type=\"Label\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\ntext = \"RARITY_COMMON\"\n\n[node name=\"UncommonCheck\" type=\"CheckBox\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"UncommonLabel\" type=\"Label\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\ntext = \"RARITY_UNCOMMON\"\n\n[node name=\"RareCheck\" type=\"CheckBox\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"RareLabel\" type=\"Label\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\ntext = \"RARITY_RARE\"\n\n[node name=\"UniqueCheck\" type=\"CheckBox\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"UniqueLabel\" type=\"Label\" parent=\"RarityFilterContainer\"]\nlayout_mode = 2\ntext = \"RARITY_UNIQUE\"\n\n[node name=\"ElementFilterContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"IceCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"IceLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_ICE\"\n\n[node name=\"NatureCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"NatureLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_NATURE\"\n\n[node name=\"FireCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"FireLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_FIRE\"\n\n[node name=\"AstralCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"AstralLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_ASTRAL\"\n\n[node name=\"DarknessCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"DarknessLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_DARKNESS\"\n\n[node name=\"IronCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"IronLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_IRON\"\n\n[node name=\"StormCheck\" type=\"CheckBox\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\nfocus_mode = 0\n\n[node name=\"StormLabel\" type=\"Label\" parent=\"ElementFilterContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_STORM\"\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 20\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 20\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"HBoxContainer/PanelContainer/MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"HBoxContainer/PanelContainer/MarginContainer/ScrollContainer\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 10\ntheme_override_constants/v_separation = 10\ncolumns = 5\n\n[node name=\"PanelContainer2\" type=\"PanelContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/PanelContainer2\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"HBoxContainer/PanelContainer2/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 15\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"SelectedTowerButton\" parent=\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HBoxContainer\" instance=ExtResource(\"1_j8krt\")]\nlayout_mode = 2\nsize_flags_horizontal = 0\n\n[node name=\"SelectedItemButton\" parent=\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HBoxContainer\" instance=ExtResource(\"3_16rs4\")]\ncustom_minimum_size = Vector2(120, 120)\nlayout_mode = 2\n\n[node name=\"SelectedNameLabel\" type=\"Label\" parent=\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Selected name placeholder\"\n\n[node name=\"InfoLabel\" type=\"RichTextLabel\" parent=\"HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 100)\nlayout_mode = 2\nsize_flags_vertical = 3\ntext = \"Placeholder description\"\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nfocus_mode = 0\ntext = \"CLOSE_BUTTON\"\n\n[connection signal=\"text_changed\" from=\"HBoxContainer2/SearchBox\" to=\".\" method=\"_on_search_box_text_changed\"]\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_items.gd",
    "content": "extends VBoxContainer\n\n\nsignal close_pressed()\n\n\nvar _button_list: Array[ItemButton] = []\nvar _button_to_searchable_name_map: Dictionary = {}\nvar _button_to_item_type_map: Dictionary = {}\nvar _button_to_rarity_map: Dictionary = {}\n\n@export var _generic_tab: EncyclopediaGenericTab\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready() -> void:\n\t_generic_tab.set_element_filters_visible(false)\n\t\n\tvar item_id_list: Array = ItemProperties.get_item_id_list()\n\t\n\titem_id_list.sort_custom(\n\t\tfunc (a: int, b: int) -> bool:\n\t\t\tvar item_type_a: ItemType.enm = ItemProperties.get_type(a)\n\t\t\tvar item_type_b: ItemType.enm = ItemProperties.get_type(b)\n\t\t\tvar rarity_a: Rarity.enm = ItemProperties.get_rarity(a)\n\t\t\tvar rarity_b: Rarity.enm = ItemProperties.get_rarity(b)\n\t\t\tvar required_wave_a: int = ItemProperties.get_required_wave_level(a)\n\t\t\tvar required_wave_b: int = ItemProperties.get_required_wave_level(b)\n\t\t\t\n\t\t\tif item_type_a != item_type_b:\n\t\t\t\treturn item_type_a < item_type_b\n\t\t\telse:\n\t\t\t\tif item_type_a == ItemType.enm.REGULAR:\n\t\t\t\t\tif rarity_a != rarity_b:\n\t\t\t\t\t\treturn rarity_a < rarity_b\n\t\t\t\t\telse:\n\t\t\t\t\t\treturn required_wave_a < required_wave_b\n\t\t\t\telse:\n\t\t\t\t\treturn a < b\n\t\t\t)\n\t\n\tfor item_id in item_id_list:\n\t\tvar button: ItemButton = ItemButton.make()\n\t\t_generic_tab.add_button_to_grid(button)\n\t\tbutton.set_horadric_lock_visible(false)\n\t\tbutton.setup_button_for_encyclopedia(item_id)\n\t\t\n\t\t_button_list.append(button)\n\t\t\n\t\tbutton.pressed.connect(_on_button_pressed.bind(item_id))\n\t\t\n\t\tvar item_name: String = ItemProperties.get_display_name(item_id)\n\t\tbutton.tooltip_text = item_name\n\n\t\tvar searchable_name: String = EncyclopediaTowers.make_searchable_string(item_name)\n\t\tvar item_type: ItemType.enm = ItemProperties.get_type(item_id)\n\t\tvar rarity: Rarity.enm = ItemProperties.get_rarity(item_id)\n\t\t_button_to_searchable_name_map[button] = searchable_name\n\t\t_button_to_item_type_map[button] = item_type\n\t\t_button_to_rarity_map[button] = rarity\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_text_for_item(item_id: int) -> String:\n\tvar text: String = \"\"\n\n\tvar description: String = ItemProperties.get_description(item_id)\n\tvar level: int = ItemProperties.get_required_wave_level(item_id)\n\tvar author: String = ItemProperties.get_author(item_id)\n\n\tvar specials_modifier: Modifier = ItemProperties.get_specials_modifier(item_id)\n\tvar specials_text: String = specials_modifier.get_tooltip_text()\n\tspecials_text = RichTexts.add_color_to_numbers(specials_text)\n\n\ttext += \" \\n\"\n\n\tif !description.is_empty():\n\t\ttext += \"[color=LIGHT_BLUE]%s[/color]\\n\" % description \\\n\t\t+ \" \\n\"\n\t\n\ttext += \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"ITEM_TOOLTIP_LEVEL\"), level] \\\n\t+ \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"TOWER_TOOLTIP_AUTHOR\"), author] \\\n\t+ \" \\n\"\n\n\tif !specials_text.is_empty():\n\t\ttext += \"[color=YELLOW]%s[/color]\\n\" % tr(\"ITEM_TOOLTIP_EFFECTS\") \\\n\t\t+ specials_text \\\n\t\t+ \" \\n\"\n\n\tvar ability_id_list: Array = ItemProperties.get_ability_id_list(item_id)\n\tfor ability_id in ability_id_list:\n\t\tvar ability_text: String = RichTexts.get_ability_text_long(ability_id)\n\n\t\ttext += ability_text\n\t\ttext += \" \\n\"\n\n\tvar aura_id_list: Array = ItemProperties.get_aura_id_list(item_id)\n\tfor aura_id in aura_id_list:\n\t\tvar aura_text: String = RichTexts.get_aura_text_long(aura_id)\n\n\t\ttext += aura_text\n\t\ttext += \" \\n\"\n\n\tvar autocast_id_list: Array = ItemProperties.get_autocast_id_list(item_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast_text: String = RichTexts.get_autocast_text_long(autocast_id)\n\n\t\ttext += autocast_text\n\t\ttext += \" \\n\"\n\n\treturn text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_encyclopedia_generic_tab_close_pressed() -> void:\n\tclose_pressed.emit()\n\n\nfunc _on_button_pressed(item_id: int):\n\t_generic_tab.set_selected_item_id(item_id)\n\t\n\tvar item_name: String = ItemProperties.get_display_name(item_id)\n\t_generic_tab.set_selected_name(item_name)\n\t\n\tvar text: String = _get_text_for_item(item_id)\n\t_generic_tab.set_info_text(text)\n\n\nfunc _on_encyclopedia_generic_tab_filter_changed() -> void:\n\tvar empty_element_map: Dictionary = {}\n\tEncyclopediaTowers.update_filtering(_button_list, _generic_tab, _button_to_searchable_name_map, _button_to_item_type_map, _button_to_rarity_map, empty_element_map)\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_items.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dtvkci6f4ocrm\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/encyclopedia_items.gd\" id=\"1_81wix\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cqj4g0gfbrtev\" path=\"res://src/ui/title_screen/encyclopedia_generic_tab.tscn\" id=\"1_sa7xi\"]\n\n[node name=\"EncyclopediaItems\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_generic_tab\")]\nscript = ExtResource(\"1_81wix\")\n_generic_tab = NodePath(\"EncyclopediaGenericTab\")\n\n[node name=\"EncyclopediaGenericTab\" parent=\".\" instance=ExtResource(\"1_sa7xi\")]\nlayout_mode = 2\n\n[connection signal=\"close_pressed\" from=\"EncyclopediaGenericTab\" to=\".\" method=\"_on_encyclopedia_generic_tab_close_pressed\"]\n[connection signal=\"filter_changed\" from=\"EncyclopediaGenericTab\" to=\".\" method=\"_on_encyclopedia_generic_tab_filter_changed\"]\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_menu.gd",
    "content": "class_name EncyclopediaMenu extends TabContainer\n\n\nsignal close_pressed()\n\n\nfunc _on_towers_close_pressed() -> void:\n\tclose_pressed.emit()\n\n\nfunc _on_encyclopedia_tab_items_close_pressed() -> void:\n\tclose_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_menu.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://dm74dudt8aesd\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/encyclopedia_menu.gd\" id=\"1_gh8nt\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bchd7sh3vf6tx\" path=\"res://src/ui/title_screen/encyclopedia_towers.tscn\" id=\"2_mgh3l\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dtvkci6f4ocrm\" path=\"res://src/ui/title_screen/encyclopedia_items.tscn\" id=\"3_3d2r8\"]\n\n[node name=\"EncyclopediaMenu\" type=\"TabContainer\"]\ncustom_minimum_size = Vector2(1460, 1200)\ncurrent_tab = 0\nscript = ExtResource(\"1_gh8nt\")\n\n[node name=\"ENCYCLOPEDIA_TAB_TOWERS\" parent=\".\" instance=ExtResource(\"2_mgh3l\")]\nlayout_mode = 2\n\n[node name=\"ENCYCLOPEDIA_TAB_ITEMS\" parent=\".\" instance=ExtResource(\"3_3d2r8\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 1\n\n[connection signal=\"close_pressed\" from=\"ENCYCLOPEDIA_TAB_TOWERS\" to=\".\" method=\"_on_towers_close_pressed\"]\n[connection signal=\"close_pressed\" from=\"ENCYCLOPEDIA_TAB_ITEMS\" to=\".\" method=\"_on_encyclopedia_tab_items_close_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_towers.gd",
    "content": "class_name EncyclopediaTowers extends VBoxContainer\n\n\n# This is the towers tab of the Encyclopedia Menu. Shows\n# tower buttons on left side and info about selected tower\n# on right side.\n\nsignal close_pressed()\n\n@export var _generic_tab: EncyclopediaGenericTab\n\nvar _button_list: Array[TowerButton] = []\nvar _button_to_searchable_name_map: Dictionary = {}\nvar _button_to_element_map: Dictionary = {}\nvar _button_to_rarity_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready() -> void:\n\t_generic_tab.set_item_type_filters_visible(false)\n\t\n\tvar tower_id_list: Array = TowerProperties.get_tower_id_list()\n\t\n#\tThis sort groups towers by element, rarity and family\n\ttower_id_list.sort_custom(\n\t\tfunc (a: int, b: int) -> bool:\n\t\t\tvar element_a: Element.enm = TowerProperties.get_element(a)\n\t\t\tvar element_b: Element.enm = TowerProperties.get_element(b)\n\t\t\tvar family_a: int = TowerProperties.get_family(a)\n\t\t\tvar family_b: int = TowerProperties.get_family(b)\n\t\t\tvar family_cost_a: int = TowerProperties.get_cost(family_a)\n\t\t\tvar family_cost_b: int = TowerProperties.get_cost(family_b)\n\t\t\tvar tier_a: int = TowerProperties.get_tier(a)\n\t\t\tvar tier_b: int = TowerProperties.get_tier(b)\n\t\t\tvar rarity_a: int = TowerProperties.get_rarity(a)\n\t\t\tvar rarity_b: int = TowerProperties.get_rarity(b)\n\t\t\t\n\t\t\tif family_a == family_b:\n\t\t\t\treturn tier_a < tier_b\n\t\t\telif element_a != element_b:\n\t\t\t\treturn element_a < element_b\n\t\t\telif rarity_a != rarity_b:\n\t\t\t\treturn rarity_a < rarity_b\n\t\t\telif family_cost_a == family_cost_b:\n\t\t\t\treturn family_a < family_b\n\t\t\telse:\n\t\t\t\treturn family_cost_a < family_cost_b\n\t\t\t)\n\t\n\tfor tower_id in tower_id_list:\n\t\tvar tower_button: TowerButton = TowerButton.make()\n\t\ttower_button.hide_freshness_indicator()\n\t\ttower_button.set_tower_id(tower_id)\n\t\ttower_button.set_tooltip_is_enabled(false)\n\t\ttower_button.set_tier_visible(true)\n\t\ttower_button.hide_freshness_indicator()\n\t\t_generic_tab.add_button_to_grid(tower_button)\n\t\t\n\t\t_button_list.append(tower_button)\n\t\n\tfor button in _button_list:\n\t\tvar tower_id: int = button.get_tower_id()\n\t\tbutton.pressed.connect(_on_button_pressed.bind(tower_id))\n\n#\tNOTE: need to cache searchable names ahead of time\n#\tbecause calculating them is a bit costly. Calculating\n#\tsearchable names while searching would cause some lag.\n\tfor button in _button_list:\n\t\tvar tower_id: int = button.get_tower_id()\n\t\tvar tower_name: String = TowerProperties.get_display_name(tower_id)\n\t\tvar searchable_name: String = EncyclopediaTowers.make_searchable_string(tower_name)\n\t\tvar element: Element.enm = TowerProperties.get_element(tower_id)\n\t\tvar rarity: Rarity.enm = TowerProperties.get_rarity(tower_id)\n\t\t\n\t\t_button_to_searchable_name_map[button] = searchable_name\n\t\t_button_to_element_map[button] = element\n\t\t_button_to_rarity_map[button] = rarity\n\n\tfor button in _button_list:\n\t\tvar tower_id: int = button.get_tower_id()\n\t\tvar tower_name: String = TowerProperties.get_display_name(tower_id)\n\t\t\n\t\tbutton.tooltip_text = tower_name\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_text_for_tower(tower_id: int) -> String:\n\tvar text: String = \"\"\n\t\n\tvar description: String = TowerProperties.get_description(tower_id)\n\tvar author: String = TowerProperties.get_author(tower_id)\n\tvar element: Element.enm = TowerProperties.get_element(tower_id)\n\tvar element_string: String = Element.convert_to_colored_string(element)\n\tvar dps: int = floori(TowerProperties.get_dps(tower_id))\n\tvar attack_enabled: bool = TowerProperties.get_attack_enabled(tower_id)\n\tvar attack_type: AttackType.enm = TowerProperties.get_attack_type(tower_id)\n\tvar attack_type_string: String = AttackType.convert_to_colored_string(attack_type)\n\tvar attack_range: int = floor(TowerProperties.get_range(tower_id))\n\tvar mana: int = floor(TowerProperties.get_mana(tower_id))\n\tvar mana_regen: int = floor(TowerProperties.get_mana_regen(tower_id))\n\tvar specials_and_extra_text: String = RichTexts.get_tower_specials_and_extra_text(tower_id)\n\n\tvar gold_cost: int = TowerProperties.get_cost(tower_id)\n\tvar tome_cost: int = TowerProperties.get_tome_cost(tower_id)\n\tvar food_cost: int = TowerProperties.get_food_cost(tower_id)\n\t\n\tif tome_cost != 0:\n\t\ttext += \"[img=32x32]res://resources/icons/hud/gold.tres[/img] [color=GOLD]%s[/color] [img=32x32]res://resources/icons/hud/knowledge_tome.tres[/img] [color=GOLD]%s[/color] [img=32x32]res://resources/icons/hud/tower_food.tres[/img] [color=GOLD]%s[/color]\\n\" % [gold_cost, tome_cost, food_cost]\n\telse:\n\t\ttext += \"[img=32x32]res://resources/icons/hud/gold.tres[/img] [color=GOLD]%s[/color] [img=32x32]res://resources/icons/hud/tower_food.tres[/img] [color=GOLD]%s[/color]\\n\" % [gold_cost, food_cost]\n\t\n\ttext += \" \\n\"\n\t\n\tif !description.is_empty():\n\t\ttext += \"[color=LIGHT_BLUE]%s[/color]\\n\" % description\n\t\ttext += \" \\n\"\n\t\n\ttext += \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"TOWER_TOOLTIP_AUTHOR\"), author]\n\ttext += \"[color=YELLOW]%s[/color] %s\\n\" % [tr(\"TOWER_TOOLTIP_ELEMENT\"), element_string]\n\tif attack_enabled:\n\t\ttext += tr(\"TOWER_TOOLTIP_ATTACK\").format({DPS = dps, ATTACK_TYPE = attack_type_string, RANGE = attack_range})\n\t\ttext += \"\\n\"\n\n\tif mana > 0:\n\t\ttext += tr(\"TOWER_TOOLTIP_MANA\").format({MANA_MAX = mana, MANA_REGEN = mana_regen})\n\t\ttext += \"\\n\"\n\t\n\ttext += \" \\n\"\n\n\tif !specials_and_extra_text.is_empty():\n\t\ttext += specials_and_extra_text\n\t\ttext += \" \\n\"\n\n\tvar ability_id_list: Array = TowerProperties.get_ability_id_list(tower_id)\n\tfor ability_id in ability_id_list:\n\t\tvar ability_text: String = RichTexts.get_ability_text_long(ability_id)\n\n\t\ttext += ability_text\n\t\ttext += \" \\n\"\n\n\tvar aura_id_list: Array = TowerProperties.get_aura_id_list(tower_id)\n\tfor aura_id in aura_id_list:\n\t\tvar aura_text: String = RichTexts.get_aura_text_long(aura_id)\n\n\t\ttext += aura_text\n\t\ttext += \" \\n\"\n\n\tvar autocast_id_list: Array = TowerProperties.get_autocast_id_list(tower_id)\n\tfor autocast_id in autocast_id_list:\n\t\tvar autocast_text: String = RichTexts.get_autocast_text_long(autocast_id)\n\n\t\ttext += autocast_text\n\t\ttext += \" \\n\"\n\n\treturn text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_button_pressed(tower_id: int):\n\t_generic_tab.set_selected_tower_id(tower_id)\n\t\n\tvar tower_name: String = TowerProperties.get_display_name(tower_id)\n\t_generic_tab.set_selected_name(tower_name)\n\t\n\tvar text: String = _get_text_for_tower(tower_id)\n\t_generic_tab.set_info_text(text)\n\n\nfunc _on_encyclopedia_generic_tab_filter_changed() -> void:\n\tvar empty_item_type_map: Dictionary = {}\n\tEncyclopediaTowers.update_filtering(_button_list, _generic_tab, _button_to_searchable_name_map, empty_item_type_map, _button_to_rarity_map, _button_to_element_map)\n\n\nfunc _on_encyclopedia_generic_tab_close_pressed() -> void:\n\tclose_pressed.emit()\n\n\n#########################\n###       Static      ###\n#########################\n\n# Simplify string by removing non-significant characters.\n# This makes the string searchable.\nstatic func make_searchable_string(string: String) -> String:\n\tvar result: String = string.replace(\",\", \"\")\n\tresult = string.replace(\" \", \"\")\n\tresult = string.replace(\"-\", \"\")\n\tresult = result.to_lower()\n\t\n\treturn result\n\n\nstatic func update_filtering(button_list: Array, generic_tab: EncyclopediaGenericTab, button_to_searchable_name_map: Dictionary, button_to_item_type_map: Dictionary, button_to_rarity_map: Dictionary, button_to_element_map: Dictionary):\n\tvar item_type_filter_list: Array[ItemType.enm] = generic_tab.get_item_type_filter()\n\tvar element_filter_list: Array[Element.enm] = generic_tab.get_element_filter()\n\tvar rarity_filter_list: Array[Rarity.enm] = generic_tab.get_rarity_filter()\n\tvar search_text: String = generic_tab.get_search_text()\n\tsearch_text = EncyclopediaTowers.make_searchable_string(search_text)\n\t\n\tfor button in button_list:\n\t\tvar searchable_name: String = button_to_searchable_name_map[button]\n\t\tvar name_match: bool = searchable_name.contains(search_text) || search_text.is_empty()\n\t\tvar item_type: ItemType.enm = button_to_item_type_map.get(button, ItemType.enm.REGULAR)\n\t\tvar item_type_filter_match: bool\n\t\tif !button_to_item_type_map.is_empty():\n\t\t\titem_type_filter_match = item_type_filter_list.has(item_type)\n\t\telse:\n\t\t\titem_type_filter_match = true\n\t\tvar element: Element.enm = button_to_element_map.get(button, Element.enm.NONE)\n\t\tvar element_filter_match: bool\n\t\tif !button_to_element_map.is_empty():\n\t\t\telement_filter_match = element_filter_list.has(element)\n\t\telse:\n\t\t\telement_filter_match = true\n\t\tvar rarity: Element.enm = button_to_rarity_map[button]\n\t\tvar rarity_filter_match: bool = rarity_filter_list.has(rarity)\n\t\tvar button_should_be_visible: bool = name_match && item_type_filter_match && element_filter_match && rarity_filter_match\n\t\t\n\t\tbutton.visible = button_should_be_visible\n"
  },
  {
    "path": "src/ui/title_screen/encyclopedia_towers.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bchd7sh3vf6tx\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/encyclopedia_towers.gd\" id=\"1_562qq\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cqj4g0gfbrtev\" path=\"res://src/ui/title_screen/encyclopedia_generic_tab.tscn\" id=\"2_yoawr\"]\n\n[node name=\"EncyclopediaTowers\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_generic_tab\")]\ntheme_override_constants/separation = 15\nscript = ExtResource(\"1_562qq\")\n_generic_tab = NodePath(\"EncyclopediaGenericTab\")\nmetadata/_tab_index = 0\n\n[node name=\"EncyclopediaGenericTab\" parent=\".\" instance=ExtResource(\"2_yoawr\")]\nlayout_mode = 2\n\n[connection signal=\"close_pressed\" from=\"EncyclopediaGenericTab\" to=\".\" method=\"_on_encyclopedia_generic_tab_close_pressed\"]\n[connection signal=\"filter_changed\" from=\"EncyclopediaGenericTab\" to=\".\" method=\"_on_encyclopedia_generic_tab_filter_changed\"]\n"
  },
  {
    "path": "src/ui/title_screen/export_exp_menu.gd",
    "content": "class_name ExportExpMenu extends Control\n\n\n@export var _exp_password_edit: TextEdit\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_exp_password(value: String):\n\t_exp_password_edit.text = value\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_close_button_pressed():\n\thide()\n"
  },
  {
    "path": "src/ui/title_screen/export_exp_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b3gh33xi2di32\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_nvj37\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/export_exp_menu.gd\" id=\"3_qmel2\"]\n\n[node name=\"ExportExpMenu\" type=\"Control\" node_paths=PackedStringArray(\"_exp_password_edit\")]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_force_pass_scroll_events = false\nscript = ExtResource(\"3_qmel2\")\n_exp_password_edit = NodePath(\"PanelContainer/VBoxContainer/TextEdit\")\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(600, 0)\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -300.0\noffset_top = -142.5\noffset_right = 300.0\noffset_bottom = 142.5\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme = ExtResource(\"2_nvj37\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"EXPORT_POPUP\"\nautowrap_mode = 2\n\n[node name=\"TextEdit\" type=\"TextEdit\" parent=\"PanelContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 40)\nlayout_mode = 2\ntext = \"asdfasdfasdfasefaef\"\neditable = false\ncontext_menu_enabled = false\n\n[node name=\"CloseButton\" type=\"Button\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"CLOSE_BUTTON\"\n\n[connection signal=\"pressed\" from=\"PanelContainer/VBoxContainer/CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/import_exp_menu.gd",
    "content": "class_name ImportExpMenu extends Control\n\n\nsignal import_pressed()\n\n\n@export var _exp_password_edit: TextEdit\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_exp_password() -> String:\n\tvar exp_password: String = _exp_password_edit.text\n\t\n\treturn exp_password\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_visibility_changed():\n\t_exp_password_edit.clear()\n\n\nfunc _on_import_button_pressed():\n\timport_pressed.emit()\n\n\nfunc _on_close_button_pressed():\n\thide()\n"
  },
  {
    "path": "src/ui/title_screen/import_exp_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://b3kgwa2iuucrh\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/import_exp_menu.gd\" id=\"1_ishyk\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_ui0c6\"]\n\n[node name=\"ImportExpMenu\" type=\"Control\" node_paths=PackedStringArray(\"_exp_password_edit\")]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nmouse_force_pass_scroll_events = false\nscript = ExtResource(\"1_ishyk\")\n_exp_password_edit = NodePath(\"PanelContainer/VBoxContainer/ExpPasswordEdit\")\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(600, 0)\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -123.0\noffset_top = -174.5\noffset_right = 123.0\noffset_bottom = 174.5\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme = ExtResource(\"2_ui0c6\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"IMPORT_POPUP\"\nautowrap_mode = 2\n\n[node name=\"ExpPasswordEdit\" type=\"TextEdit\" parent=\"PanelContainer/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 40)\nlayout_mode = 2\ncontext_menu_enabled = false\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\n\n[node name=\"CloseButton\" type=\"Button\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"CLOSE_BUTTON\"\n\n[node name=\"ImportButton\" type=\"Button\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"IMPORT_BUTTON\"\n\n[connection signal=\"visibility_changed\" from=\".\" to=\".\" method=\"_on_visibility_changed\"]\n[connection signal=\"pressed\" from=\"PanelContainer/VBoxContainer/HBoxContainer/CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n[connection signal=\"pressed\" from=\"PanelContainer/VBoxContainer/HBoxContainer/ImportButton\" to=\".\" method=\"_on_import_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/create_lan_match_menu.gd",
    "content": "class_name CreateLanMatchMenu extends PanelContainer\n\n\nsignal cancel_pressed()\nsignal create_pressed()\n\n\n@export var _match_config_panel: MatchConfigPanel\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_match_config() -> MatchConfig:\n\tvar match_config: MatchConfig = _match_config_panel.get_match_config()\n\t\n\treturn match_config\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_cancel_button_pressed():\n\tcancel_pressed.emit()\n\n\nfunc _on_create_button_pressed():\n\tcreate_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/create_lan_match_menu.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://d0m1fiwnsk3tf\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_fm3ja\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dc67simk1xfp4\" path=\"res://src/ui/title_screen/match_config_panel.tscn\" id=\"2_g0u3e\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/lan_match/create_lan_match_menu.gd\" id=\"2_tb3dy\"]\n\n[node name=\"CreateLanMatchMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_match_config_panel\")]\ntheme = ExtResource(\"1_fm3ja\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_tb3dy\")\n_match_config_panel = NodePath(\"VBoxContainer/MatchConfigPanel\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Choose game settings:\"\n\n[node name=\"MatchConfigPanel\" parent=\"VBoxContainer\" instance=ExtResource(\"2_g0u3e\")]\nlayout_mode = 2\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nalignment = 2\n\n[node name=\"CancelButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"Cancel\"\n\n[node name=\"CreateButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"Create\n\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CancelButton\" to=\".\" method=\"_on_cancel_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CreateButton\" to=\".\" method=\"_on_create_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/lan_connect_menu.gd",
    "content": "class_name LanConnectMenu extends PanelContainer\n\n\nsignal join_pressed()\nsignal cancel_pressed()\nsignal create_pressed()\n\n\n@export var _address_edit: LineEdit\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_entered_address() -> String:\n\treturn _address_edit.text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_cancel_button_pressed():\n\tcancel_pressed.emit()\n\n\nfunc _on_create_button_pressed():\n\tcreate_pressed.emit()\n\n\nfunc _on_join_button_pressed():\n\tjoin_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/lan_connect_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cnnkyqysqqyar\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_vaewn\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/lan_match/lan_connect_menu.gd\" id=\"2_82rep\"]\n\n[node name=\"LanConnectMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_address_edit\")]\ncustom_minimum_size = Vector2(900, 400)\ntheme = ExtResource(\"1_vaewn\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_82rep\")\n_address_edit = NodePath(\"VBoxContainer/GridContainer/PanelContainer2/MarginContainer/HBoxContainer/Address Edit\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"LAN Multiplayer\"\nhorizontal_alignment = 1\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\ntheme_override_constants/v_separation = 10\ncolumns = 2\n\n[node name=\"PanelContainer2\" type=\"PanelContainer\" parent=\"VBoxContainer/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 0\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"VBoxContainer/GridContainer/PanelContainer2\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer/GridContainer/PanelContainer2/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer/GridContainer/PanelContainer2/MarginContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"IP Address:\"\n\n[node name=\"Address Edit\" type=\"LineEdit\" parent=\"VBoxContainer/GridContainer/PanelContainer2/MarginContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"VBoxContainer/GridContainer\"]\nlayout_mode = 2\n\n[node name=\"JoinButton\" type=\"Button\" parent=\"VBoxContainer/GridContainer/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Join\"\n\n[node name=\"CreateButton\" type=\"Button\" parent=\"VBoxContainer/GridContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"Create\"\n\n[node name=\"CancelButton\" type=\"Button\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\ntext = \"Cancel\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/GridContainer/VBoxContainer/JoinButton\" to=\".\" method=\"_on_join_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/GridContainer/VBoxContainer/CreateButton\" to=\".\" method=\"_on_create_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/CancelButton\" to=\".\" method=\"_on_cancel_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/lan_lobby_menu.gd",
    "content": "class_name LanLobbyMenu extends PanelContainer\n\n\n# Menu for an open LAN lobby, before the game begins.\n# Displays players in the lobby.\n\n\nsignal start_pressed()\nsignal back_pressed()\n\n\n@export var _player_list: ItemList\n@export var _match_config_label: RichTextLabel\n@export var _host_address_container: HBoxContainer\n@export var _host_address_line_edit: LineEdit\n@export var _start_button: Button\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_player_list(player_list: Array[String]):\n\t_player_list.clear()\n\t\n\tfor player in player_list:\n\t\t_player_list.add_item(player)\n\t\n\tfor i in range(0, _player_list.item_count):\n\t\t_player_list.set_item_selectable(i, false)\n\n\nfunc display_match_config(match_config: MatchConfig):\n\tvar match_config_string: String = match_config.get_display_string_rich()\n\t\n\t_match_config_label.clear()\n\t_match_config_label.append_text(match_config_string)\n\n\nfunc set_host_address(value: String):\n\t_host_address_line_edit.text = value\n\n\nfunc set_host_address_visible(value: bool):\n\t_host_address_container.visible = value\n\n\nfunc set_start_button_visible(value: bool):\n\t_start_button.visible = value\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_back_button_pressed():\n\tback_pressed.emit()\n\n\nfunc _on_start_button_pressed():\n\tstart_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/lan_lobby_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://cecaq4wvkvxv3\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/lan_match/lan_lobby_menu.gd\" id=\"1_gou4l\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_sgqs1\"]\n\n\n[node name=\"LanLobbyMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_player_list\", \"_match_config_label\", \"_host_address_container\", \"_host_address_line_edit\", \"_start_button\")]\ntheme = ExtResource(\"1_sgqs1\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"1_gou4l\")\n_player_list = NodePath(\"VBoxContainer/PlayerList\")\n_match_config_label = NodePath(\"VBoxContainer/MatchConfigLabel\")\n_host_address_container = NodePath(\"VBoxContainer/HostAddressContainer\")\n_host_address_line_edit = NodePath(\"VBoxContainer/HostAddressContainer/HostAddressLineEdit\")\n_start_button = NodePath(\"VBoxContainer/HBoxContainer/StartButton\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"Header\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Match lobby\"\nhorizontal_alignment = 1\n\n[node name=\"MatchConfigLabel\" type=\"RichTextLabel\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nfit_content = true\n\n[node name=\"HostAddressContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nvisible = false\nlayout_mode = 2\n\n[node name=\"HostAddressLabelLeft\" type=\"Label\" parent=\"VBoxContainer/HostAddressContainer\"]\nlayout_mode = 2\ntext = \"Host address:\"\n\n[node name=\"HostAddressLineEdit\" type=\"LineEdit\" parent=\"VBoxContainer/HostAddressContainer\"]\nlayout_mode = 2\nplaceholder_text = \"192.168.0.12\"\neditable = false\nexpand_to_text_length = true\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntext = \"Connected players:\"\n\n[node name=\"PlayerList\" type=\"ItemList\" parent=\"VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 200)\nlayout_mode = 2\nallow_search = false\nauto_height = true\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\n\n[node name=\"BackButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Back\"\n\n[node name=\"StartButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Start\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/BackButton\" to=\".\" method=\"_on_back_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/StartButton\" to=\".\" method=\"_on_start_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/setup_lan_game.gd",
    "content": "class_name SetupLanGame extends Node\n\n\n# Handles logic for creating and joining LAN matches.\n\n\nconst SERVER_PEER_ID: int = 1\n\n\nvar _current_match_config: MatchConfig = null\n\n\n@export var _title_screen: TitleScreen\n@export var _lan_connect_menu: LanConnectMenu\n@export var _lan_lobby_menu: LanLobbyMenu\n@export var _create_lan_match_menu: CreateLanMatchMenu\n\nvar _peer_id_to_player_name_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tmultiplayer.connected_to_server.connect(_on_connected_to_server)\n\tmultiplayer.peer_connected.connect(_on_peer_connected)\n\tmultiplayer.peer_disconnected.connect(_on_peer_disconnected)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_player_list_in_lobby_menu():\n\tvar peer_id_list: Array = multiplayer.get_peers()\n\tvar local_peer_id: int = multiplayer.get_unique_id()\n\tpeer_id_list.append(local_peer_id)\n\n\tvar player_list: Array[String] = []\n\n\tfor peer_id in peer_id_list:\n\t\tvar fallback_string: String = \"Player %d\" % peer_id\n\t\tvar player_name: String = _peer_id_to_player_name_map.get(peer_id, fallback_string)\n\t\tplayer_list.append(player_name)\n\t\n\t_lan_lobby_menu.set_player_list(player_list)\n\n\n# All peers (including the host itself) call this f-n to\n# tell the host their player names. The host later passes\n# this info to all peers.\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc _give_local_player_name_to_host(player_name: String):\n\tvar peer_id: int = multiplayer.get_remote_sender_id()\n\t_peer_id_to_player_name_map[peer_id] = player_name\n\n\t_receive_player_name_map_from_host.rpc(_peer_id_to_player_name_map)\n\n\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc _receive_player_name_map_from_host(player_name_map: Dictionary):\n\t_peer_id_to_player_name_map = player_name_map\n\t\n#\tNOTE: need to update displayed player list to show\n#\tupdated player names\n\t_update_player_list_in_lobby_menu()\n\n\n@rpc(\"authority\", \"call_local\", \"reliable\")\nfunc _receive_match_config_from_host(match_config_bytes: PackedByteArray):\n\t_current_match_config = MatchConfig.convert_from_bytes(match_config_bytes)\n\t_lan_lobby_menu.display_match_config(_current_match_config)\n\n\nfunc _connect_to_lobby(address: String) -> bool:\n\tvar peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()\n\tvar create_client_result: Error = peer.create_client(address, Constants.SERVER_PORT)\n\n\tif create_client_result != OK:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"SETUP_LAN_ERROR_FAILED_CLIENT\").format({ERROR = error_string(create_client_result)}))\n\n\t\treturn false\n\n\tpeer.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)\n\tmultiplayer.set_multiplayer_peer(peer)\n\t\n\treturn true\n\n\n# This check is needed in case current MultiplayerPeer is\n# set to NakamaMultiplayerPeer, which means that all signals\n# should be ignored.\nfunc _multiplayer_peer_is_enet() -> bool:\n\tvar multiplayer_peer: MultiplayerPeer = multiplayer.get_multiplayer_peer()\n\tvar peer_is_enet: bool = multiplayer_peer is ENetMultiplayerPeer\n\n\treturn peer_is_enet\n\n\nfunc _determine_host_address() -> String:\n\tvar address: String = \"\"\n\n\tif OS.has_feature(\"windows\"):\n\t\tif OS.has_environment(\"COMPUTERNAME\"):\n\t\t\taddress = IP.resolve_hostname(OS.get_environment(\"COMPUTERNAME\"), IP.Type.TYPE_IPV4)\n\telif OS.has_feature(\"x11\"):\n\t\tif OS.has_environment(\"HOSTNAME\"):\n\t\t\taddress = IP.resolve_hostname(OS.get_environment(\"HOSTNAME\"), IP.Type.TYPE_IPV4)\n\telif OS.has_feature(\"OSX\"):\n\t\tif OS.has_environment(\"HOSTNAME\"):\n\t\t\taddress = IP.resolve_hostname(OS.get_environment(\"HOSTNAME\"), IP.Type.TYPE_IPV4)\n\n\tif !address.is_empty():\n\t\treturn address\n\telse:\n\t\treturn \"UNKNOWN\"\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_connected_to_server():\n\tif !_multiplayer_peer_is_enet():\n\t\treturn\n\n\tvar local_player_name: String = Settings.get_setting(Settings.PLAYER_NAME)\n\t_give_local_player_name_to_host.rpc_id(SERVER_PEER_ID, local_player_name)\n\n\nfunc _on_peer_connected(peer_id: int):\n\tif !_multiplayer_peer_is_enet():\n\t\treturn\n\n# \tWhen a new peer connects, host(server) will tell the\n# \tnewly connected peer the names of all of the players.\n\tif multiplayer.is_server():\n\t\t_receive_player_name_map_from_host.rpc_id(peer_id, _peer_id_to_player_name_map)\n\t\tvar match_config_bytes: PackedByteArray = _current_match_config.convert_to_bytes()\n\t\t_receive_match_config_from_host.rpc_id(peer_id, match_config_bytes)\n\t\n\t_update_player_list_in_lobby_menu()\n\n\nfunc _on_peer_disconnected(_id: int):\n\tif !_multiplayer_peer_is_enet():\n\t\treturn\n\n\t_update_player_list_in_lobby_menu()\n\n\nfunc _on_create_lan_match_menu_create_pressed():\n\t_current_match_config = _create_lan_match_menu.get_match_config()\n\n\tvar team_mode: TeamMode.enm = _current_match_config.get_team_mode()\n\tvar player_count_max: int = TeamMode.get_player_count_max(team_mode)\n\tvar client_count_max: int = player_count_max - 1\n\n\tvar peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()\n\tvar create_server_result: Error = peer.create_server(Constants.SERVER_PORT, client_count_max)\n\tif create_server_result != OK:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"SETUP_LAN_ERROR_FAILED_SERVER\").format({ERROR = error_string(create_server_result)}))\n\n\t\treturn\n\n\tpeer.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)\n\tmultiplayer.set_multiplayer_peer(peer)\n\n\t_title_screen.switch_to_tab(TitleScreen.Tab.LAN_LOBBY)\n\t_lan_lobby_menu.display_match_config(_current_match_config)\n\tvar host_address: String = _determine_host_address()\n\t_lan_lobby_menu.set_host_address(host_address)\n\t_lan_lobby_menu.set_host_address_visible(true)\n\t_lan_lobby_menu.set_start_button_visible(true)\n\n\tvar local_player_name: String = Settings.get_setting(Settings.PLAYER_NAME)\n\t_give_local_player_name_to_host.rpc_id(SERVER_PEER_ID, local_player_name)\n\n\t_update_player_list_in_lobby_menu()\n\n\nfunc _on_lan_connect_menu_create_pressed():\n\t_title_screen.switch_to_tab(TitleScreen.Tab.CREATE_LAN_MATCH)\n\n\nfunc _on_lan_lobby_menu_start_pressed():\n\tvar is_host: bool = multiplayer.is_server()\n\tif !is_host:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"SETUP_LAN_ERROR_ONLY_HOST_CAN_START\"))\n\t\t\n\t\treturn\n\t\n\tGlobals._enet_peer_id_to_player_name = _peer_id_to_player_name_map\n\t\n\tvar difficulty: Difficulty.enm = _current_match_config.get_difficulty()\n\tvar game_length: int = _current_match_config.get_game_length()\n\tvar game_mode: GameMode.enm = _current_match_config.get_game_mode()\n\tvar team_mode: TeamMode.enm = _current_match_config.get_team_mode()\n\tvar origin_seed: int = randi()\n\t\n\t_title_screen.start_game.rpc(PlayerMode.enm.MULTIPLAYER, game_length, game_mode, difficulty, team_mode, origin_seed, Globals.ConnectionType.ENET)\n\n\nfunc _on_lan_connect_menu_join_pressed():\n\tvar address: String = _lan_connect_menu.get_entered_address()\n\t\n\tif address.is_empty():\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"SETUP_LAN_ERROR_MISSING_ADDRESS\"))\n\t\t\n\t\treturn\n\t\n\t_connect_to_lobby(address)\n\t\n\t_title_screen.switch_to_tab(TitleScreen.Tab.LAN_LOBBY)\n\n\t_lan_lobby_menu.set_host_address_visible(false)\n\t_lan_lobby_menu.set_start_button_visible(false)\n\n\n# NOTE: both server and clients need to close the\n# connection when leaving lobby menu\nfunc _on_lan_lobby_menu_back_pressed():\n\tmultiplayer.multiplayer_peer.close()\n"
  },
  {
    "path": "src/ui/title_screen/lan_match/setup_lan_game.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://cusqgcgg37fj7\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/lan_match/setup_lan_game.gd\" id=\"1_02dc7\"]\n\n[node name=\"SetupLanGame\" type=\"Node\"]\nscript = ExtResource(\"1_02dc7\")\n"
  },
  {
    "path": "src/ui/title_screen/match_config.gd",
    "content": "class_name MatchConfig\n\n\nenum Field {\n\tGAME_MODE,\n\tDIFFICULTY,\n\tGAME_LENGTH,\n\tTEAM_MODE,\n\tCOUNT,\n}\n\n# Stores config values for a game match.\n\n\nvar _game_mode: GameMode.enm = GameMode.enm.BUILD\nvar _difficulty: Difficulty.enm = Difficulty.enm.BEGINNER\nvar _game_length: int = Constants.WAVE_COUNT_FULL\nvar _team_mode: TeamMode.enm = TeamMode.enm.ONE_PLAYER_PER_TEAM\n\n\nconst KEY_DIFFICULTY: String = \"difficulty\"\nconst KEY_GAME_MODE: String = \"game_mode\"\nconst KEY_GAME_LENGTH: String = \"game_length\"\nconst KEY_TEAM_MODE: String = \"team_mode\"\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init(game_mode: GameMode.enm, difficulty: Difficulty.enm, game_length: int, team_mode: TeamMode.enm):\n\t_game_mode = game_mode\n\t_difficulty = difficulty\n\t_game_length = game_length\n\t_team_mode = team_mode\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_difficulty() -> Difficulty.enm:\n\treturn _difficulty\n\n\nfunc get_game_length() -> int:\n\treturn _game_length\n\n\nfunc get_game_mode() -> GameMode.enm:\n\treturn _game_mode\n\n\nfunc get_team_mode() -> TeamMode.enm:\n\treturn _team_mode\n\n\nfunc get_display_string_rich() -> String:\n\tvar display_string: String = MatchConfig.convert_configs_to_string(_game_length, _game_mode, _difficulty, _team_mode)\n\t\n\treturn display_string\n\n\nfunc convert_to_bytes() -> PackedByteArray:\n\tvar dict: Dictionary = {}\n\tdict[Field.DIFFICULTY] = _difficulty\n\tdict[Field.GAME_MODE] = _game_mode\n\tdict[Field.GAME_LENGTH] = _game_length\n\tdict[Field.TEAM_MODE] = _team_mode\n\tvar bytes: PackedByteArray = var_to_bytes(dict)\n\t\n\treturn bytes\n\n\nstatic func convert_from_bytes(bytes: PackedByteArray) -> MatchConfig:\n\tvar dict: Dictionary = Utils.convert_bytes_to_dict(bytes)\n\t\n\tvar dict_is_valid: bool = Utils.check_dict_has_fields(dict, Field.COUNT)\n\tif !dict_is_valid:\n\t\treturn null\n\t\n\tvar game_mode: GameMode.enm = int(dict[Field.GAME_MODE]) as GameMode.enm\n\tvar difficulty: Difficulty.enm = int(dict[Field.DIFFICULTY]) as Difficulty.enm\n\tvar game_length: int = int(dict[Field.GAME_LENGTH])\n\tvar team_mode: TeamMode.enm = int(dict[Field.TEAM_MODE]) as TeamMode.enm\n\tvar match_config: MatchConfig = MatchConfig.new(game_mode, difficulty, game_length, team_mode)\n\t\n\treturn match_config\n\n\nfunc convert_to_dict() -> Dictionary:\n\tvar dict: Dictionary = {}\n\tvar difficulty_string: String = Difficulty.convert_to_string(_difficulty)\n\tvar game_mode_string: String = GameMode.convert_to_string(_game_mode)\n\tvar game_length_string: String = str(_game_length)\n\tvar team_mode_string: String = TeamMode.convert_to_string(_team_mode)\n\tdict[KEY_DIFFICULTY] = difficulty_string\n\tdict[KEY_GAME_MODE] = game_mode_string\n\tdict[KEY_GAME_LENGTH] = game_length_string\n\tdict[KEY_TEAM_MODE] = team_mode_string\n\t\n\treturn dict\n\n\nstatic func convert_from_dict(dict: Dictionary) -> MatchConfig:\n\tvar game_mode_string: String = dict.get(KEY_GAME_MODE, \"\")\n\tvar game_mode: GameMode.enm = GameMode.from_string(game_mode_string)\n\tvar difficulty_string: String = dict.get(KEY_DIFFICULTY, \"\")\n\tvar difficulty: Difficulty.enm = Difficulty.from_string(difficulty_string)\n\tvar game_length: int = dict.get(KEY_GAME_LENGTH, Constants.WAVE_COUNT_TRIAL) as int\n\tvar team_mode_string: String = dict.get(KEY_TEAM_MODE, \"\")\n\tvar team_mode: TeamMode.enm = TeamMode.from_string(team_mode_string)\n\tvar match_config: MatchConfig = MatchConfig.new(game_mode, difficulty, game_length, team_mode)\n\t\n\treturn match_config\n\n\nstatic func convert_configs_to_string(game_length: int, game_mode: GameMode.enm, difficulty: Difficulty.enm, team_mode: TeamMode.enm) -> String:\n\tvar game_length_string: String = _get_game_length_string(game_length)\n\tvar game_mode_string: String = GameMode.convert_to_display_string(game_mode)\n\tvar difficulty_string: String = Difficulty.convert_to_colored_string(difficulty)\n\tvar team_mode_string: String = TeamMode.convert_to_display_string(team_mode)\n\t\n\tvar display_string: String = \"[color=GOLD]%s[/color], [color=GOLD]%s[/color], %s, %s\\n\" % [game_length_string, game_mode_string, difficulty_string, team_mode_string]\n\t\n\treturn display_string\n\n\nstatic func _get_game_length_string(wave_count: int) -> String:\n\tvar game_length_string: String\n\n\tmatch wave_count:\n\t\tConstants.WAVE_COUNT_TRIAL: game_length_string = Utils.tr(\"GAME_LENGTH_TRIAL\")\n\t\tConstants.WAVE_COUNT_FULL: game_length_string = Utils.tr(\"GAME_LENGTH_FULL\")\n\t\tConstants.WAVE_COUNT_NEVERENDING: game_length_string = Utils.tr(\"GAME_LENGTH_NEVERENDING\")\n\t\t_: \"DEBUG - Unknown\"\n\n\treturn game_length_string\n"
  },
  {
    "path": "src/ui/title_screen/match_config_panel.gd",
    "content": "class_name MatchConfigPanel extends GridContainer\n\n\nvar _combo_index_to_game_length: Dictionary = {\n\t0: Constants.WAVE_COUNT_TRIAL,\n\t1: Constants.WAVE_COUNT_FULL,\n\t2: Constants.WAVE_COUNT_NEVERENDING,\n}\n\n@export var _difficulty_combo: OptionButton\n@export var _game_length_combo: OptionButton\n@export var _game_mode_combo: OptionButton\n@export var _team_mode_label: Label\n@export var _team_mode_combo: OptionButton\n\n\nfunc hide_team_mode_selector():\n\t_team_mode_label.hide()\n\t_team_mode_combo.hide()\n\n\nfunc set_difficulty(difficulty: Difficulty.enm):\n\t_difficulty_combo.select(difficulty)\n\n\nfunc set_game_mode(game_mode: GameMode.enm):\n\t_game_mode_combo.select(game_mode)\n\n\nfunc set_game_length(game_length: int):\n\tvar combo_index = _combo_index_to_game_length.find_key(game_length)\n\n\tif combo_index == null:\n\t\tpush_error(\"Invalid game length: %d\" % game_length)\n\n\t\treturn\n\t\n\t_game_length_combo.select(combo_index)\n\n\nfunc set_disabled(value: bool):\n\t_difficulty_combo.disabled = value\n\t_game_length_combo.disabled = value\n\t_game_mode_combo.disabled = value\n\n\nfunc get_difficulty() -> Difficulty.enm:\n\tvar selected_index: int = _difficulty_combo.get_selected()\n\tvar difficulty: Difficulty.enm = selected_index as Difficulty.enm\n\t\n\treturn difficulty\n\n\nfunc get_game_length() -> int:\n\tvar selected_index: int = _game_length_combo.get_selected()\n\tvar game_length: int = _combo_index_to_game_length[selected_index]\n\t\n\treturn game_length\n\n\nfunc get_game_mode() -> GameMode.enm:\n\tvar selected_index: int = _game_mode_combo.get_selected()\n\tvar game_mode: GameMode.enm = selected_index as GameMode.enm\n\t\n\treturn game_mode\n\n\nfunc get_team_mode() -> TeamMode.enm:\n\tvar selected_index: int = _team_mode_combo.get_selected()\n\tvar team_mode: TeamMode.enm = selected_index as TeamMode.enm\n\t\n\treturn team_mode\n\n\nfunc get_match_config() -> MatchConfig:\n\tvar game_mode: GameMode.enm = get_game_mode()\n\tvar difficulty: Difficulty.enm = get_difficulty()\n\tvar game_length: int = get_game_length()\n\tvar team_mode: TeamMode.enm = get_team_mode()\n\tvar match_config: MatchConfig = MatchConfig.new(game_mode, difficulty, game_length, team_mode)\n\t\n\treturn match_config\n"
  },
  {
    "path": "src/ui/title_screen/match_config_panel.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://dc67simk1xfp4\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/match_config_panel.gd\" id=\"1_wksi8\"]\n\n[node name=\"MatchConfigPanel\" type=\"GridContainer\" node_paths=PackedStringArray(\"_difficulty_combo\", \"_game_length_combo\", \"_game_mode_combo\", \"_team_mode_label\", \"_team_mode_combo\")]\ntheme_override_constants/v_separation = 5\ncolumns = 2\nscript = ExtResource(\"1_wksi8\")\n_difficulty_combo = NodePath(\"DifficultyCombo\")\n_game_length_combo = NodePath(\"GameLengthCombo\")\n_game_mode_combo = NodePath(\"GameModeCombo\")\n_team_mode_label = NodePath(\"TeamModeLabel\")\n_team_mode_combo = NodePath(\"TeamModeCombo\")\n\n[node name=\"Label\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntext = \"MATCH_CONFIG_DIFFICULTY\"\n\n[node name=\"DifficultyCombo\" type=\"OptionButton\" parent=\".\"]\nlayout_mode = 2\nfocus_mode = 0\nselected = 2\nitem_count = 5\npopup/item_0/text = \"DIFFICULTY_BEGINNER\"\npopup/item_1/text = \"DIFFICULTY_EASY\"\npopup/item_1/id = 1\npopup/item_2/text = \"DIFFICULTY_MEDIUM\"\npopup/item_2/id = 2\npopup/item_3/text = \"DIFFICULTY_HARD\"\npopup/item_3/id = 3\npopup/item_4/text = \"DIFFICULTY_EXTREME\"\npopup/item_4/id = 4\n\n[node name=\"Label2\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntext = \"MATCH_CONFIG_GAME_LENGTH\"\n\n[node name=\"GameLengthCombo\" type=\"OptionButton\" parent=\".\"]\nlayout_mode = 2\nfocus_mode = 0\nselected = 1\nitem_count = 3\npopup/item_0/text = \"MATCH_CONFIG_80_WAVE\"\npopup/item_1/text = \"MATCH_CONFIG_120_WAVE\"\npopup/item_1/id = 1\npopup/item_2/text = \"MATCH_CONFIG_240_WAVE\"\npopup/item_2/id = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntext = \"MATCH_CONFIG_GAME_MODE\"\n\n[node name=\"GameModeCombo\" type=\"OptionButton\" parent=\".\"]\nlayout_mode = 2\ntooltip_text = \"MATCH_CONFIG_TOOLTIP_GAME_MODE\"\nfocus_mode = 0\nselected = 1\nitem_count = 3\npopup/item_0/text = \"GAME_MODE_LONG_BUILD\"\npopup/item_1/text = \"GAME_MODE_LONG_RANDOM_WITH_UPGRADES\"\npopup/item_1/id = 1\npopup/item_2/text = \"GAME_MODE_LONG_TOTALLY_RANDOM\"\npopup/item_2/id = 2\n\n[node name=\"TeamModeLabel\" type=\"Label\" parent=\".\"]\nlayout_mode = 2\ntext = \"MATCH_CONFIG_TEAM_MODE\"\n\n[node name=\"TeamModeCombo\" type=\"OptionButton\" parent=\".\"]\nlayout_mode = 2\ntooltip_text = \"MATCH_CONFIG_TOOLTIP_TEAM_MODE\"\nselected = 1\nitem_count = 2\npopup/item_0/text = \"TEAM_MODE_FFA\"\npopup/item_1/text = \"TEAM_MODE_COOP\"\npopup/item_1/id = 1\n"
  },
  {
    "path": "src/ui/title_screen/message_popup.gd",
    "content": "class_name MessagePopup extends Control\n\n\n# Popup for displaying messages in title screen.\n\n\nvar _text: String = \"\"\n\n@export var _label: RichTextLabel\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_label.clear()\n\t_label.append_text(_text)\n\t\n#\tNOTE: autowrap mode of RichTextLabel must be set to\n#\t\"Word\" in the scene. Otherwise, RichTextLabel behaves\n#\tweirdly by expanding to maximum available height. This\n#\tmakes the popup very tall.\n\tvar autowrap_mode_is_correct: bool = _label.autowrap_mode == TextServer.AutowrapMode.AUTOWRAP_WORD\n\tif !autowrap_mode_is_correct:\n\t\tpush_error(\"RichTextLabel autowrap mode is incorrect. Make sure it's set to Word in the scene.\")\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make(text: String) -> MessagePopup:\n\tvar scene: PackedScene = load(\"res://src/ui/title_screen/message_popup.tscn\")\n\tvar instance: MessagePopup = scene.instantiate()\n\tinstance._text = text\n\t\n\treturn instance\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_ok_button_pressed():\n\thide()\n\tqueue_free()\n"
  },
  {
    "path": "src/ui/title_screen/message_popup.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://d1di6x5fjm4b5\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_uo1gt\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/message_popup.gd\" id=\"3_8ld02\"]\n\n[node name=\"MessagePopup\" type=\"Control\" node_paths=PackedStringArray(\"_label\")]\ntop_level = true\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\nscript = ExtResource(\"3_8ld02\")\n_label = NodePath(\"PanelContainer/MarginContainer/VBoxContainer/RichTextLabel\")\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(350, 250)\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -53.5\noffset_top = -46.0\noffset_right = 53.5\noffset_bottom = 46.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme = ExtResource(\"2_uo1gt\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 5\ntheme_override_constants/margin_top = 5\ntheme_override_constants/margin_right = 5\ntheme_override_constants/margin_bottom = 5\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer/MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\nbbcode_enabled = true\ntext = \"[center]Title[/center]\nMessage.\"\nfit_content = true\nautowrap_mode = 2\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"OkButton\" type=\"Button\" parent=\"PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"OK\"\n\n[connection signal=\"pressed\" from=\"PanelContainer/MarginContainer/VBoxContainer/OkButton\" to=\".\" method=\"_on_ok_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/missions_menu/mission_card.gd",
    "content": "class_name MissionCard extends PanelContainer\n\n\n@export var _number_label: Label\n@export var _description_label: Label\n@export var _completed_indicator: PanelContainer\n@export var _track_label: Label\n@export var _track_checkbox: CheckBox\n\n\nvar _mission_id: int\n\n\nfunc _ready():\n\tvar number_text: String = \"#%d\" % _mission_id\n\t_number_label.text = number_text\n\t\n\tvar description: String = MissionProperties.get_description(_mission_id)\n\t_description_label.text = description\n\t\n\tvar mission_is_complete: bool = MissionStatus.get_mission_is_complete(_mission_id)\n\t_completed_indicator.visible = mission_is_complete\n\t\n\tvar mission_is_tracked: bool = MissionTracking.get_mission_is_tracked(_mission_id)\n\t_track_checkbox.set_pressed_no_signal(mission_is_tracked)\n\t\n\tif mission_is_complete:\n\t\tset_theme_type_variation(\"UniqueRarityPanelContainer\")\n\t\t\n#\t\tIf mission is complete, then hide tracking UI\n#\t\tbecause there's no point to display it for completed\n#\t\tmissions.\n#\t\tNOTE: hide UI elements and leave the box container\n#\t\tvisible to have consistent width of the description\n#\t\tlabel for both complete/incomplete missions\n\t\t_track_label.hide()\n\t\t_track_checkbox.hide()\n\n\nfunc set_mission_id(mission_id: int):\n\t_mission_id = mission_id\n\n\nstatic func make(mission_id: int) -> MissionCard:\n\tvar card: MissionCard = Preloads.mission_card.instantiate()\n\tcard.set_mission_id(mission_id)\n\t\n\treturn card\n\n\nfunc _on_track_check_box_toggled(toggled_on: bool) -> void:\n#\tLimit max amount of tracked missions\n\tif toggled_on:\n\t\tvar prev_tracked_count: int = MissionTracking.get_tracked_count()\n\t\tvar going_over_max: bool = prev_tracked_count == MissionTracking.MAX_TRACKED_COUNT\n\t\t\n\t\tif going_over_max:\n\t\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"MISSION_TRACK_ERROR_TOO_MANY\").format({MAX_TRACKED_COUNT = MissionTracking.MAX_TRACKED_COUNT}))\n\t\t\t\n\t\t\t_track_checkbox.set_pressed_no_signal(false)\n\t\t\t\n\t\t\treturn\n\t\n\tMissionTracking.set_mission_is_tracked(_mission_id, toggled_on)\n"
  },
  {
    "path": "src/ui/title_screen/missions_menu/mission_card.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://crkei1pbrqxta\"]\n\n[ext_resource type=\"StyleBox\" uid=\"uid://cjho6n8sw5utc\" path=\"res://resources/theme/mission_complete_indicator.tres\" id=\"1_cof1l\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/missions_menu/mission_card.gd\" id=\"1_l76ty\"]\n\n[node name=\"MissionCard\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_number_label\", \"_description_label\", \"_completed_indicator\", \"_track_label\", \"_track_checkbox\")]\ncustom_minimum_size = Vector2(620, 110)\nsize_flags_horizontal = 3\ntheme_type_variation = &\"UncommonRarityPanelContainer\"\nscript = ExtResource(\"1_l76ty\")\n_number_label = NodePath(\"MarginContainer/HBoxContainer/NumberLabel\")\n_description_label = NodePath(\"MarginContainer/HBoxContainer/VBoxContainer/DescriptionLabel\")\n_completed_indicator = NodePath(\"MarginContainer2/CompletedIndicator\")\n_track_label = NodePath(\"MarginContainer/HBoxContainer/HBoxContainer/TrackLabel\")\n_track_checkbox = NodePath(\"MarginContainer/HBoxContainer/HBoxContainer/TrackCheckBox\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_vertical = 4\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"NumberLabel\" type=\"Label\" parent=\"MarginContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"#12\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"DescriptionLabel\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"Beat 240 Medium Upgrade with Master of Encyclopedic Wisdom builder\"\nvertical_alignment = 1\nautowrap_mode = 2\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(100, 0)\nlayout_mode = 2\n\n[node name=\"TrackLabel\" type=\"Label\" parent=\"MarginContainer/HBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"MISSION_CARD_TOOLTIP_TRACKING\"\nmouse_filter = 0\ntext = \"Track:\"\n\n[node name=\"TrackCheckBox\" type=\"CheckBox\" parent=\"MarginContainer/HBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntooltip_text = \"MISSION_CARD_TOOLTIP_TRACKING\"\nfocus_mode = 0\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = -35\n\n[node name=\"CompletedIndicator\" type=\"PanelContainer\" parent=\"MarginContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntheme_override_styles/panel = ExtResource(\"1_cof1l\")\n\n[node name=\"CompletedLabel\" type=\"Label\" parent=\"MarginContainer2/CompletedIndicator\"]\nlayout_mode = 2\ntext = \"COMPLETED\"\n\n[connection signal=\"toggled\" from=\"MarginContainer/HBoxContainer/HBoxContainer/TrackCheckBox\" to=\".\" method=\"_on_track_check_box_toggled\"]\n"
  },
  {
    "path": "src/ui/title_screen/missions_menu/missions_menu.gd",
    "content": "class_name MissionsMenu extends PanelContainer\n\n\nsignal close_pressed()\n\n\nfunc _on_close_button_pressed() -> void:\n\tclose_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/missions_menu/missions_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dhvrqpk4snrok\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/missions_menu/missions_menu.gd\" id=\"1_jybt1\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ddobckupfnl1y\" path=\"res://src/ui/title_screen/missions_menu/missions_menu_tab.tscn\" id=\"2_u6yfm\"]\n\n[node name=\"MissionsMenu\" type=\"PanelContainer\"]\ncustom_minimum_size = Vector2(870, 0)\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"1_jybt1\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"MISSIONS_MENU_MISSIONS\"\nhorizontal_alignment = 1\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\"VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 800)\nlayout_mode = 2\ncurrent_tab = 0\n\n[node name=\"MISSIONS_MENU_TAB_GENERAL\" parent=\"VBoxContainer/TabContainer\" instance=ExtResource(\"2_u6yfm\")]\nlayout_mode = 2\n_section_name = \"general\"\nmetadata/_tab_index = 0\n\n[node name=\"MISSIONS_MENU_TAB_ELEMENTS\" parent=\"VBoxContainer/TabContainer\" instance=ExtResource(\"2_u6yfm\")]\nvisible = false\nlayout_mode = 2\n_section_name = \"elements\"\nmetadata/_tab_index = 1\n\n[node name=\"MISSIONS_MENU_TAB_BUILDERS\" parent=\"VBoxContainer/TabContainer\" instance=ExtResource(\"2_u6yfm\")]\nvisible = false\nlayout_mode = 2\n_section_name = \"builders\"\nmetadata/_tab_index = 2\n\n[node name=\"MISSIONS_MENU_TAB_SPECIAL\" parent=\"VBoxContainer/TabContainer\" instance=ExtResource(\"2_u6yfm\")]\nvisible = false\nlayout_mode = 2\n_section_name = \"special\"\nmetadata/_tab_index = 3\n\n[node name=\"CloseButton\" type=\"Button\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\ntext = \"CLOSE_BUTTON\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/missions_menu/missions_menu_tab.gd",
    "content": "class_name MissionsMenuTab extends MarginContainer\n\n\n@export var _section_name: String\n@export var _mission_box: VBoxContainer\n@export var _completed_count_label: Label\n\n\nfunc _ready() -> void:\n\tvar id_list: Array = MissionProperties.get_id_list()\n\n#\tSort id list to display missions in order\n\tid_list.sort()\n\t\n\tfor id in id_list:\n\t\tvar mission_section: String = MissionProperties.get_section(id)\n\t\tvar section_match: bool = mission_section == _section_name\n\t\t\n\t\tif !section_match:\n\t\t\tcontinue\n\t\t\n\t\tvar card: MissionCard = MissionCard.make(id)\n\t\t\n\t\t_mission_box.add_child(card)\n\t\n\tvar total_count: int = _get_mission_count_in_section()\n\tvar completed_count: int = _get_completed_mission_count_in_section()\n\tvar complete_text: String = \"%d/%d\" % [completed_count, total_count]\n\t_completed_count_label.text = complete_text\n\n\nfunc _get_mission_count_in_section() -> int:\n\tvar count: int = 0\n\t\n\tvar id_list: Array = MissionProperties.get_id_list()\n\tfor id in id_list:\n\t\tvar mission_section: String = MissionProperties.get_section(id)\n\t\tvar section_match: bool = mission_section == _section_name\n\t\t\n\t\tif section_match:\n\t\t\tcount += 1\n\t\n\treturn count\n\n\nfunc _get_completed_mission_count_in_section() -> int:\n\tvar count: int = 0\n\t\n\tvar id_list: Array = MissionProperties.get_id_list()\n\tfor id in id_list:\n\t\tvar mission_section: String = MissionProperties.get_section(id)\n\t\tvar section_match: bool = mission_section == _section_name\n\t\tvar completed: bool = MissionStatus.get_mission_is_complete(id)\n\t\t\n\t\tif section_match && completed:\n\t\t\tcount += 1\n\t\n\treturn count\n"
  },
  {
    "path": "src/ui/title_screen/missions_menu/missions_menu_tab.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://ddobckupfnl1y\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/missions_menu/missions_menu_tab.gd\" id=\"1_sk0ti\"]\n\n[node name=\"MissionsMenuTab\" type=\"MarginContainer\" node_paths=PackedStringArray(\"_mission_box\", \"_completed_count_label\")]\ncustom_minimum_size = Vector2(400, 400)\nsize_flags_horizontal = 3\nscript = ExtResource(\"1_sk0ti\")\n_mission_box = NodePath(\"VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer2/VBoxContainer\")\n_completed_count_label = NodePath(\"VBoxContainer/PanelContainer/MarginContainer/HBoxContainer/CompletedCountLabel\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"VBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 5\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer/PanelContainer/MarginContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"MISSIONS_MENU_TAB\"\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(50, 0)\nlayout_mode = 2\n\n[node name=\"CompletedCountLabel\" type=\"Label\" parent=\"VBoxContainer/PanelContainer/MarginContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"1/10\n\"\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"VBoxContainer\"]\ncustom_minimum_size = Vector2(400, 400)\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"VBoxContainer/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_constants/margin_right = 20\n\n[node name=\"VBoxContainer2\" type=\"VBoxContainer\" parent=\"VBoxContainer/ScrollContainer/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_constants/separation = 20\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"VBoxContainer/ScrollContainer/MarginContainer/VBoxContainer2/VBoxContainer\"]\nlayout_mode = 2\n"
  },
  {
    "path": "src/ui/title_screen/notification_panel.gd",
    "content": "class_name NotificationPanel extends PanelContainer\n\n\n# Used for displaying notifications in title screen.\n# Fades out after a delay.\n\nconst VISIBLE_DURATION: float = 10.0\nconst FADEOUT_DURATION: float = 1.0\n\n@export var _label: RichTextLabel\n@export var _fadeout_timer: Timer\n\n\nfunc display_text(text: String):\n\t_label.clear()\n\t_label.append_text(text)\n\t\n\tmodulate = Color.WHITE\n\t_fadeout_timer.start(VISIBLE_DURATION)\n\n\nfunc _on_fadeout_timer_timeout():\n\tvar modulate_tween = create_tween()\n\tmodulate_tween.tween_property(self, \"modulate\",\n\t\tColor(modulate.r, modulate.g, modulate.b, 0),\n\t\tFADEOUT_DURATION).set_trans(Tween.TRANS_LINEAR)\n"
  },
  {
    "path": "src/ui/title_screen/notification_panel.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bvc2yim85t7vs\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_3e4dk\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/notification_panel.gd\" id=\"1_8mqn4\"]\n\n[node name=\"NotificationPanel\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_label\", \"_fadeout_timer\")]\ncustom_minimum_size = Vector2(400, 0)\ntheme = ExtResource(\"1_3e4dk\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"1_8mqn4\")\n_label = NodePath(\"MarginContainer/RichTextLabel\")\n_fadeout_timer = NodePath(\"MarginContainer/FadeoutTimer\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"MarginContainer\"]\nlayout_mode = 2\nbbcode_enabled = true\ntext = \"Placeholder text\"\nfit_content = true\n\n[node name=\"FadeoutTimer\" type=\"Timer\" parent=\"MarginContainer\"]\none_shot = true\n\n[connection signal=\"timeout\" from=\"MarginContainer/FadeoutTimer\" to=\".\" method=\"_on_fadeout_timer_timeout\"]\n"
  },
  {
    "path": "src/ui/title_screen/online/create_online_match_menu.gd",
    "content": "class_name CreateOnlineMatchMenu extends PanelContainer\n\n\nsignal cancel_pressed()\nsignal create_pressed()\n\n\n@export var _match_config_panel: MatchConfigPanel\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_match_config() -> MatchConfig:\n\tvar match_config: MatchConfig = _match_config_panel.get_match_config()\n\t\n\treturn match_config\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_cancel_button_pressed():\n\tcancel_pressed.emit()\n\n\nfunc _on_create_button_pressed():\n\tcreate_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/online/create_online_match_menu.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://ddpf0wt3rp57k\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_6c5n7\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/online/create_online_match_menu.gd\" id=\"2_cct1s\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dc67simk1xfp4\" path=\"res://src/ui/title_screen/match_config_panel.tscn\" id=\"3_cxmya\"]\n\n[node name=\"CreateOnlineMatchMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_match_config_panel\")]\ntheme = ExtResource(\"1_6c5n7\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_cct1s\")\n_match_config_panel = NodePath(\"VBoxContainer/MatchConfigPanel\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"ONLINE_MATCH_MENU_LABEL\"\n\n[node name=\"MatchConfigPanel\" parent=\"VBoxContainer\" instance=ExtResource(\"3_cxmya\")]\nlayout_mode = 2\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nalignment = 2\n\n[node name=\"CancelButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"CANCEL_BUTTON\"\n\n[node name=\"CreateButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"CREATE_BUTTON\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CancelButton\" to=\".\" method=\"_on_cancel_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CreateButton\" to=\".\" method=\"_on_create_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/online/match_card.gd",
    "content": "@tool\nclass_name MatchCard extends PanelContainer\n\n\n# Displays info about a match\n\n\nsignal join_pressed()\n\nvar _match_id: String = \"\"\n\n@export var _match_info_label: RichTextLabel\n@export var _player_count_label: RichTextLabel\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc load_match(match_: NakamaAPI.ApiMatch):\n\t_match_id = match_.match_id\n\t\n\tvar match_info_text: String = _get_match_info_text(match_)\n\tvar player_count_text: String = _get_player_count_text(match_)\n\t\n\t_match_info_label.clear()\n\t_match_info_label.append_text(match_info_text)\n\t_player_count_label.clear()\n\t_player_count_label.append_text(player_count_text)\n\n\nfunc get_match_id() -> String:\n\treturn _match_id\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_match_label_dict(match_: NakamaAPI.ApiMatch) -> Dictionary:\n\tvar label_string: String = match_.label\n\n\tvar parse_result = JSON.parse_string(label_string)\n\tvar parse_failed: bool = parse_result == null\n\tif parse_failed:\n\t\treturn {}\n\n\tvar label_dict: Dictionary = parse_result\n\n\treturn label_dict\n\n\nfunc _get_match_info_text(match_: NakamaAPI.ApiMatch) -> String:\n\tvar label_dict: Dictionary = _get_match_label_dict(match_)\n\n\tif label_dict.is_empty():\n\t\treturn \"\"\n\n\tvar match_config: MatchConfig = MatchConfig.convert_from_dict(label_dict)\n\n\tvar host_display_name: String = label_dict.get(\"host_display_name\", \"UNKNOWN\")\n\thost_display_name = SanitizeText.sanitize_player_name(host_display_name)\n\n\tvar difficulty: Difficulty.enm = match_config.get_difficulty()\n\tvar difficulty_string: String = Difficulty.convert_to_colored_string(difficulty)\n\tvar game_length: int = match_config.get_game_length()\n\tvar game_length_string: String = str(game_length)\n\tvar game_mode: GameMode.enm = match_config.get_game_mode()\n\tvar game_mode_string: String = GameMode.convert_to_long_display_string(game_mode)\n\tvar team_mode: TeamMode.enm = match_config.get_team_mode()\n\tvar team_mode_string: String = TeamMode.convert_to_display_string(team_mode)\n\n\tvar text: String = \"\" \\\n\t+ \"%s\\n\" % difficulty_string \\\n\t+ tr(\"MATCH_CARD_WAVE_COUNT\").format({WAVE_COUNT = game_length_string}) + \"\\n\" \\\n\t+ \"%s %s\\n\" % [game_mode_string, team_mode_string] \\\n\t+ \" \\n\" \\\n\t+ \"[color=ROYAL_BLUE]%s[/color]\" % tr(\"MATCH_CARD_CREATOR\").format({CREATOR_NAME = host_display_name}) \\\n\t+ \"\"\n\n\treturn text\n\n\nfunc _get_player_count_text(match_: NakamaAPI.ApiMatch) -> String:\n\tvar label_dict: Dictionary = _get_match_label_dict(match_)\n\n\tif label_dict.is_empty():\n\t\treturn \"\"\n\n\tvar match_config: MatchConfig = MatchConfig.convert_from_dict(label_dict)\n\tvar team_mode: TeamMode.enm = match_config.get_team_mode()\n\tvar player_count_max: int = TeamMode.get_player_count_max(team_mode)\n\n\tvar player_count: int = match_.size\n\tvar text: String = \"%d/%d\" % [player_count, player_count_max]\n\t\n\treturn text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_join_button_pressed():\n\tjoin_pressed.emit()\n\n\n#########################\n###       Static      ###\n#########################\n\nstatic func make() -> MatchCard:\n\tvar scene: PackedScene = preload(\"res://src/ui/title_screen/online/match_card.tscn\")\n\tvar card: MatchCard = scene.instantiate()\n\t\n\treturn card\n"
  },
  {
    "path": "src/ui/title_screen/online/match_card.tscn",
    "content": "[gd_scene load_steps=4 format=3 uid=\"uid://d27if5hnovvmj\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/online/match_card.gd\" id=\"1_4ej3x\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_pd78y\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_w73c3\"]\ncontent_margin_left = 8.0\ncontent_margin_top = 8.0\ncontent_margin_right = 8.0\ncontent_margin_bottom = 8.0\nbg_color = Color(0.0823529, 0.0823529, 0.129412, 0.392157)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.533333, 0.533333, 0.533333, 1)\ncorner_radius_top_left = 5\ncorner_radius_top_right = 5\ncorner_radius_bottom_right = 5\ncorner_radius_bottom_left = 5\n\n[node name=\"MatchCard\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_match_info_label\", \"_player_count_label\")]\ncustom_minimum_size = Vector2(500, 140)\ntheme = ExtResource(\"1_pd78y\")\ntheme_type_variation = &\"RightSidePanel\"\ntheme_override_styles/panel = SubResource(\"StyleBoxFlat_w73c3\")\nscript = ExtResource(\"1_4ej3x\")\n_match_info_label = NodePath(\"HBoxContainer/MatchInfoLabel\")\n_player_count_label = NodePath(\"HBoxContainer/VBoxContainer/PlayerCountLabel\")\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"MatchInfoLabel\" type=\"RichTextLabel\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nbbcode_enabled = true\ntext = \"Normal\n120 waves\nRandom with upgrades\n \n[color=ROYAL_BLUE]Host: kevl[/color]\"\nfit_content = true\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"PlayerCountLabel\" type=\"RichTextLabel\" parent=\"HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 6\nbbcode_enabled = true\ntext = \"[center]1/2[/center]\"\nfit_content = true\n\n[node name=\"JoinButton\" type=\"Button\" parent=\"HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 4\nfocus_mode = 0\ntext = \"Join\"\n\n[connection signal=\"pressed\" from=\"HBoxContainer/VBoxContainer/JoinButton\" to=\".\" method=\"_on_join_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/online/online_lobby_menu.gd",
    "content": "class_name OnlineLobbyMenu extends PanelContainer\n\n\n# Menu for an online match lobby, which is shown before\n# starting the match. Displays connected players.\n\n\nsignal start_pressed()\nsignal leave_pressed()\n\n\n@export var _player_list: ItemList\n@export var _match_config_label: RichTextLabel\n@export var _start_button: Button\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_start_button_visible(value: bool):\n\t_start_button.visible = value\n\n\n# NOTE: skips presences without display names yet\nfunc set_presences(presence_list: Array, host_user_id: String):\n\t_player_list.clear()\n\n\tfor e in presence_list:\n\t\tvar presence: NakamaRTAPI.UserPresence = e\n\t\tvar user_id: String = presence.user_id\n\t\tvar display_name: String = NakamaConnection.get_display_name_of_user(user_id)\n\n\t\tif display_name.is_empty():\n\t\t\tcontinue\n\n\t\tvar user_is_host: bool = user_id == host_user_id\n\n\t\tvar item_text: String = display_name\n\n\t\tif user_is_host:\n\t\t\titem_text += \" %s\" % tr(\"LOBBY_HOST_INDICATOR\")\n\n\t\t_player_list.add_item(item_text)\n\t\t\n\t\tvar new_item_index: int = _player_list.get_item_count() - 1\n\t\t_player_list.set_item_metadata(new_item_index, user_id)\n\t\t_player_list.set_item_selectable(new_item_index, false)\n\n\nfunc display_match_config(match_config: MatchConfig):\n\tvar match_config_string: String = match_config.get_display_string_rich()\n\t\n\t_match_config_label.clear()\n\t_match_config_label.append_text(match_config_string)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_leave_button_pressed():\n\tleave_pressed.emit()\n\n\nfunc _on_start_button_pressed():\n\tstart_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/online/online_lobby_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dkxudlev66vnr\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/online/online_lobby_menu.gd\" id=\"1_gou4l\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_sgqs1\"]\n\n[node name=\"OnlineLobbyMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_player_list\", \"_match_config_label\", \"_start_button\")]\ntheme = ExtResource(\"1_sgqs1\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"1_gou4l\")\n_player_list = NodePath(\"VBoxContainer/PlayerList\")\n_match_config_label = NodePath(\"VBoxContainer/MatchConfigLabel\")\n_start_button = NodePath(\"VBoxContainer/HBoxContainer/StartButton\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"Header\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Match Lobby\"\nhorizontal_alignment = 1\n\n[node name=\"MatchConfigLabel\" type=\"RichTextLabel\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nfit_content = true\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntext = \"Connected players:\"\n\n[node name=\"PlayerList\" type=\"ItemList\" parent=\"VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 200)\nlayout_mode = 2\nallow_search = false\nauto_height = true\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"LeaveButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Leave\"\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"StartButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Start\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/LeaveButton\" to=\".\" method=\"_on_leave_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/StartButton\" to=\".\" method=\"_on_start_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/online/online_match_list_menu.gd",
    "content": "@tool\nclass_name OnlineMatchListMenu extends PanelContainer\n\n\n# Displays a list of online matches.\n\n\nenum State {\n\tSEARCHING,\n\tNO_MATCHES_FOUND,\n\tSHOW_MATCHES,\n\tFAILED_TO_CONNECT,\n}\n\n\nsignal join_pressed(match_id: int)\nsignal refresh_pressed()\nsignal cancel_pressed()\nsignal create_match_pressed()\nsignal lan_pressed()\n\n\n# NOTE: currently a max of 50 matches are supported\nconst MATCH_CARD_COUNT_MAX: int = 50\n\n@export var _searching_label: Label\n@export var _no_matches_found_label: Label\n@export var _failed_to_connect_label: Label\n@export var _match_card_grid: GridContainer\n@export var _create_match_button: Button\n@export var _refresh_button: Button\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tfor i in range(0, MATCH_CARD_COUNT_MAX):\n#\t\tvar match_id: String = match_.match_id\n\t\tvar match_card: MatchCard = MatchCard.make()\n\t\tmatch_card.join_pressed.connect(_on_match_card_join_pressed.bind(match_card))\n\t\t_match_card_grid.add_child(match_card)\n\t\tmatch_card.hide()\n\t\n\tif Engine.is_editor_hint():\n\t\t_searching_label.hide()\n\t\t\n\t\tvar card_list: Array = _match_card_grid.get_children()\n\t\tfor card in card_list:\n\t\t\tcard.show()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_state(new_state: OnlineMatchListMenu.State):\n\t_searching_label.visible = new_state == OnlineMatchListMenu.State.SEARCHING\n\t_no_matches_found_label.visible = new_state == OnlineMatchListMenu.State.NO_MATCHES_FOUND\n\t_failed_to_connect_label.visible = new_state == OnlineMatchListMenu.State.FAILED_TO_CONNECT\n\t_refresh_button.disabled = !(new_state == OnlineMatchListMenu.State.SHOW_MATCHES || new_state == OnlineMatchListMenu.State.NO_MATCHES_FOUND)\n\t_create_match_button.disabled = !(new_state == OnlineMatchListMenu.State.SHOW_MATCHES || new_state == OnlineMatchListMenu.State.NO_MATCHES_FOUND)\n\n\tif new_state == State.SEARCHING || new_state == State.NO_MATCHES_FOUND:\n\t\tclear_match_list()\n\n\nfunc clear_match_list():\n\tvar card_list: Array = _match_card_grid.get_children()\n\t\n\tfor card in card_list:\n\t\tcard.hide()\n\n\nfunc update_match_list(match_list: Array):\n\tvar found_matches: bool = !match_list.is_empty()\n\n\t_match_card_grid.visible = found_matches\n\t\n\tvar card_list: Array = _match_card_grid.get_children()\n\n\tvar free_match_card_list: Array = card_list.duplicate()\n\n#\tLoad match data into match card UI\n\tfor match_ in match_list:\n\t\tvar out_of_match_cards: bool = free_match_card_list.is_empty()\n\t\tif out_of_match_cards:\n\t\t\tbreak\n\n\t\tvar match_is_valid: bool = _check_match_is_valid(match_)\n\t\tif !match_is_valid:\n\t\t\tcontinue\n\n\t\tvar match_card: MatchCard = free_match_card_list.pop_front()\n\t\tmatch_card.load_match(match_)\n\t\tmatch_card.show()\n\n#\tHide unused match cards\n\tfor match_card in free_match_card_list:\n\t\tmatch_card.hide()\n\n\tvar visible_match_count: int = _get_visible_match_count()\n\tvar matches_found: bool = visible_match_count > 0\n\t\n\tif matches_found:\n\t\tset_state(State.SHOW_MATCHES)\n\telse:\n\t\tset_state(State.NO_MATCHES_FOUND)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_visible_match_count() -> int:\n\tvar count: int = 0\n\t\n\tvar card_list: Array = _match_card_grid.get_children()\n\tfor match_card in card_list:\n\t\tif match_card.visible:\n\t\t\tcount += 1\n\n\treturn count\n\n\nfunc _check_match_is_valid(match_: NakamaAPI.ApiMatch) -> bool:\n\tvar label_string: String = match_.label\n\tvar parse_result = JSON.parse_string(label_string)\n\tvar parse_failed: bool = parse_result == null\n\tif parse_failed:\n\t\treturn false\n\n\tvar match_label: Dictionary = parse_result\n\n\tvar match_game_version: String = match_label.get(\"game_version\", \"UNKNOWN\")\n\tvar local_game_version: String = Config.build_version()\n\tvar match_game_version_is_same: bool = match_game_version == local_game_version\n\tif !match_game_version_is_same:\n\t\tprint_verbose(\"Found invalid match. Match has incompatible version.\")\n\n\t\treturn false\n\t\n\tvar player_count: int = match_label.get(\"player_count\", 0)\n\tvar match_has_0_players: bool = player_count == 0\n\tif match_has_0_players:\n\t\tprint_verbose(\"Found invalid match. Match has 0 players.\")\n\n\t\treturn false\n\t\n\treturn true\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_match_card_join_pressed(match_card: MatchCard):\n\tvar match_id: String = match_card.get_match_id()\n\tjoin_pressed.emit(match_id)\n\n\nfunc _on_cancel_button_pressed():\n\tcancel_pressed.emit()\n\n\nfunc _on_create_match_button_pressed():\n\tcreate_match_pressed.emit()\n\n\nfunc _on_refresh_button_pressed():\n\trefresh_pressed.emit()\n\n\nfunc _on_lan_button_pressed() -> void:\n\tlan_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/online/online_match_list_menu.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://csg2abpgju1ay\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_0djlm\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/online/online_match_list_menu.gd\" id=\"2_inhau\"]\n\n[node name=\"OnlineMatchListMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_searching_label\", \"_no_matches_found_label\", \"_failed_to_connect_label\", \"_match_card_grid\", \"_create_match_button\", \"_refresh_button\")]\ncustom_minimum_size = Vector2(1122, 600)\ntheme = ExtResource(\"1_0djlm\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"2_inhau\")\n_searching_label = NodePath(\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/MarginContainer/SearchingLabel\")\n_no_matches_found_label = NodePath(\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/MarginContainer/NoMatchesFoundLabel\")\n_failed_to_connect_label = NodePath(\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/MarginContainer/FailedToConnectLabel\")\n_match_card_grid = NodePath(\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/ScrollContainer/MatchCardGrid\")\n_create_match_button = NodePath(\"VBoxContainer/HBoxContainer/CreateMatchButton\")\n_refresh_button = NodePath(\"VBoxContainer/HBoxContainer/RefreshButton\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"Online Matches\"\nhorizontal_alignment = 1\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\ntheme = ExtResource(\"1_0djlm\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"VBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 4\n\n[node name=\"SearchingLabel\" type=\"Label\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/MarginContainer\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"LabelTitle\"\ntext = \"Searching for matches...\"\n\n[node name=\"NoMatchesFoundLabel\" type=\"Label\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/MarginContainer\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"LabelTitle\"\ntext = \"No matches found\"\n\n[node name=\"FailedToConnectLabel\" type=\"Label\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/MarginContainer\"]\nvisible = false\nlayout_mode = 2\ntheme_type_variation = &\"LabelTitle\"\ntext = \"Failed to connect to server\"\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer\"]\ncustom_minimum_size = Vector2(0, 600)\nlayout_mode = 2\nsize_flags_vertical = 3\nhorizontal_scroll_mode = 0\n\n[node name=\"MatchCardGrid\" type=\"GridContainer\" parent=\"VBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/ScrollContainer\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 10\ntheme_override_constants/v_separation = 10\ncolumns = 2\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"CreateMatchButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nfocus_mode = 0\ntext = \"Create match\"\n\n[node name=\"RefreshButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"Refresh\"\n\n[node name=\"LANButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"LAN Multiplayer\"\n\n[node name=\"Spacer\" type=\"HBoxContainer\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"CancelButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nfocus_mode = 0\ntext = \"Cancel\"\n\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CreateMatchButton\" to=\".\" method=\"_on_create_match_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/RefreshButton\" to=\".\" method=\"_on_refresh_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/LANButton\" to=\".\" method=\"_on_lan_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer/CancelButton\" to=\".\" method=\"_on_cancel_button_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/online/setup_online_game.gd",
    "content": "class_name SetupOnlineGame extends Node\n\n\nenum State {\n\tIDLE,\n\tLOBBY,\n\tTRANSFER_FROM_LOBBY,\n}\n\n\nenum NakamaOpCode {\n\tTRANSFER_FROM_LOBBY = 1,\n}\n\nconst TIMEOUT_FOR_TRANSFER_FROM_LOBBY: float = 2.0\n\n\nvar _current_match_config: MatchConfig = null\nvar _lobby_match_id: String = \"\"\nvar _is_host: bool = false\nvar _state: State = State.IDLE\nvar _presence_map: Dictionary = {}\nvar _presence_order_list: Array = []\nvar _expected_player_count: int = -1\nvar _host_user_id: String = \"\"\n\n@export var _title_screen: TitleScreen\n@export var _online_match_list_menu: OnlineMatchListMenu\n@export var _online_lobby_menu: OnlineLobbyMenu\n@export var _create_online_match_menu: CreateOnlineMatchMenu\n@export var _connecting_to_server_indicator: Control\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n#\tNOTE: need to manually call the callback here in case\n#\tnakama is already connected. This happens when player\n#\tquits from match back to title screen.\n\tNakamaConnection.state_changed.connect(_on_nakama_connection_state_changed)\n\t_on_nakama_connection_state_changed()\n\n\tOnlineMatch.error.connect(_on_webrtc_error)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_online_lobby_menu_presences():\n\tvar presence_list: Array = []\n\n\tfor user_id in _presence_order_list:\n\t\tvar presence: NakamaRTAPI.UserPresence = _presence_map[user_id]\n\t\tpresence_list.append(presence)\n\n\t_online_lobby_menu.set_presences(presence_list, _host_user_id)\n\n\nfunc _refresh_match_list():\n\t_online_match_list_menu.set_state(OnlineMatchListMenu.State.SEARCHING)\n\t\n\tvar client: NakamaClient = NakamaConnection.get_client()\n\tvar session: NakamaSession = NakamaConnection.get_session()\n\n\tvar min_players: int = 0\n\tvar max_players: int = 10\n\tvar limit: int = 10\n\tvar authoritative: bool = true\n\tvar label: String = \"\"\n\tvar query: String = \"\"\n\tvar list_matches_result: NakamaAPI.ApiMatchList = await client.list_matches_async(session, min_players, max_players, limit, authoritative, label, query)\n\n\tif list_matches_result.is_exception():\n\t\tpush_error(\"Error in list_matches_async(): %s\" % list_matches_result)\n\t\t\n\t\treturn\n\n# \tNOTE: add artificial delay to prevent UI feeling abrupt\n# \tand also as a way to throttle requests a bit.\n\tawait get_tree().create_timer(0.5).timeout\n\t\n\tvar match_list: Array = list_matches_result.matches\n\t_online_match_list_menu.update_match_list(match_list)\n\n\nfunc _get_match_config_from_label(match_label: String) -> MatchConfig:\n\tvar label_dict: Dictionary = JSON.parse_string(match_label)\n\tvar match_config: MatchConfig = MatchConfig.convert_from_dict(label_dict)\n\t\n\treturn match_config\n\n\n#########################\n###      Private      ###\n#########################\n\n# Delay opening multiplayer menu until client is connected\n# to server.\nfunc _switch_to_match_list_when_connected():\n\t_connecting_to_server_indicator.show()\n\n#\tNOTE: add an extra delay to avoid too quick UI\n#\tswitching, otherwise it looks bad\n\tawait NakamaConnection.state_changed\n\tawait get_tree().create_timer(0.3).timeout\n\t\n\t_connecting_to_server_indicator.hide()\n\t\n\tvar connection_state: NakamaConnection.State = NakamaConnection.get_state()\n\t\n#\tNOTE: need to switch to online match list even if failed\n#\tto connect so that LAN multiplayer remains accessible\n#\twhen game can't connect to online server.\n\t_title_screen.switch_to_tab(TitleScreen.Tab.ONLINE_MATCH_LIST)\n\t\n\tvar connected_ok: bool = connection_state == NakamaConnection.State.CONNECTED\n\n\tif connected_ok:\n\t\t_refresh_match_list()\n\telse:\n\t\t_online_match_list_menu.set_state(OnlineMatchListMenu.State.FAILED_TO_CONNECT)\n\n\nfunc _get_host_user_id_for_match(match_: NakamaRTAPI.Match) -> String:\n\tvar label_string: String = match_.label\n\n\tvar parse_result = JSON.parse_string(label_string)\n\tvar parse_failed: bool = parse_result == null\n\tif parse_failed:\n\t\treturn \"\"\n\n\tvar label_dict: Dictionary = parse_result\n\tvar host_user_id: String = label_dict.get(\"host_user_id\", \"\")\n\n\treturn host_user_id\n\n\nfunc _save_presences(presence_list: Array):\n\tfor presence in presence_list:\n\t\t_presence_map[presence.user_id] = presence\n\n\t\tif !_presence_order_list.has(presence.user_id):\n\t\t\t_presence_order_list.append(presence.user_id)\n\n#\tRequest display names of new joiners from server\n\tvar user_id_list: Array = []\n\tfor presence in presence_list:\n\t\tvar user_id: String = presence.user_id\n\t\tuser_id_list.append(user_id)\n\n\tvar client: NakamaClient = NakamaConnection.get_client()\n\tvar session: NakamaSession = NakamaConnection.get_session()\n\n\tvar get_users_async_result: NakamaAsyncResult = await client.get_users_async(session, user_id_list)\n\n\tif get_users_async_result.is_exception():\n\t\tpush_error(\"Error in get_users_async_result rpc(): %s\" % get_users_async_result)\n\n\t\treturn\n\n\tvar api_users: NakamaAPI.ApiUsers = get_users_async_result as NakamaAPI.ApiUsers\n\n\tfor user in api_users.users:\n\t\tvar user_id: String = user.id\n\t\tvar display_name: String = user.display_name\n\n\t\tNakamaConnection.set_display_name_of_user(user_id, display_name)\n\n#\tNOTE: update online lobby again to show player names\n\t_update_online_lobby_menu_presences()\n\n\nfunc _process_nakama_message_transfer_from_lobby(message: NakamaRTAPI.MatchData):\n\tif _is_host:\n\t\treturn\n\n\tprint_verbose(\"Received signal from host about transferring from lobby match to game match\")\n\t\n\t_title_screen.switch_to_tab(TitleScreen.Tab.LOADING)\n\t\n\tvar state_data: Dictionary = JSON.parse_string(message.data)\n\tvar game_match_id: String = state_data.get(\"match_id\", \"\")\n\n\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\tvar leave_match_result: NakamaAsyncResult = await socket.leave_match_async(_lobby_match_id)\n\tif leave_match_result.is_exception():\n\t\tpush_error(\"Error in leave_match_async rpc(): %s\" % leave_match_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s.\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_TRANSFER_FROM_LOBBY\"), leave_match_result.exception.message])\n\n\t\treturn\n\n\t_lobby_match_id = \"\"\n\n#\tNOTE: clear presence map which contains presences\n#\tcollected for lobby. We're entering the real game match\n#\tnow so need to re-obtain presences.\n\t_presence_map.clear()\n\t_presence_order_list.clear()\n\n\tOnlineMatch.join_match(socket, game_match_id)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_webrtc_error(message: String):\n\tpush_error(\"webrtc error: %s\" % message)\n\n\nfunc _on_nakama_connection_state_changed():\n\tvar connection_state: NakamaConnection.State = NakamaConnection.get_state()\n\n\tif connection_state == NakamaConnection.State.CONNECTED:\n\t\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\t\tsocket.received_match_presence.connect(_on_nakama_received_match_presence)\n\t\tsocket.received_match_state.connect(_on_nakama_received_match_state)\n\n\nfunc _on_online_match_list_menu_create_match_pressed():\n\t_title_screen.switch_to_tab(TitleScreen.Tab.CREATE_ONLINE_MATCH)\n\n\nfunc _on_create_online_match_menu_create_pressed():\n\t_current_match_config = _create_online_match_menu.get_match_config()\n\n\tvar match_config_dict: Dictionary = _current_match_config.convert_to_dict()\n\tvar host_display_name: String = Settings.get_setting(Settings.PLAYER_NAME)\n\tvar creation_time: float = Time.get_unix_time_from_system()\n\tvar game_version: String = Config.build_version()\n\tvar team_mode: TeamMode.enm = _current_match_config.get_team_mode()\n\tvar player_count_max: int = TeamMode.get_player_count_max(team_mode)\n\t\t\n\tvar local_user_id: String = NakamaConnection.get_local_user_id()\n\n\tvar match_params_dict: Dictionary = {\n\t\t\"host_display_name\": host_display_name,\n\t\t\"host_user_id\": local_user_id,\n\t\t\"player_count_max\": player_count_max,\n\t\t\"is_private\": false,\n\t\t\"creation_time\": creation_time,\n\t\t\"game_version\": game_version,\n\t}\n\tmatch_params_dict.merge(match_config_dict)\n\n\tvar match_params_string: String = JSON.stringify(match_params_dict)\n\tvar client: NakamaClient = NakamaConnection.get_client()\n\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\tvar session: NakamaSession = NakamaConnection.get_session()\n\tvar create_match_result: NakamaAsyncResult = await client.rpc_async(session, \"create_match\", match_params_string)\n\tif create_match_result.is_exception():\n\t\tpush_error(\"Error in create_match rpc(): %s\" % create_match_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_CREATE_MATCH\"), create_match_result.exception.message])\n\n\t\treturn\n\t\n\tvar result_payload: Dictionary = JSON.parse_string(create_match_result.payload)\n\tvar lobby_match_id: String = result_payload[\"match_id\"]\n\t\n\tvar join_match_result: NakamaAsyncResult = await socket.join_match_async(lobby_match_id)\n\tif join_match_result.is_exception():\n\t\tpush_error(\"Error in join_match_async rpc(): %s\" % join_match_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_JOIN_MATCH\"), join_match_result.exception.message])\n\n\t\treturn\n\t\n\tvar lobby_match: NakamaRTAPI.Match = join_match_result\n\t_save_presences(lobby_match.presences)\n\t_save_presences([lobby_match.self_user])\n\t\n\t_lobby_match_id = lobby_match_id\n\t_state = State.LOBBY\n\n\t_host_user_id = _get_host_user_id_for_match(lobby_match)\n\n\t_is_host = true\n\t\n\t_title_screen.switch_to_tab(TitleScreen.Tab.ONLINE_LOBBY)\n\t_update_online_lobby_menu_presences()\n\t_online_lobby_menu.set_start_button_visible(true)\n\t_online_lobby_menu.display_match_config(_current_match_config)\n\n\nfunc _on_nakama_received_match_presence(presence_event: NakamaRTAPI.MatchPresenceEvent):\n\tfor presence in presence_event.leaves:\n\t\t_presence_map.erase(presence.user_id)\n\t\t_presence_order_list.erase(presence.user_id)\n\n\t_save_presences(presence_event.joins)\n\n\tif _online_lobby_menu.visible:\n\t\t_update_online_lobby_menu_presences()\n\n\nfunc _on_nakama_received_match_state(message: NakamaRTAPI.MatchData):\n\tvar op_code: int = message.op_code\n\t\n\tmatch op_code:\n\t\tNakamaOpCode.TRANSFER_FROM_LOBBY: _process_nakama_message_transfer_from_lobby(message)\n\t\t_: pass\n\n\n\nfunc _on_online_match_list_menu_join_pressed(selected_match_id: String):\n\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\t\n\tvar join_match_result: NakamaAsyncResult = await socket.join_match_async(selected_match_id)\n\tif join_match_result.is_exception():\n\t\tpush_error(\"Error in join_match_async rpc(): %s\" % join_match_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_JOIN_MATCH\"), join_match_result.exception.message])\n\n\t\treturn\n\n\tvar lobby_match: NakamaRTAPI.Match = join_match_result\n\n\t_lobby_match_id = selected_match_id\n\n\t_host_user_id = _get_host_user_id_for_match(lobby_match)\n\n\t_save_presences(lobby_match.presences)\n\t_save_presences([lobby_match.self_user])\n\n\tvar match_label: String = lobby_match.label\n\tvar match_config = _get_match_config_from_label(match_label)\n\n#\tTODO: make it possible to recover from this error state\n\tif match_config == null:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"SETUP_ONLINE_ERROR_LOAD_MATCH_PROPS\"))\n\n\t\treturn\n\n\t_current_match_config = match_config\n\t_state = State.LOBBY\n\n\t_title_screen.switch_to_tab(TitleScreen.Tab.ONLINE_LOBBY)\n\t_update_online_lobby_menu_presences()\n#\tNOTE: hide start button if client is not host because only the host\n#\tshould be able to start the game\n\t_online_lobby_menu.set_start_button_visible(false)\n\t_online_lobby_menu.display_match_config(_current_match_config)\n\n\n\nfunc _on_online_lobby_menu_leave_pressed():\n\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\tvar leave_match_result: NakamaAsyncResult = await socket.leave_match_async(_lobby_match_id)\n\tif leave_match_result.is_exception():\n\t\tpush_error(\"Error in leave_match_async(): %s\" % leave_match_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_LEAVE_MATCH\"), leave_match_result.exception.message])\n\n\t\treturn\n\t\n\t_lobby_match_id = \"\"\n\t_state = State.IDLE\n\n\t_title_screen.switch_to_tab(TitleScreen.Tab.ONLINE_MATCH_LIST)\n\t_refresh_match_list()\n\n\n# NOTE: host doesn't leave the lobby match here, so that\n# host can send message to other peers to tell them to leave\n# the lobby match and go to game match.\nfunc _on_online_lobby_menu_start_pressed():\n\t_expected_player_count = _presence_map.size()\n\n\t_title_screen.switch_to_tab(TitleScreen.Tab.LOADING)\n\n\tOnlineMatch.match_created.connect(_on_host_created_game_match)\n\n#\tNOTE: Set leave_prev_match flag to false so that host\n#\tstays in lobby match. This is so that host can tell\n#\tpeers in lobby about new match id.\n\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\tvar leave_prev_match: bool = false\n\tOnlineMatch.create_match(socket, leave_prev_match)\n\n\nfunc _on_peer_connected(_peer_id: int):\n\tvar peer_id_list: Array = multiplayer.get_peers()\n\tvar peer_count: int = peer_id_list.size()\n# \tNOTE: need to add 1 to peer count to include local peer\n\tvar player_count: int = peer_count + 1\n\tvar all_players_connected: bool = player_count == _expected_player_count\n\n\tprint_verbose(\"New peer connected to game match. peer_count=%s, player_count=%s, all_players_connected=%s\" % [peer_count, player_count, all_players_connected])\n\n\tif all_players_connected:\n\t\tprint_verbose(\"All players connected to game match! Player count: %s. Starting the game.\" % player_count)\n\n#\t\tNOTE: wait a bit just in case (is this really\n#\t\tneeded?)\n\t\tawait get_tree().create_timer(1.0).timeout\n\t\t\n\t\tvar difficulty: Difficulty.enm = _current_match_config.get_difficulty()\n\t\tvar game_length: int = _current_match_config.get_game_length()\n\t\tvar game_mode: GameMode.enm = _current_match_config.get_game_mode()\n\t\tvar team_mode: TeamMode.enm = _current_match_config.get_team_mode()\n\t\tvar origin_seed: int = randi()\n\n\t\t_title_screen.start_game.rpc(PlayerMode.enm.MULTIPLAYER, game_length, game_mode, difficulty, team_mode, origin_seed, Globals.ConnectionType.NAKAMA)\n\n\nfunc _on_host_created_game_match(game_match_id: String):\n\tvar socket: NakamaSocket = NakamaConnection.get_socket()\n\t\n\tOnlineMatch.match_created.disconnect(_on_host_created_game_match)\n\tmultiplayer.multiplayer_peer.peer_connected.connect(_on_peer_connected)\n\n\tprint_verbose(\"Created game match with id %s.\" % game_match_id);\n\n\tvar data_dict: Dictionary = {\n\t\t\"match_id\": game_match_id,\n\t}\n\n\tvar data: String = JSON.stringify(data_dict)\n\tvar send_match_state_result: NakamaAsyncResult = await socket.send_match_state_async(_lobby_match_id, NakamaOpCode.TRANSFER_FROM_LOBBY, data)\n\tif send_match_state_result.is_exception():\n\t\tpush_error(\"Error in send_match_state_async(): %s\" % send_match_state_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_COMMUNICATE_WITH_LOBBY\"), send_match_state_result.exception.message])\n \n\t\treturn\n\n#\tHost sent the TRANSFER_FROM_LOBBY message so now it's\n#\tokay to leave the lobby match\n\tvar leave_match_result: NakamaAsyncResult = await socket.leave_match_async(_lobby_match_id)\n\tif leave_match_result.is_exception():\n\t\tpush_error(\"Error in leave_match_async rpc(): %s\" % leave_match_result)\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), \"%s\\n%s\" % [tr(\"SETUP_ONLINE_ERROR_TRANSFER_FROM_LOBBY\"), leave_match_result.exception.message])\n\n\t\treturn\n\t\n\t_lobby_match_id = \"\"\n\n\tif _expected_player_count == 1:\n\t\t_on_peer_connected(1)\n\n\nfunc _on_online_match_list_menu_refresh_pressed():\n\t_refresh_match_list()\n\n\nfunc _on_multiplayer_button_pressed():\n\tvar running_on_desktop: bool = OS.has_feature(\"pc\")\n\tif !running_on_desktop:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"SETUP_ONLINE_ERROR_IN_BROWSER\"))\n\t\n\t\treturn\n\t\n\tvar connection_state: NakamaConnection.State = NakamaConnection.get_state()\n\t\n\tmatch connection_state:\n\t\tNakamaConnection.State.CONNECTING:\n\t\t\t_switch_to_match_list_when_connected()\n\t\tNakamaConnection.State.CONNECTED:\n\t\t\t_title_screen.switch_to_tab(TitleScreen.Tab.ONLINE_MATCH_LIST)\n\t\t\t_refresh_match_list()\n\t\tNakamaConnection.State.FAILED_TO_CONNECT:\n#\t\t\tNOTE: if failed to connect previously, try again\n#\t\t\there\n\t\t\tNakamaConnection.connect_to_server()\n\t\t\t_switch_to_match_list_when_connected()\n"
  },
  {
    "path": "src/ui/title_screen/online/setup_online_game.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://bran1c08eptno\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/online/setup_online_game.gd\" id=\"1_alk5r\"]\n\n[node name=\"SetupOnlineGame\" type=\"Node\"]\nscript = ExtResource(\"1_alk5r\")\n"
  },
  {
    "path": "src/ui/title_screen/profile_menu.gd",
    "content": "extends PanelContainer\n\n\nsignal close_pressed()\nsignal missions_button_pressed()\n\n\nvar _setup_error_list: Array[String] = []\n\nvar _regex_allowed_chars: RegEx\n\n\n@export var _name_edit: LineEdit\n@export var _export_exp_menu: ExportExpMenu\n@export var _import_exp_menu: ImportExpMenu\n@export var _level_label: Label\n@export var _exp_label: Label\n@export var _exp_for_next_lvl_left_label: Label\n@export var _exp_for_next_lvl_label: Label\n@export var _wisdom_upgrade_menu: WisdomUpgradeMenu\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_regex_allowed_chars = RegEx.new()\n\t_regex_allowed_chars.compile(Constants.PLAYER_NAME_ALLOWED_CHARS)\n\n\tvar player_name: String = Settings.get_setting(Settings.PLAYER_NAME)\n\t_name_edit.text = player_name\n\t\n\tvar exp_password: String = Settings.get_setting(Settings.EXP_PASSWORD)\n\tvar player_exp: int = ExperiencePassword.decode(exp_password)\n\t\n\tvar player_exp_is_valid: bool = player_exp != -1\n\tif !player_exp_is_valid:\n\t\t_setup_error_list.append(tr(\"PROFILE_MENU_ERROR_LOAD_EXP\"))\n\t\t\n\t\tplayer_exp = 0\n\t\n\t_load_player_exp(player_exp)\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_player_name_for_nakama_account():\n\tvar client: NakamaClient = NakamaConnection.get_client()\n\tvar session: NakamaSession = NakamaConnection.get_session()\n\tvar username = null\n\tvar display_name: String = _name_edit.get_text()\n\tvar avatar_url = null\n\tvar lang_tag = null\n\tvar location = null\n\tvar timezone = null\n\tvar update_account_async_result: NakamaAsyncResult = await client.update_account_async(session, username, display_name, avatar_url, lang_tag, location, timezone)\n\n\tif update_account_async_result.is_exception():\n\t\tpush_error(\"Error in update_account_async(): %s\" % update_account_async_result)\n\t\t\n\t\treturn\n\n\nfunc _load_player_exp(player_exp: int):\n\t_exp_label.text = str(player_exp)\n\n\tvar player_level: int = PlayerExperience.get_level_at_exp(player_exp)\n\t_level_label.text = str(player_level)\n\t\n\tvar reached_max_level: bool = player_level == Constants.PLAYER_MAX_LEVEL\n\t\n\t_exp_for_next_lvl_left_label.visible = !reached_max_level\n\t_exp_for_next_lvl_label.visible = !reached_max_level\n\t\n\tif !reached_max_level:\n\t\tvar next_lvl: int = player_level + 1\n\t\tvar exp_for_next_lvl: int = PlayerExperience.get_exp_for_level(next_lvl)\n\t\t_exp_for_next_lvl_label.text = str(exp_for_next_lvl)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_name_edit_text_changed(new_text: String):\n\tvar old_caret_column: int = _name_edit.get_caret_column()\n\n\tvar regexed_text: String = \"\"\n\tfor valid_character in _regex_allowed_chars.search_all(new_text):\n\t\tregexed_text += valid_character.get_string()\n\t\n\t_name_edit.set_text(regexed_text)\n\n\t_name_edit.set_caret_column(old_caret_column)\n\n\n# NOTE: update display_name for account only when profile\n# menu is closed, not every time when name edit text\n# changes. This is to avoid too frequent updates.\nfunc _on_close_button_pressed():\n\tvar player_name: String = _name_edit.get_text()\n\n\tvar name_is_too_short: bool = player_name.length() < Constants.PLAYER_NAME_LENGTH_MIN\n\tif name_is_too_short:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"PROFILE_MENU_ERROR_NAME_TOO_SHORT\"))\n\n\t\treturn\n\n\tclose_pressed.emit()\n\n\tSettings.set_setting(Settings.PLAYER_NAME, player_name)\n\tSettings.flush()\n\n\tvar running_on_desktop: bool = OS.has_feature(\"pc\")\n\tvar connected_to_server: bool = NakamaConnection.get_state() == NakamaConnection.State.CONNECTED\n\tif running_on_desktop && connected_to_server:\n\t\t_update_player_name_for_nakama_account()\n\n\nfunc _on_import_exp_button_pressed():\n\t_import_exp_menu.show()\n\n\nfunc _on_export_exp_button_pressed():\n\tvar exp_password: String = Settings.get_setting(Settings.EXP_PASSWORD)\n\n#\tNOTE: if password in settings is empty, generate a\n#\tpassword for 0 exp so that there's something to show in\n#\texport menu.\n\tif exp_password.is_empty():\n\t\texp_password = ExperiencePassword.encode(0)\n\n\t_export_exp_menu.set_exp_password(exp_password)\n\t_export_exp_menu.show()\n\n\nfunc _on_import_exp_menu_import_pressed():\n\tvar exp_password: String = _import_exp_menu.get_exp_password()\n\tvar player_exp: int = ExperiencePassword.decode(exp_password)\n\n#\tNOTE: treat empty password as invalid to prevent player\n#\tfrom accidentally resetting exp to 0.\n\tvar player_level_is_valid: bool = player_exp != -1 && !exp_password.is_empty()\n\tif !player_level_is_valid:\n\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), tr(\"PROFILE_MENU_ERROR_EXP_PASSWORD_INVALID\"))\n\t\t\n\t\treturn\n\t\n\tSettings.set_setting(Settings.EXP_PASSWORD, exp_password)\n\tSettings.flush()\n\n\tvar success_message: String = tr(\"PROFILE_MENU_IMPORTED_EXP_PASSWORD\").format({EXPERIENCE = player_exp})\n\tUtils.show_popup_message(self, tr(\"GENERIC_SUCCESS_TITLE\"), success_message)\n\t_load_player_exp(player_exp)\n\n#\tNOTE: need to update wisdom upgrades because they depend\n#\ton player exp\n\t_wisdom_upgrade_menu.load_wisdom_upgrades_from_settings()\n\n\nfunc _on_visibility_changed():\n\tif visible:\n\t\t_wisdom_upgrade_menu.load_wisdom_upgrades_from_settings()\n\t\t\n\t\tif !_setup_error_list.is_empty():\n\t\t\tfor error in _setup_error_list:\n\t\t\t\tUtils.show_popup_message(self, tr(\"GENERIC_ERROR_TITLE\"), error)\n\n\t\t\t_setup_error_list.clear()\n\n\nfunc _on_missions_button_pressed() -> void:\n\tmissions_button_pressed.emit()\n"
  },
  {
    "path": "src/ui/title_screen/profile_menu.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://ch6cw5m8w8r7j\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_6uqqm\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/profile_menu.gd\" id=\"1_h7bqv\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://di1a1qyge5s3a\" path=\"res://src/ui/title_screen/wisdom_upgrade_menu.tscn\" id=\"2_gias8\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b3gh33xi2di32\" path=\"res://src/ui/title_screen/export_exp_menu.tscn\" id=\"2_son4h\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b3kgwa2iuucrh\" path=\"res://src/ui/title_screen/import_exp_menu.tscn\" id=\"3_8rg10\"]\n\n[node name=\"ProfileMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_name_edit\", \"_export_exp_menu\", \"_import_exp_menu\", \"_level_label\", \"_exp_label\", \"_exp_for_next_lvl_left_label\", \"_exp_for_next_lvl_label\", \"_wisdom_upgrade_menu\")]\ncustom_minimum_size = Vector2(600, 0)\ntheme = ExtResource(\"1_6uqqm\")\ntheme_type_variation = &\"MainPanelContainer\"\nscript = ExtResource(\"1_h7bqv\")\n_name_edit = NodePath(\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer/NameEdit\")\n_export_exp_menu = NodePath(\"ExportExpMenu\")\n_import_exp_menu = NodePath(\"ImportExpMenu\")\n_level_label = NodePath(\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer/LevelLabel\")\n_exp_label = NodePath(\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer/ExperienceLabel\")\n_exp_for_next_lvl_left_label = NodePath(\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer/ExpForNextLvlLeftLabel\")\n_exp_for_next_lvl_label = NodePath(\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer/ExpForNextLvlLabel\")\n_wisdom_upgrade_menu = NodePath(\"VBoxContainer/HBoxContainer3/WisdomUpgradeMenu\")\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntheme_type_variation = &\"LabelLarge\"\ntext = \"PROFILE_MENU_PROFILE\"\n\n[node name=\"HBoxContainer3\" type=\"HBoxContainer\" parent=\"VBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"VBoxContainer/HBoxContainer3\"]\nlayout_mode = 2\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 20\ntheme_override_constants/v_separation = 10\ncolumns = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"PROFILE_MENU_NAME\"\n\n[node name=\"NameEdit\" type=\"LineEdit\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_font_sizes/font_size = 35\ntext = \"Player\"\nmax_length = 15\ncontext_menu_enabled = false\ncaret_blink = true\n\n[node name=\"Label2\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"PROFILE_MENU_LEVEL\"\n\n[node name=\"LevelLabel\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"0\"\n\n[node name=\"Label4\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"PROFILE_MENU_EXPERIENCE\"\n\n[node name=\"ExperienceLabel\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"0\"\n\n[node name=\"ExpForNextLvlLeftLabel\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntext = \"PROFILE_MENU_FNL\"\n\n[node name=\"ExpForNextLvlLabel\" type=\"Label\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelLarge\"\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"12\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"HBoxContainer2\" type=\"HBoxContainer\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\n\n[node name=\"ExportExpButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer/HBoxContainer2\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"PROFILE_MENU_EXPORT\"\n\n[node name=\"ImportExpButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer/HBoxContainer2\"]\nlayout_mode = 2\nfocus_mode = 0\ntext = \"PROFILE_MENU_IMPORT\"\n\n[node name=\"MissionsButton\" type=\"Button\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nfocus_mode = 0\ntext = \"PROFILE_MENU_MISSIONS\"\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"VBoxContainer/HBoxContainer3/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"WisdomUpgradeMenu\" parent=\"VBoxContainer/HBoxContainer3\" instance=ExtResource(\"2_gias8\")]\nlayout_mode = 2\n\n[node name=\"CloseButton\" type=\"Button\" parent=\"VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\nfocus_mode = 0\ntext = \"CLOSE_BUTTON\"\n\n[node name=\"ExportExpMenu\" parent=\".\" instance=ExtResource(\"2_son4h\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"ImportExpMenu\" parent=\".\" instance=ExtResource(\"3_8rg10\")]\nvisible = false\nlayout_mode = 2\n\n[connection signal=\"visibility_changed\" from=\".\" to=\".\" method=\"_on_visibility_changed\"]\n[connection signal=\"text_changed\" from=\"VBoxContainer/HBoxContainer3/VBoxContainer/GridContainer/NameEdit\" to=\".\" method=\"_on_name_edit_text_changed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer/HBoxContainer2/ExportExpButton\" to=\".\" method=\"_on_export_exp_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer/HBoxContainer2/ImportExpButton\" to=\".\" method=\"_on_import_exp_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/HBoxContainer3/VBoxContainer/VBoxContainer/MissionsButton\" to=\".\" method=\"_on_missions_button_pressed\"]\n[connection signal=\"pressed\" from=\"VBoxContainer/CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n[connection signal=\"import_pressed\" from=\"ImportExpMenu\" to=\".\" method=\"_on_import_exp_menu_import_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/title_screen.gd",
    "content": "class_name TitleScreen extends Node\n\n# Main menu for the game. Opens when the game starts.\n\n\nenum Tab {\n\tMAIN,\n\tCONFIGURE_SINGLEPLAYER,\n\tONLINE_MATCH_LIST,\n\tLAN_CONNECT_MENU,\n\tCREATE_ONLINE_MATCH,\n\tCREATE_LAN_MATCH,\n\tONLINE_LOBBY,\n\tLAN_LOBBY,\n\tPROFILE,\n\tENCYCLOPEDIA,\n\tMISSIONS,\n\tSETTINGS,\n\tCREDITS,\n\tLOADING,\n}\n\n@export var _tab_container: TabContainer\n@export var _configure_singleplayer_menu: ConfigureSinglePlayerMenu\n@export var _spacer_before_quit_button: VBoxContainer\n@export var _quit_button: Button\n@export var _notification_panel: NotificationPanel\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tprint(\" \\n\")\n\tprint(\"The messages about Basis universal can be ignored: \\\"Basis universal cannot unpack level 1.\\\".\")\n\tprint(\" \\n\")\n\t\n#\tNOTE: show quit button only on pc platform because quit\n#\tfunction is not needed on web\n\t_quit_button.visible = OS.has_feature(\"pc\")\n\t_spacer_before_quit_button.visible = OS.has_feature(\"pc\")\n\t\n\tvar notification_list: Array[String] = Globals.get_title_screen_notification_list()\n\t\n\tif !notification_list.is_empty():\n\t\tvar notification_text: String = notification_list[0]\n\t\t\n\t\t_notification_panel.display_text(notification_text)\n\t\t_notification_panel.show()\n\t\t\n\t\tGlobals.clear_title_screen_notification_list()\n\t\t\n\n#########################\n###       Public      ###\n#########################\n\nfunc switch_to_tab(tab: TitleScreen.Tab):\n\t_tab_container.current_tab = tab\n\n\n# NOTE: this function transitions the game from title screen to game scene. Can be called either by client itself or the host if the game is in multiplayer mode.\n@rpc(\"any_peer\", \"call_local\", \"reliable\")\nfunc start_game(player_mode: PlayerMode.enm, wave_count: int, game_mode: GameMode.enm, difficulty: Difficulty.enm, team_mode: TeamMode.enm, origin_seed: int, connection_type: Globals.ConnectionType):\n#\tNOTE: save game settings into globals so that GameScene\n#\tcan access them\n\tGlobals._player_mode = player_mode\n\tGlobals._difficulty = difficulty\n\tGlobals._wave_count = wave_count\n\tGlobals._game_mode = game_mode\n\tGlobals._team_mode = team_mode\n\tGlobals._origin_seed = origin_seed\n\tGlobals._connection_type = connection_type\n\t\n#\tNOTE: need to add a delay so that the game properly\n#\tswitches to displaying LOADING tab before starting\n#\tchange_scene_to_packed()\n\t_tab_container.current_tab = Tab.LOADING\n\tawait get_tree().create_timer(0.1).timeout\n\t\n\tget_tree().change_scene_to_packed(Preloads.game_scene_scene)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_quit_button_pressed():\n\tget_tree().quit()\n\n\nfunc _on_singleplayer_button_pressed():\n\t_tab_container.current_tab = Tab.CONFIGURE_SINGLEPLAYER\n\n\nfunc _on_settings_button_pressed():\n\t_tab_container.current_tab = Tab.SETTINGS\n\n\nfunc _on_credits_button_pressed():\n\t_tab_container.current_tab = Tab.CREDITS\n\n\nfunc _on_configure_singleplayer_menu_start_button_pressed():\n\tvar difficulty: Difficulty.enm = _configure_singleplayer_menu.get_difficulty()\n\tvar game_length: int = _configure_singleplayer_menu.get_game_length()\n\tvar game_mode: GameMode.enm = _configure_singleplayer_menu.get_game_mode()\n\tvar team_mode: TeamMode.enm = TeamMode.enm.ONE_PLAYER_PER_TEAM\n\tvar origin_seed: int = randi()\n\n\tvar difficulty_string: String = Difficulty.convert_to_string(difficulty)\n\tvar game_mode_string: String = GameMode.convert_to_string(game_mode)\n\tSettings.set_setting(Settings.CACHED_GAME_DIFFICULTY, difficulty_string)\n\tSettings.set_setting(Settings.CACHED_GAME_MODE, game_mode_string)\n\tSettings.set_setting(Settings.CACHED_GAME_LENGTH, game_length)\n\tSettings.flush()\n\t\n\tstart_game(PlayerMode.enm.SINGLEPLAYER, game_length, game_mode, difficulty, team_mode, origin_seed, Globals.ConnectionType.ENET)\n\n\nfunc _on_generic_tab_cancel_pressed():\n\tswitch_to_tab(TitleScreen.Tab.MAIN)\n\n\nfunc _on_settings_menu_ok_pressed():\n\tswitch_to_tab(TitleScreen.Tab.MAIN)\n\n\nfunc _on_lan_lobby_menu_back_pressed():\n\t_tab_container.current_tab = Tab.LAN_CONNECT_MENU\n\n\nfunc _on_create_lan_match_menu_cancel_pressed():\n\t_tab_container.current_tab = Tab.LAN_CONNECT_MENU\n\n\nfunc _on_profile_button_pressed():\n\t_tab_container.current_tab = Tab.PROFILE\n\n\nfunc _on_profile_menu_close_pressed():\n\t_tab_container.current_tab = Tab.MAIN\n\n\nfunc _on_create_online_match_menu_cancel_pressed():\n\t_tab_container.current_tab = Tab.ONLINE_MATCH_LIST\n\n\nfunc _on_online_match_list_menu_lan_pressed() -> void:\n\t_tab_container.current_tab = Tab.LAN_CONNECT_MENU\n\n\nfunc _on_profile_menu_missions_button_pressed() -> void:\n\t_tab_container.current_tab = Tab.MISSIONS\n\n\nfunc _on_missions_menu_close_pressed() -> void:\n\t_tab_container.current_tab = Tab.PROFILE\n\n\nfunc _on_encyclopedia_button_pressed() -> void:\n\t_tab_container.current_tab = Tab.ENCYCLOPEDIA\n\n\nfunc _on_encyclopedia_menu_close_pressed() -> void:\n\tswitch_to_tab(TitleScreen.Tab.MAIN)\n"
  },
  {
    "path": "src/ui/title_screen/title_screen.tscn",
    "content": "[gd_scene load_steps=22 format=3 uid=\"uid://d12sm4nc5wwqt\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/title_screen.gd\" id=\"1_dx8oa\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cusqgcgg37fj7\" path=\"res://src/ui/title_screen/lan_match/setup_lan_game.tscn\" id=\"2_2qgi3\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_ec3wj\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bran1c08eptno\" path=\"res://src/ui/title_screen/online/setup_online_game.tscn\" id=\"3_mias5\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bpfx0lg44dqkv\" path=\"res://assets/misc/icob_ultra_wide.png\" id=\"3_uvrn4\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bx0xth6bthpon\" path=\"res://src/ui/game_menu/credits_menu.tscn\" id=\"4_rdxi7\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cnnkyqysqqyar\" path=\"res://src/ui/title_screen/lan_match/lan_connect_menu.tscn\" id=\"5_pc1mj\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cx86ea3loo8a2\" path=\"res://src/ui/game_menu/settings_menu.tscn\" id=\"5_q0hc3\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://eies0lnegrf6\" path=\"res://src/ui/title_screen/configure_singleplayer_menu.tscn\" id=\"6_nj3u5\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://d0m1fiwnsk3tf\" path=\"res://src/ui/title_screen/lan_match/create_lan_match_menu.tscn\" id=\"7_8vssb\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://csg2abpgju1ay\" path=\"res://src/ui/title_screen/online/online_match_list_menu.tscn\" id=\"7_ggn0o\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ch6cw5m8w8r7j\" path=\"res://src/ui/title_screen/profile_menu.tscn\" id=\"8_7qboh\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ddpf0wt3rp57k\" path=\"res://src/ui/title_screen/online/create_online_match_menu.tscn\" id=\"9_f0p2i\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dkxudlev66vnr\" path=\"res://src/ui/title_screen/online/online_lobby_menu.tscn\" id=\"11_b1t0j\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cecaq4wvkvxv3\" path=\"res://src/ui/title_screen/lan_match/lan_lobby_menu.tscn\" id=\"12_3m802\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dhvrqpk4snrok\" path=\"res://src/ui/title_screen/missions_menu/missions_menu.tscn\" id=\"14_5jj2m\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://i0b3uilwt2as\" path=\"res://src/ui/hud/build_version_label.tscn\" id=\"16_xve8p\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dm74dudt8aesd\" path=\"res://src/ui/title_screen/encyclopedia_menu.tscn\" id=\"17_7asif\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bvc2yim85t7vs\" path=\"res://src/ui/title_screen/notification_panel.tscn\" id=\"17_whg35\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://chegdechhho3d\" path=\"res://src/ui/title_screen/connecting_to_server_indicator.tscn\" id=\"18_5n8qn\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_vbfm6\"]\n\n[node name=\"TitleScreen\" type=\"Node\" node_paths=PackedStringArray(\"_tab_container\", \"_configure_singleplayer_menu\", \"_spacer_before_quit_button\", \"_quit_button\", \"_notification_panel\")]\nscript = ExtResource(\"1_dx8oa\")\n_tab_container = NodePath(\"UI/TabContainer\")\n_configure_singleplayer_menu = NodePath(\"UI/TabContainer/ConfigureSingleplayerMenu\")\n_spacer_before_quit_button = NodePath(\"UI/TabContainer/MainTab/VBoxContainer/Spacer\")\n_quit_button = NodePath(\"UI/TabContainer/MainTab/VBoxContainer/QuitButton\")\n_notification_panel = NodePath(\"UI/MarginContainer2/NotificationPanel\")\n\n[node name=\"SetupLanGame\" parent=\".\" node_paths=PackedStringArray(\"_title_screen\", \"_lan_connect_menu\", \"_lan_lobby_menu\", \"_create_lan_match_menu\") instance=ExtResource(\"2_2qgi3\")]\n_title_screen = NodePath(\"..\")\n_lan_connect_menu = NodePath(\"../UI/TabContainer/LanConnectMenu\")\n_lan_lobby_menu = NodePath(\"../UI/TabContainer/LanLobbyMenu\")\n_create_lan_match_menu = NodePath(\"../UI/TabContainer/CreateLanMatchMenu\")\n\n[node name=\"SetupOnlineGame\" parent=\".\" node_paths=PackedStringArray(\"_title_screen\", \"_online_match_list_menu\", \"_online_lobby_menu\", \"_create_online_match_menu\", \"_connecting_to_server_indicator\") instance=ExtResource(\"3_mias5\")]\n_title_screen = NodePath(\"..\")\n_online_match_list_menu = NodePath(\"../UI/TabContainer/OnlineMatchListMenu\")\n_online_lobby_menu = NodePath(\"../UI/TabContainer/OnlineLobbyMenu\")\n_create_online_match_menu = NodePath(\"../UI/TabContainer/CreateOnlineMatchMenu\")\n_connecting_to_server_indicator = NodePath(\"../UI/ConnectingToServerIndicator\")\n\n[node name=\"UI\" type=\"Control\" parent=\".\"]\nlayout_mode = 3\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme = ExtResource(\"2_ec3wj\")\n\n[node name=\"TextureRect\" type=\"TextureRect\" parent=\"UI\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntexture = ExtResource(\"3_uvrn4\")\nexpand_mode = 3\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\"UI\"]\nlayout_mode = 1\nanchors_preset = 8\nanchor_left = 0.5\nanchor_top = 0.5\nanchor_right = 0.5\nanchor_bottom = 0.5\noffset_left = -202.0\noffset_top = -210.0\noffset_right = 202.0\noffset_bottom = 210.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_vbfm6\")\ncurrent_tab = 0\ntabs_visible = false\n\n[node name=\"MainTab\" type=\"PanelContainer\" parent=\"UI/TabContainer\"]\nlayout_mode = 2\ntheme = ExtResource(\"2_ec3wj\")\ntheme_type_variation = &\"MainPanelContainer\"\nmetadata/_tab_index = 0\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"UI/TabContainer/MainTab\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"SingleplayerButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"SINGLEPLAYER_BUTTON\"\n\n[node name=\"MultiplayerButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"MULTIPLAYER_BUTTON\"\n\n[node name=\"ProfileButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"PROFILE_BUTTON\"\n\n[node name=\"EncyclopediaButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"ENCYCLOPEDIA_BUTTON\"\n\n[node name=\"SettingsButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"SETTINGS_BUTTON\"\n\n[node name=\"CreditsButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"CREDITS_BUTTON\"\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\ncustom_minimum_size = Vector2(0, 40)\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"QuitButton\" type=\"Button\" parent=\"UI/TabContainer/MainTab/VBoxContainer\"]\nlayout_mode = 2\nfocus_mode = 0\ntheme_type_variation = &\"ButtonLarge\"\ntext = \"QUIT_BUTTON\"\n\n[node name=\"ConfigureSingleplayerMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"6_nj3u5\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 1\n\n[node name=\"OnlineMatchListMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"7_ggn0o\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 2\n\n[node name=\"LanConnectMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"5_pc1mj\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 3\n\n[node name=\"CreateOnlineMatchMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"9_f0p2i\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 4\n\n[node name=\"CreateLanMatchMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"7_8vssb\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 5\n\n[node name=\"OnlineLobbyMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"11_b1t0j\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 6\n\n[node name=\"LanLobbyMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"12_3m802\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 7\n\n[node name=\"ProfileMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"8_7qboh\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 8\n\n[node name=\"EncyclopediaMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"17_7asif\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 9\n\n[node name=\"MissionsMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"14_5jj2m\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 10\n\n[node name=\"SettingsMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"5_q0hc3\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 11\n\n[node name=\"CreditsMenu\" parent=\"UI/TabContainer\" instance=ExtResource(\"4_rdxi7\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 12\n\n[node name=\"LoadingIndicator\" type=\"VBoxContainer\" parent=\"UI/TabContainer\"]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 13\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"UI/TabContainer/LoadingIndicator\"]\nlayout_mode = 2\nsize_flags_vertical = 6\ntheme = ExtResource(\"2_ec3wj\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"RichTextLabel\" type=\"RichTextLabel\" parent=\"UI/TabContainer/LoadingIndicator/PanelContainer\"]\nlayout_mode = 2\nbbcode_enabled = true\ntext = \"[center][font_size=60]LOADING[/font_size][/center]\"\nfit_content = true\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"UI\"]\nlayout_mode = 1\nanchors_preset = 2\nanchor_top = 1.0\nanchor_bottom = 1.0\noffset_top = -40.0\noffset_right = 245.0\ngrow_vertical = 0\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"BuildVersionLabel\" parent=\"UI/MarginContainer\" instance=ExtResource(\"16_xve8p\")]\nlayout_mode = 2\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"UI\"]\nlayout_mode = 1\nanchors_preset = 3\nanchor_left = 1.0\nanchor_top = 1.0\nanchor_right = 1.0\nanchor_bottom = 1.0\noffset_left = -40.0\noffset_top = -40.0\ngrow_horizontal = 0\ngrow_vertical = 0\ntheme_override_constants/margin_left = 20\ntheme_override_constants/margin_top = 20\ntheme_override_constants/margin_right = 20\ntheme_override_constants/margin_bottom = 20\n\n[node name=\"NotificationPanel\" parent=\"UI/MarginContainer2\" instance=ExtResource(\"17_whg35\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"UI\"]\nlayout_mode = 0\noffset_right = 4.0\noffset_bottom = 4.0\n\n[node name=\"ConnectingToServerIndicator\" parent=\"UI\" instance=ExtResource(\"18_5n8qn\")]\nvisible = false\nlayout_mode = 1\n\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/SingleplayerButton\" to=\".\" method=\"_on_singleplayer_button_pressed\"]\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/MultiplayerButton\" to=\"SetupOnlineGame\" method=\"_on_multiplayer_button_pressed\"]\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/ProfileButton\" to=\".\" method=\"_on_profile_button_pressed\"]\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/EncyclopediaButton\" to=\".\" method=\"_on_encyclopedia_button_pressed\"]\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/SettingsButton\" to=\".\" method=\"_on_settings_button_pressed\"]\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/CreditsButton\" to=\".\" method=\"_on_credits_button_pressed\"]\n[connection signal=\"pressed\" from=\"UI/TabContainer/MainTab/VBoxContainer/QuitButton\" to=\".\" method=\"_on_quit_button_pressed\"]\n[connection signal=\"cancel_pressed\" from=\"UI/TabContainer/ConfigureSingleplayerMenu\" to=\".\" method=\"_on_generic_tab_cancel_pressed\"]\n[connection signal=\"start_button_pressed\" from=\"UI/TabContainer/ConfigureSingleplayerMenu\" to=\".\" method=\"_on_configure_singleplayer_menu_start_button_pressed\"]\n[connection signal=\"cancel_pressed\" from=\"UI/TabContainer/OnlineMatchListMenu\" to=\".\" method=\"_on_generic_tab_cancel_pressed\"]\n[connection signal=\"create_match_pressed\" from=\"UI/TabContainer/OnlineMatchListMenu\" to=\"SetupOnlineGame\" method=\"_on_online_match_list_menu_create_match_pressed\"]\n[connection signal=\"join_pressed\" from=\"UI/TabContainer/OnlineMatchListMenu\" to=\"SetupOnlineGame\" method=\"_on_online_match_list_menu_join_pressed\"]\n[connection signal=\"lan_pressed\" from=\"UI/TabContainer/OnlineMatchListMenu\" to=\".\" method=\"_on_online_match_list_menu_lan_pressed\"]\n[connection signal=\"refresh_pressed\" from=\"UI/TabContainer/OnlineMatchListMenu\" to=\"SetupOnlineGame\" method=\"_on_online_match_list_menu_refresh_pressed\"]\n[connection signal=\"cancel_pressed\" from=\"UI/TabContainer/LanConnectMenu\" to=\".\" method=\"_on_generic_tab_cancel_pressed\"]\n[connection signal=\"create_pressed\" from=\"UI/TabContainer/LanConnectMenu\" to=\"SetupLanGame\" method=\"_on_lan_connect_menu_create_pressed\"]\n[connection signal=\"join_pressed\" from=\"UI/TabContainer/LanConnectMenu\" to=\"SetupLanGame\" method=\"_on_lan_connect_menu_join_pressed\"]\n[connection signal=\"cancel_pressed\" from=\"UI/TabContainer/CreateOnlineMatchMenu\" to=\".\" method=\"_on_create_online_match_menu_cancel_pressed\"]\n[connection signal=\"create_pressed\" from=\"UI/TabContainer/CreateOnlineMatchMenu\" to=\"SetupOnlineGame\" method=\"_on_create_online_match_menu_create_pressed\"]\n[connection signal=\"cancel_pressed\" from=\"UI/TabContainer/CreateLanMatchMenu\" to=\".\" method=\"_on_create_lan_match_menu_cancel_pressed\"]\n[connection signal=\"create_pressed\" from=\"UI/TabContainer/CreateLanMatchMenu\" to=\"SetupLanGame\" method=\"_on_create_lan_match_menu_create_pressed\"]\n[connection signal=\"leave_pressed\" from=\"UI/TabContainer/OnlineLobbyMenu\" to=\"SetupOnlineGame\" method=\"_on_online_lobby_menu_leave_pressed\"]\n[connection signal=\"start_pressed\" from=\"UI/TabContainer/OnlineLobbyMenu\" to=\"SetupOnlineGame\" method=\"_on_online_lobby_menu_start_pressed\"]\n[connection signal=\"back_pressed\" from=\"UI/TabContainer/LanLobbyMenu\" to=\".\" method=\"_on_lan_lobby_menu_back_pressed\"]\n[connection signal=\"back_pressed\" from=\"UI/TabContainer/LanLobbyMenu\" to=\"SetupLanGame\" method=\"_on_lan_lobby_menu_back_pressed\"]\n[connection signal=\"start_pressed\" from=\"UI/TabContainer/LanLobbyMenu\" to=\"SetupLanGame\" method=\"_on_lan_lobby_menu_start_pressed\"]\n[connection signal=\"close_pressed\" from=\"UI/TabContainer/ProfileMenu\" to=\".\" method=\"_on_profile_menu_close_pressed\"]\n[connection signal=\"missions_button_pressed\" from=\"UI/TabContainer/ProfileMenu\" to=\".\" method=\"_on_profile_menu_missions_button_pressed\"]\n[connection signal=\"close_pressed\" from=\"UI/TabContainer/EncyclopediaMenu\" to=\".\" method=\"_on_encyclopedia_menu_close_pressed\"]\n[connection signal=\"close_pressed\" from=\"UI/TabContainer/MissionsMenu\" to=\".\" method=\"_on_missions_menu_close_pressed\"]\n[connection signal=\"cancel_pressed\" from=\"UI/TabContainer/SettingsMenu\" to=\".\" method=\"_on_generic_tab_cancel_pressed\"]\n[connection signal=\"ok_pressed\" from=\"UI/TabContainer/SettingsMenu\" to=\".\" method=\"_on_settings_menu_ok_pressed\"]\n[connection signal=\"close_pressed\" from=\"UI/TabContainer/CreditsMenu\" to=\".\" method=\"_on_generic_tab_cancel_pressed\"]\n"
  },
  {
    "path": "src/ui/title_screen/wisdom_upgrade_menu.gd",
    "content": "class_name WisdomUpgradeMenu extends PanelContainer\n\n\n# Menu where player can choose keeper of wisdom upgrades.\n\n\n@export var _button_container: GridContainer\n@export var _available_label: Label\n@export var _next_upgrade_unlock_label: RichTextLabel\n@export var _wisdom_effectiveness_bonus_label: Label\n@export var _wisdom_effectiveness_container: HBoxContainer\n\nvar _upgrade_available_count: int\nvar _upgrades_cached: Dictionary = {}\nvar _button_map: Dictionary = {}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n# \tNOTE: upgrades cache may be invalid if player manually\n# \tmodifies settings file or if player chooses a builder\n# \twhich modifies max upgrades and old cached values don't\n# \tfit.\n\tvar upgrade_id_list: Array = WisdomUpgradeProperties.get_id_list()\n\n\tfor upgrade_id in upgrade_id_list:\n\t\tvar button: WisdomUpgradeButton = WisdomUpgradeButton.make(upgrade_id)\n\t\t_button_container.add_child(button)\n\t\t\n\t\tbutton.pressed.connect(_on_button_pressed.bind(button, upgrade_id))\n\t\t\n\t\t_button_map[upgrade_id] = button\n\n\tSettings.changed.connect(_on_settings_changed)\n\t_on_settings_changed()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc load_wisdom_upgrades_from_settings():\n\tvar player_level: int = Utils.get_local_player_level()\n\t_upgrade_available_count = Utils.get_wisdom_upgrade_count_for_player_level(player_level)\n\t_upgrades_cached = _load_wisdom_upgrade_state(_upgrade_available_count)\n\n\tvar upgrade_id_list: Array = WisdomUpgradeProperties.get_id_list()\n\tfor upgrade_id in upgrade_id_list:\n\t\tvar button: WisdomUpgradeButton = _button_map[upgrade_id]\n\t\tvar upgrade_is_enabled: bool = _upgrades_cached[upgrade_id]\n\t\tbutton.set_upgrade_used_status(upgrade_is_enabled)\n\t\n\tvar next_unlock_level: int = _get_next_upgrade_unlock_level()\n\tvar next_unlock_level_exists: bool = next_unlock_level != -1\n\t_next_upgrade_unlock_label.visible = next_unlock_level_exists\n\t_next_upgrade_unlock_label.clear()\n\tif next_unlock_level_exists:\n\t\t_next_upgrade_unlock_label.append_text(tr(\"WISDOM_UPGRADES_UNLOCK_LABEL\") + \"[color=GOLD]%d[/color].\" % next_unlock_level)\n\n\t_update_available_label()\n\t_update_wisdom_effectiveness_label()\n\n\n#########################\n###      Private      ###\n#########################\n\n# Find next unlock level by finding a level at which the\n# upgrade count doesn't equal to current upgrade count.\nfunc _get_next_upgrade_unlock_level() -> int:\n\tvar current_player_level: int = Utils.get_local_player_level()\n\n\tvar upgrade_id_list: Array = WisdomUpgradeProperties.get_id_list()\n\tvar upgrade_available_count_max: int = upgrade_id_list.size()\n\tvar unlocked_all_upgrades: bool = _upgrade_available_count == upgrade_available_count_max\n\n\tif unlocked_all_upgrades:\n\t\treturn -1\n\t\n\tvar current_upgrade_count: int = Utils.get_wisdom_upgrade_count_for_player_level(current_player_level)\n\n\tvar next_unlock_level: int = -1\n\n\tfor level in range(current_player_level, Constants.PLAYER_MAX_LEVEL):\n\t\tvar this_upgrade_count: int = Utils.get_wisdom_upgrade_count_for_player_level(level)\n\t\tvar new_upgrade_unlocks_at_this_level: bool = this_upgrade_count != current_upgrade_count\n\t\t\n\t\tif new_upgrade_unlocks_at_this_level:\n\t\t\tnext_unlock_level = level\n\t\t\t\n\t\t\tbreak\n\n\treturn next_unlock_level\n\n\nfunc _load_wisdom_upgrade_state(upgrade_available_count: int) -> Dictionary:\n\tvar result: Dictionary = Settings.get_wisdom_upgrades()\n\n\tvar used_count: int = _get_used_upgrade_count(result)\n\tvar used_more_upgrades_than_available: bool = used_count > upgrade_available_count\n\tif used_more_upgrades_than_available:\n\t\tpush_warning(\"Wisdom upgrade cache is invalid! Resetting upgrades. Invalid cache = %s\" % result)\n\t\t\n\t\tfor key in result.keys():\n\t\t\tresult[key] = false\n\n\treturn result\n\n\nfunc _get_used_upgrade_count(upgrade_state: Dictionary) -> int:\n\tvar upgrade_id_list: Array = WisdomUpgradeProperties.get_id_list()\n\tvar used_count: int = 0\n\n\tfor upgrade_id in upgrade_id_list:\n\t\tvar upgrade_is_used: bool = upgrade_state[upgrade_id]\n\t\t\n\t\tif upgrade_is_used:\n\t\t\tused_count += 1\n\n\treturn used_count\n\n\nfunc _update_available_label():\n\tvar used_count: int = _get_used_upgrade_count(_upgrades_cached)\n\tvar available_count: int = _upgrade_available_count - used_count\n\t_available_label.text = str(available_count)\n\n\nfunc _update_wisdom_effectiveness_label():\n\tvar upgrades_wisdom_multiplier_bonus: float = Utils.get_wisdom_multiplier_bonus_from_upgrades(_upgrades_cached)\n\tvar wisdom_multiplier_bonus_exists: bool = upgrades_wisdom_multiplier_bonus != 0\n\t_wisdom_effectiveness_container.visible = wisdom_multiplier_bonus_exists\n\tif wisdom_multiplier_bonus_exists:\n\t\t_wisdom_effectiveness_bonus_label.text = \"%s%%\" % Utils.format_float((1+upgrades_wisdom_multiplier_bonus) * 100, 1)\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_button_pressed(button: WisdomUpgradeButton, upgrade_id: int):\n\tvar current_state: bool = _upgrades_cached[upgrade_id]\n\tvar new_state: bool = !current_state\n\tvar used_count: int = _get_used_upgrade_count(_upgrades_cached)\n\tvar will_increase_used: bool = new_state == true\n\tvar can_increase_used: bool = used_count < _upgrade_available_count\n\t\n\tif will_increase_used && !can_increase_used:\n\t\treturn\n\t\n\t_upgrades_cached[upgrade_id] = new_state\n\tbutton.set_upgrade_used_status(new_state)\n\t\n\t_update_available_label()\n\t_update_wisdom_effectiveness_label()\n\n\tSettings.set_setting(Settings.WISDOM_UPGRADES_CACHED, _upgrades_cached)\n\tSettings.flush()\n\n\n# Hide plus mode upgrades when plus mode is disabled\nfunc _on_settings_changed():\n\tvar plus_mode_is_enabled: bool = Settings.get_bool_setting(Settings.ENABLE_PLUS_MODE)\n\tvar plus_mode_upgrade_list: Array = WisdomUpgradeProperties.get_plus_mode_upgrade_list()\n\n\tfor upgrade in plus_mode_upgrade_list:\n\t\tvar button: Button = _button_map[upgrade]\n\t\tbutton.visible = plus_mode_is_enabled\t\t\n"
  },
  {
    "path": "src/ui/title_screen/wisdom_upgrade_menu.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://di1a1qyge5s3a\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/title_screen/wisdom_upgrade_menu.gd\" id=\"1_s5krx\"]\n\n[node name=\"WisdomUpgradeMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_button_container\", \"_available_label\", \"_next_upgrade_unlock_label\", \"_wisdom_effectiveness_bonus_label\", \"_wisdom_effectiveness_container\")]\noffset_right = 294.0\noffset_bottom = 126.0\nscript = ExtResource(\"1_s5krx\")\n_button_container = NodePath(\"MarginContainer/VBoxContainer/ButtonContainer\")\n_available_label = NodePath(\"MarginContainer/VBoxContainer/HBoxContainer/AvailableLabel\")\n_next_upgrade_unlock_label = NodePath(\"MarginContainer/VBoxContainer/NextUpgradeUnlockLabel\")\n_wisdom_effectiveness_bonus_label = NodePath(\"MarginContainer/VBoxContainer/WisdomEffectivenessHBoxContainer/WisdomEffectivenessBonusLabel\")\n_wisdom_effectiveness_container = NodePath(\"MarginContainer/VBoxContainer/WisdomEffectivenessHBoxContainer\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 5\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntheme_type_variation = &\"LabelLarge\"\ntext = \"WISDOM_UPGRADES_HEAD\"\n\n[node name=\"NextUpgradeUnlockLabel\" type=\"RichTextLabel\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntext = \"(placeholder) Next upgrade slot will unlock at level X.\"\nfit_content = true\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\n\n[node name=\"Label2\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"WISDOM_UPGRADES_AVAILABLE\"\n\n[node name=\"AvailableLabel\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"123\"\n\n[node name=\"WisdomEffectivenessHBoxContainer\" type=\"HBoxContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 8\n\n[node name=\"Label3\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/WisdomEffectivenessHBoxContainer\"]\nlayout_mode = 2\ntext = \"WISDOM_EFFECTIVENESS_BONUS\"\n\n[node name=\"WisdomEffectivenessBonusLabel\" type=\"Label\" parent=\"MarginContainer/VBoxContainer/WisdomEffectivenessHBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"123\"\n\n[node name=\"ButtonContainer\" type=\"GridContainer\" parent=\"MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 4\n"
  },
  {
    "path": "src/ui/top_left_menu/game_stats.gd",
    "content": "class_name GameStats extends VBoxContainer\n\n\n@export var _settings_label: RichTextLabel\n\n@export var _builder_label: Label\n\n@export var _stats_label: RichTextLabel\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar wave_count: int = Globals.get_wave_count()\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar difficulty: Difficulty.enm = Globals.get_difficulty()\n\tvar team_mode: TeamMode.enm = Globals.get_team_mode()\n\tvar match_config_string: String = MatchConfig.convert_configs_to_string(wave_count, game_mode, difficulty, team_mode)\n\n\t_settings_label.text = match_config_string\n\n\nfunc _process(_delta: float):\n\tvar player_stats_text: String = _get_player_stats_text()\n\tvar your_best_towers_text: String = _get_your_best_towers_text()\n\tvar overall_best_towers_text: String = _get_overall_best_towers_text()\n\n\t_stats_label.clear()\n\t_stats_label.append_text(player_stats_text)\n\t_stats_label.append_text(\" \\n\")\n\t_stats_label.append_text(\"[color=GOLD]%s[/color]\\n\" % tr(\"GAME_STATS_YOUR_BEST_TOWERS\"))\n\t_stats_label.append_text(your_best_towers_text)\n\t\n\tif Globals.get_player_mode() == PlayerMode.enm.MULTIPLAYER:\n\t\t_stats_label.append_text(\"\\n\")\n\t\t_stats_label.append_text(\"[color=GOLD]%s[/color]\\n\" % tr(\"GAME_STATS_OVERALL_BEST_TOWERS\"))\n\t\t_stats_label.append_text(overall_best_towers_text)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\tlocal_player.selected_builder.connect(_on_local_player_selected_builder)\n\n\nfunc _get_player_stats_text() -> String:\n\tvar player_list: Array[Player] = PlayerManager.get_player_list()\n\n\tvar text: String = \"\"\n\n\ttext += \"[table=7]\"\n\ttext += \"[cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell]\" % [tr(\"GAME_STATS_COLUMN_NAME\"), tr(\"GAME_STATS_COLUMN_TEAM\"), tr(\"GAME_STATS_COLUMN_SCORE\"), tr(\"GAME_STATS_COLUMN_LIVES\"), tr(\"GAME_STATS_COLUMN_LEVEL\"), tr(\"GAME_STATS_COLUMN_TOTAL_DAMAGE\"), tr(\"GAME_STATS_COLUMN_GOLD\")]\n\n\tplayer_list.sort_custom(\n\t\tfunc(a, b) -> bool:\n\t\t\tvar id_a: int = a.get_id()\n\t\t\tvar id_b: int = b.get_id()\n\t\t\t\n\t\t\treturn id_a < id_b\n\t)\n\n\tfor player in player_list:\n\t\tvar player_name: String = player.get_player_name_with_color()\n\n\t\tvar team: Team = player.get_team()\n\t\tvar team_id: int = team.get_id()\n\t\tvar team_string: String = \"%s %d\" % [tr(\"GAME_STATS_COLUMN_TEAM\"), team_id]\n\n\t\tvar score: float = player.get_score()\n\t\tvar score_string: String = TowerDetails.int_format(floori(score))\n\n\t\tvar lives_string: String = player.get_team().get_lives_string()\n\n\t\tvar wave_level: float = player.get_team().get_level()\n\t\tvar wave_level_string: String = str(wave_level)\n\n\t\tvar total_damage: float = player.get_total_damage()\n\t\tvar total_damage_string: String = TowerDetails.int_format(total_damage)\n\n\t\tvar gold: int = floori(player.get_gold())\n\t\tvar gold_string: String = TowerDetails.int_format(gold)\n\t\t\n\t\ttext += \"[cell]%s[/cell][cell]%s[/cell][cell]%s[/cell][cell]%s[/cell][cell]%s[/cell][cell]%s[/cell][cell]%s[/cell]\" % [player_name, team_string, score_string, lives_string, wave_level_string, total_damage_string, gold_string]\n\n\ttext += \"[/table]\\n\"\n\n\treturn text\n\n\nfunc _get_your_best_towers_text() -> String:\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\t\n\ttower_list = tower_list.filter(\n\t\tfunc(tower: Tower) -> bool:\n\t\t\tvar player_match: bool = tower.belongs_to_local_player()\n\n\t\t\treturn player_match\n\t)\n\t\n\tvar text: String = _get_tower_stats_text_generic(tower_list)\n\t\n\treturn text\n\n\nfunc _get_overall_best_towers_text() -> String:\n\tvar tower_list: Array[Tower] = Utils.get_tower_list()\n\tvar text: String = _get_tower_stats_text_generic(tower_list)\n\t\n\treturn text\n\n\nfunc _get_tower_stats_text_generic(tower_list: Array[Tower]) -> String:\n\tvar most_damage_tower: Tower = _get_most_total_damage_tower(tower_list)\n\tvar most_damage_tower_name: String = _get_colored_name_for_tower(most_damage_tower)\n\tvar most_damage_value: String = \"\"\n\tif most_damage_tower != null:\n\t\tvar most_damage: float = most_damage_tower.get_total_damage()\n\t\tmost_damage_value = TowerDetails.int_format(most_damage)\n\n\tvar tower_with_best_hit: Tower = _get_best_hit_tower(tower_list)\n\tvar best_hit_tower_name: String = _get_colored_name_for_tower(tower_with_best_hit)\n\tvar best_hit_value: String = \"\"\n\tif tower_with_best_hit != null:\n\t\tvar best_hit: float = tower_with_best_hit.get_best_hit()\n\t\tbest_hit_value = TowerDetails.int_format(best_hit)\n\n\tvar most_exp_tower: Tower = _get_most_exp_tower(tower_list)\n\tvar most_exp_tower_name: String = _get_colored_name_for_tower(most_exp_tower)\n\tvar most_exp_value: String = \"\"\n\tif most_exp_tower != null:\n\t\tvar most_exp: float = most_exp_tower.get_exp()\n\t\tmost_exp_value = TowerDetails.int_format(most_exp)\n\n\tvar most_kills_tower: Tower = _get_most_kills_tower(tower_list)\n\tvar most_kills_tower_name: String = _get_colored_name_for_tower(most_kills_tower)\n\tvar most_kills_value: String = \"\"\n\tif most_kills_tower != null:\n\t\tvar most_kills: float = most_kills_tower.get_kills()\n\t\tmost_kills_value = TowerDetails.int_format(most_kills)\n\t\n\tvar text: String = \"\"\n\ttext += \"[table=3]\"\n\ttext += \"[cell]%s[/cell][cell]%s[/cell][cell]%s[/cell]\" % [tr(\"GAME_STATS_MOST_DAMAGE\"), most_damage_tower_name, most_damage_value]\n\ttext += \"[cell]%s[/cell][cell]%s[/cell]\\t\\t[cell]%s[/cell]\" % [tr(\"GAME_STATS_BEST_HIT\"), best_hit_tower_name, best_hit_value]\n\ttext += \"[cell]%s[/cell][cell]%s[/cell]\\t\\t[cell]%s[/cell]\" % [tr(\"GAME_STATS_MOST_EXP\"), most_exp_tower_name, most_exp_value]\n\ttext += \"[cell]%s[/cell][cell]%s[/cell]\\t\\t[cell]%s[/cell]\" % [tr(\"GAME_STATS_MOST_KILLS\"), most_kills_tower_name, most_kills_value]\n\ttext += \"[/table]\"\n\n\treturn text\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _get_most_total_damage_tower(tower_list: Array[Tower]) -> Tower:\n\tvar best_tower: Tower = _get_best_tower_by_criteria(tower_list,\n\t\tfunc(a: Tower, b: Tower) -> bool:\n\t\t\treturn a.get_total_damage() > b.get_total_damage()\n\t\t\t)\n\n\treturn best_tower\n\n\nfunc _get_best_hit_tower(tower_list: Array[Tower]) -> Tower:\n\tvar best_tower: Tower = _get_best_tower_by_criteria(tower_list,\n\t\tfunc(a: Tower, b: Tower) -> bool:\n\t\t\treturn a.get_best_hit() > b.get_best_hit()\n\t\t\t)\n\n\treturn best_tower\n\n\nfunc _get_most_exp_tower(tower_list: Array[Tower]) -> Tower:\n\tvar best_tower: Tower = _get_best_tower_by_criteria(tower_list,\n\t\tfunc(a: Tower, b: Tower) -> bool:\n\t\t\treturn a.get_exp() > b.get_exp()\n\t\t\t)\n\n\treturn best_tower\n\n\nfunc _get_most_kills_tower(tower_list: Array[Tower]) -> Tower:\n\tvar best_tower: Tower = _get_best_tower_by_criteria(tower_list,\n\t\tfunc(a: Tower, b: Tower) -> bool:\n\t\t\treturn a.get_kills() > b.get_kills()\n\t\t\t)\n\n\treturn best_tower\n\n\nfunc _get_best_tower_by_criteria(tower_list: Array[Tower], criteria_callable: Callable) -> Tower:\n\tvar best_tower: Tower = null\n\n\tfor tower in tower_list:\n\t\tif best_tower == null:\n\t\t\tbest_tower = tower\n\t\t\tcontinue\n\n\t\tvar this_tower_is_better: bool = criteria_callable.call(tower, best_tower)\n\n\t\tif this_tower_is_better:\n\t\t\tbest_tower = tower\n\n\treturn best_tower\n\n\nfunc _get_colored_name_for_tower(tower: Tower) -> String:\n\tif tower == null:\n\t\treturn \"\"\n\n\tvar tower_name: String = tower.get_display_name()\n\tvar element: Element.enm = tower.get_element()\n\tvar element_color: Color = Element.get_color(element)\n\tvar colored_name: String = Utils.get_colored_string(tower_name, element_color)\n\n\treturn colored_name\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_local_player_selected_builder():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar builder: Builder = local_player.get_builder()\n\tvar builder_id: int = builder.get_id()\n\tvar builder_name: String = BuilderProperties.get_display_name(builder_id)\n\tvar builder_description: String = BuilderProperties.get_description(builder_id)\n\t\n\t_builder_label.text = builder_name\n\t_builder_label.tooltip_text = builder_description\n"
  },
  {
    "path": "src/ui/top_left_menu/game_stats.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://jm3vhrboca8b\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_fcvcc\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/top_left_menu/game_stats.gd\" id=\"2_yyjiq\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/label_with_rich_tooltip.gd\" id=\"3_r8spy\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://213bkal0uk32\" path=\"res://src/ui/top_left_menu/plus_mode_label.tscn\" id=\"3_ylxqo\"]\n\n[node name=\"GameStats\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_settings_label\", \"_builder_label\", \"_stats_label\")]\noffset_right = 621.0\noffset_bottom = 348.0\nsize_flags_horizontal = 0\nsize_flags_vertical = 2\ntheme = ExtResource(\"1_fcvcc\")\nscript = ExtResource(\"2_yyjiq\")\n_settings_label = NodePath(\"HBoxContainer/SettingsLabel\")\n_builder_label = NodePath(\"GridContainer/BuilderLabel\")\n_stats_label = NodePath(\"StatsLabel\")\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"SettingsLabel\" type=\"RichTextLabel\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 2\ntheme_override_constants/table_h_separation = 20\nbbcode_enabled = true\ntext = \"[color=GOLD]Neverending[/color], [color=GOLD]Build[/color], [color=4169e1ff]Beginner[/color]\"\nfit_content = true\nautowrap_mode = 0\n\n[node name=\"PlusModeLabel\" parent=\"HBoxContainer\" instance=ExtResource(\"3_ylxqo\")]\nlayout_mode = 2\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 10\ncolumns = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"GridContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"GAME_STATUS_BUILDER\"\n\n[node name=\"BuilderLabel\" type=\"Label\" parent=\"GridContainer\"]\nlayout_mode = 2\nmouse_filter = 0\ntext = \"Farseer\"\nscript = ExtResource(\"3_r8spy\")\n\n[node name=\"StatsLabel\" type=\"RichTextLabel\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/table_h_separation = 20\ntext = \"stats go here\"\nfit_content = true\nscroll_active = false\nautowrap_mode = 0\n\n[node name=\"Spacer\" type=\"VBoxContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n"
  },
  {
    "path": "src/ui/top_left_menu/plus_mode_label.gd",
    "content": "extends Label\n\n\nfunc _ready() -> void:\n\tvar plus_mode_is_enabled: bool = Settings.get_bool_setting(Settings.ENABLE_PLUS_MODE)\n\tvisible = plus_mode_is_enabled\n"
  },
  {
    "path": "src/ui/top_left_menu/plus_mode_label.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://213bkal0uk32\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/top_left_menu/plus_mode_label.gd\" id=\"1_yrotg\"]\n\n[node name=\"PlusModeLabel\" type=\"Label\"]\ntext = \"PLUS_MODE\"\nscript = ExtResource(\"1_yrotg\")\n"
  },
  {
    "path": "src/ui/top_left_menu/top_left_menu.gd",
    "content": "class_name TopLeftMenu extends PanelContainer\n\n\n@export var _wave_status: WaveStatus\n@export var _game_stats: GameStats\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\t_wave_status.connect_to_local_player(local_player)\n\t_game_stats.connect_to_local_player(local_player)\n\n\nfunc set_game_start_timer(timer: ManualTimer):\n\t_wave_status.set_game_start_timer(timer)\n"
  },
  {
    "path": "src/ui/top_left_menu/top_left_menu.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://b3grhp7bp5t54\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_fewds\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/top_left_menu/top_left_menu.gd\" id=\"2_j6xl1\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://4tcjyre0hoji\" path=\"res://src/ui/top_left_menu/wave_status.tscn\" id=\"3_8qtkf\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://jm3vhrboca8b\" path=\"res://src/ui/top_left_menu/game_stats.tscn\" id=\"4_8lyyh\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_hwtay\"]\n\n[node name=\"TopLeftMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_wave_status\", \"_game_stats\")]\ntheme = ExtResource(\"1_fewds\")\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_hwtay\")\nscript = ExtResource(\"2_j6xl1\")\n_wave_status = NodePath(\"TabContainer/TOP_LEFT_MENU_WAVE\")\n_game_stats = NodePath(\"TabContainer/TOP_LEFT_MENU_GAME\")\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\".\"]\nself_modulate = Color(1, 1, 1, 0.705882)\ncustom_minimum_size = Vector2(640, 250)\nlayout_mode = 2\ncurrent_tab = 0\ntab_focus_mode = 0\n\n[node name=\"TOP_LEFT_MENU_WAVE\" parent=\"TabContainer\" instance=ExtResource(\"3_8qtkf\")]\nlayout_mode = 2\nmetadata/_tab_index = 0\n\n[node name=\"TOP_LEFT_MENU_GAME\" parent=\"TabContainer\" instance=ExtResource(\"4_8lyyh\")]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 1\n"
  },
  {
    "path": "src/ui/top_left_menu/wave_status.gd",
    "content": "class_name WaveStatus extends VBoxContainer\n\n\n# Displays next wave level how much time is left before it\n# starts.\n\n\n@export var _label: RichTextLabel\n@export var _start_game_button: Button\n@export var _start_next_wave_button: Button\n@export var _level_label: Label\n@export var _game_start_time_container: HBoxContainer\n@export var _game_start_time_label: Label\n@export var _next_wave_time_container: HBoxContainer\n@export var _next_wave_time_label: Label\n@export var _score_label: Label\n@export var _game_time_label: Label\n@export var _total_damage_label: Label\n@export var _gold_farmed_label: Label\n\nvar _armor_hint_map: Dictionary\nvar _game_start_timer: ManualTimer = null\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_armor_hint_map = _generate_armor_hints()\n\n#\tNOTE: remove placeholder text, will be replaced by real\n#\ttext\n\t_show_wave_list([])\n\n\nfunc _process(_delta: float):\n\tvar local_player: Player = PlayerManager.get_local_player()\n\n\tif local_player == null:\n\t\treturn\n\n\tvar local_team: Team = local_player.get_team()\n\tvar next_wave_timer: ManualTimer = local_team.get_next_wave_timer()\n\tvar next_wave_time_string: String = _get_time_string(next_wave_timer)\n\t_next_wave_time_container.visible = !next_wave_timer.is_stopped()\n\t_next_wave_time_label.text = next_wave_time_string\n\n\tvar game_start_time_string: String = _get_time_string(_game_start_timer)\n\t_game_start_time_container.visible = !_game_start_timer.is_stopped()\n\t_game_start_time_label.text = game_start_time_string\n\n\tvar gold_farmed: float = local_player.get_gold_farmed()\n\tvar gold_farmed_string: String = TowerDetails.int_format(floori(gold_farmed))\n\t_gold_farmed_label.text = gold_farmed_string\n\n\tvar level: int = local_player.get_team().get_level()\n\t_level_label.text = str(level)\n\t\n\tvar total_damage: float = local_player.get_total_damage()\n\tvar total_damage_string: String = TowerDetails.int_format(floori(total_damage))\n\t_total_damage_label.text = total_damage_string\n\t\n\tvar score: float = local_player.get_score()\n\tvar score_string: String = TowerDetails.int_format(floori(score))\n\t_score_label.text = score_string\n\t\n\tvar game_time: float = Utils.get_time()\n\tvar game_time_string: String = Utils.convert_time_to_string(game_time)\n\t_game_time_label.text = game_time_string\n\n\n#########################\n###      Public       ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\tvar local_team: Team = local_player.get_team()\n\tlocal_team.level_changed.connect(_on_wave_level_changed)\n\tlocal_team.started_first_wave.connect(_on_started_first_wave)\n\t_on_wave_level_changed()\n\n\tlocal_player.generated_waves.connect(_on_local_player_generated_waves)\n\n\nfunc set_game_start_timer(timer: ManualTimer):\n\t_game_start_timer = timer\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_wave_details():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar wave_list: Array[Wave] = local_player.get_next_5_waves()\n\t_show_wave_list(wave_list)\n\n\nfunc _show_wave_list(wave_list: Array[Wave]):\n\t_label.clear()\n\t\n\tvar text: String = \"\"\n\n\ttext += \"[table=5]\"\n\n\ttext += \"[cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell][cell][color=GOLD]%s[/color][/cell]\" % [tr(\"WAVE_STATUS_COLUMN_LEVEL\"), tr(\"WAVE_STATUS_COLUMN_SIZE\"), tr(\"WAVE_STATUS_COLUMN_RACE\"), tr(\"WAVE_STATUS_COLUMN_ARMOR\"), tr(\"WAVE_STATUS_COLUMN_SPECIAL\")]\n\n\tfor wave in wave_list:\n\t\tvar level: int = wave.get_level()\n\t\tvar race: CreepCategory.enm = wave.get_race()\n\t\tvar race_string: String = CreepCategory.convert_to_colored_string(race)\n\n\t\tif race == CreepCategory.enm.CHALLENGE:\n\t\t\trace_string = \"---\"\n\n\t\tvar size_string: String = wave.get_creep_combination_string()\n\n\t\tvar armor_type: ArmorType.enm = wave.get_armor_type()\n\t\tvar armor_hint: String = _armor_hint_map[armor_type]\n\t\tvar armor_string: String = ArmorType.convert_to_colored_string(armor_type)\n\n\t\tvar specials_description: String = _get_specials_description(wave)\n\t\tvar specials_string: String = _get_specials_string_short(wave)\n\n\t\t# Escape BBCode in hint parameters to prevent parsing issues\n\t\tvar armor_hint_escaped: String = Utils.escape_bbcode(armor_hint)\n\t\tvar specials_description_escaped: String = Utils.escape_bbcode(specials_description)\n\n\t\ttext += \"[cell]%d[/cell][cell]%s[/cell][cell]%s[/cell][cell][hint=%s]%s[/hint][/cell][cell][hint=%s]%s[/hint][/cell]\" % [level, size_string, race_string, armor_hint_escaped, armor_string, specials_description_escaped, specials_string]\n\t\n\ttext += \"[/table]\"\n\n\t_label.append_text(text)\n\n\nfunc _get_specials_description(wave: Wave) -> String:\n\tvar special_list: Array[int] = wave.get_specials()\n\tvar string_list: Array[String] = []\n\n\tfor special in special_list:\n\t\tvar special_name: String = WaveSpecialProperties.get_special_name(special)\n\t\tvar special_description: String = WaveSpecialProperties.get_description(special)\n\t\tvar line: String = \"%s - %s\" % [special_name, special_description]\n\t\tstring_list.append(line)\n\n\tvar specials_string: String = \"\\n\".join(string_list)\n\n\treturn specials_string\n\n\nfunc _get_specials_string_short(wave: Wave) -> String:\n\tvar special_list: Array[int] = wave.get_specials()\n\tvar string_list: Array[String] = []\n\n\tfor special in special_list:\n\t\tvar string: String = WaveSpecialProperties.get_short_name(special)\n\t\tstring_list.append(string)\n\n\tvar specials_string: String = \", \".join(string_list)\n\n\treturn specials_string\n\n\n# NOTE: not using rich text versions of these texts because\n# it doesn't work with RichTextLabel's \"hint\" system\nfunc _generate_armor_hints() -> Dictionary:\n\tvar out: Dictionary = {}\n\n\tfor armor_type in ArmorType.get_list():\n\t\tvar hint: String = \"\"\n\t\thint += \"%s\\n\" % tr(\"WAVE_STATUS_DAMAGE_FROM\")\n\t\thint += ArmorType.get_text_for_damage_taken(armor_type)\n\n\t\tout[armor_type] = hint\n\n\treturn out\n\n\nfunc _get_time_string(timer: ManualTimer) -> String:\n\tif timer.is_paused():\n\t\treturn tr(\"WAVE_STATUS_PAUSED\")\n\n\tvar time: int = floori(timer.get_time_left())\n\tvar time_minutes: int = floor(time / 60.0)\n\tvar time_seconds: int = time - time_minutes * 60\n\tvar time_string: String = \"%02d:%02d\" % [time_minutes, time_seconds]\n\t\n\treturn time_string\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_local_player_generated_waves():\n\t_update_wave_details()\n\n\nfunc _on_started_first_wave():\n\t_start_game_button.hide()\n\t_start_next_wave_button.show()\n\n\nfunc _on_wave_level_changed():\n\t_update_wave_details()\n\n\nfunc _on_start_next_wave_button_pressed():\n\tEventBus.player_requested_next_wave.emit()\n\n\nfunc _on_start_game_button_pressed():\n\tEventBus.player_requested_start_game.emit()\n"
  },
  {
    "path": "src/ui/top_left_menu/wave_status.tscn",
    "content": "[gd_scene load_steps=7 format=3 uid=\"uid://4tcjyre0hoji\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_3h6gw\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/top_left_menu/wave_status.gd\" id=\"2_fsc15\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://213bkal0uk32\" path=\"res://src/ui/top_left_menu/plus_mode_label.tscn\" id=\"3_27rq8\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/hud/rich_text_label_with_rich_tooltip.gd\" id=\"3_crgv5\"]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_srlh2\"]\ndevice = -1\nphysical_keycode = 78\nunicode = 110\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_u7iub\"]\nevents = [SubResource(\"InputEventKey_srlh2\")]\n\n[node name=\"WaveStatus\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_label\", \"_start_game_button\", \"_start_next_wave_button\", \"_level_label\", \"_game_start_time_container\", \"_game_start_time_label\", \"_next_wave_time_container\", \"_next_wave_time_label\", \"_score_label\", \"_game_time_label\", \"_total_damage_label\", \"_gold_farmed_label\")]\ncustom_minimum_size = Vector2(650, 0)\noffset_right = 600.0\noffset_bottom = 134.0\ntheme = ExtResource(\"1_3h6gw\")\nscript = ExtResource(\"2_fsc15\")\n_label = NodePath(\"DetailsLabel\")\n_start_game_button = NodePath(\"HBoxContainer2/StartGameButton\")\n_start_next_wave_button = NodePath(\"HBoxContainer2/StartNextWaveButton\")\n_level_label = NodePath(\"HBoxContainer/LevelLabel\")\n_game_start_time_container = NodePath(\"HBoxContainer/GameStartTimeContainer\")\n_game_start_time_label = NodePath(\"HBoxContainer/GameStartTimeContainer/GameStartTimeLabel\")\n_next_wave_time_container = NodePath(\"HBoxContainer/NextWaveTimeContainer\")\n_next_wave_time_label = NodePath(\"HBoxContainer/NextWaveTimeContainer/NextWaveTimeLabel\")\n_score_label = NodePath(\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer/ScoreLabel\")\n_game_time_label = NodePath(\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer2/GameTimeLabel\")\n_total_damage_label = NodePath(\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer3/TotalDamageLabel\")\n_gold_farmed_label = NodePath(\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer4/GoldFarmedLabel\")\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"HBoxContainer\"]\nlayout_mode = 2\ntext = \"WAVE_STATS_WAVE\"\n\n[node name=\"LevelLabel\" type=\"Label\" parent=\"HBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"1\"\n\n[node name=\"GameStartTimeContainer\" type=\"HBoxContainer\" parent=\"HBoxContainer\"]\nvisible = false\nlayout_mode = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"HBoxContainer/GameStartTimeContainer\"]\nlayout_mode = 2\ntext = \"WAVE_STATS_GAME_COUNT_DOWN\"\n\n[node name=\"GameStartTimeLabel\" type=\"Label\" parent=\"HBoxContainer/GameStartTimeContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"00:00\"\n\n[node name=\"NextWaveTimeContainer\" type=\"HBoxContainer\" parent=\"HBoxContainer\"]\nvisible = false\nlayout_mode = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"HBoxContainer/NextWaveTimeContainer\"]\nlayout_mode = 2\ntext = \"WAVE_STATS_WAVE_COUNT_DOWN\"\n\n[node name=\"NextWaveTimeLabel\" type=\"Label\" parent=\"HBoxContainer/NextWaveTimeContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"00:00\"\n\n[node name=\"PlusModeLabel\" parent=\"HBoxContainer\" instance=ExtResource(\"3_27rq8\")]\nlayout_mode = 2\n\n[node name=\"DetailsLabel\" type=\"RichTextLabel\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/table_h_separation = 20\nbbcode_enabled = true\ntext = \"[table=5][cell][color=GOLD]Level[/color][/cell][cell][color=GOLD]Size[/color][/cell][cell][color=GOLD]Race[/color][/cell][cell][color=GOLD]Armor[/color][/cell][cell][color=GOLD]Special[/color][/cell][cell]1[/cell][cell][color=GOLD]20[/color] [color=ffa500ff]Mass[/color][/cell][cell][color=32cd32ff]Nature[/color][/cell][cell][color=ff4500ff]Hel[/color][/cell][cell][hint=][/hint][/cell][cell]2[/cell][cell][color=GOLD]10[/color] [color=8fbc8fff]Normal[/color][/cell][cell][color=32cd32ff]Nature[/color][/cell][cell][color=ff4500ff]Hel[/color][/cell][cell][hint=][/hint][/cell][cell]3[/cell][cell][color=GOLD]20[/color] [color=ffa500ff]Mass[/color][/cell][cell][color=9370dbff]Undead[/color][/cell][cell][color=ff4500ff]Hel[/color][/cell][cell][hint=][/hint][/cell][cell]4[/cell][cell][color=GOLD]10[/color] [color=8fbc8fff]Normal[/color][/cell][cell][color=9370dbff]Undead[/color][/cell][cell][color=32cd32ff]Lua[/color][/cell][cell][hint=][/hint][/cell][cell]5[/cell][cell][color=GOLD]2[/color] [color=9370dbff]Champion[/color], [color=GOLD]6[/color] [color=8fbc8fff]Normal[/color][/cell][cell][color=6495edff]Magic[/color][/cell][cell][color=ffd700ff]Sol[/color][/cell][cell][hint=][/hint][/cell][/table]\"\nfit_content = true\nscroll_active = false\nautowrap_mode = 0\nhint_underlined = false\nscript = ExtResource(\"3_crgv5\")\n\n[node name=\"HBoxContainer2\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"HBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"HBoxContainer2/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"HBoxContainer2/VBoxContainer/GridContainer\"]\nlayout_mode = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"WAVE_STATS_SCORE\"\n\n[node name=\"ScoreLabel\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer\"]\nlayout_mode = 2\ntext = \"11\"\n\n[node name=\"HBoxContainer2\" type=\"HBoxContainer\" parent=\"HBoxContainer2/VBoxContainer/GridContainer\"]\nlayout_mode = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer2\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"WAVE_STATS_GAME_TIME\"\n\n[node name=\"GameTimeLabel\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer2\"]\nlayout_mode = 2\ntext = \"03:07\"\n\n[node name=\"HBoxContainer3\" type=\"HBoxContainer\" parent=\"HBoxContainer2/VBoxContainer/GridContainer\"]\nlayout_mode = 2\n\n[node name=\"Label4\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer3\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"WAVE_STATS_TOTAL_DMG\"\n\n[node name=\"TotalDamageLabel\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer3\"]\nlayout_mode = 2\ntext = \"11\"\n\n[node name=\"HBoxContainer4\" type=\"HBoxContainer\" parent=\"HBoxContainer2/VBoxContainer/GridContainer\"]\nlayout_mode = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer4\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.84, 0, 1)\ntext = \"WAVE_STATS_GOLD_FARMED\"\n\n[node name=\"GoldFarmedLabel\" type=\"Label\" parent=\"HBoxContainer2/VBoxContainer/GridContainer/HBoxContainer4\"]\nlayout_mode = 2\ntext = \"11\"\n\n[node name=\"Spacer\" type=\"HBoxContainer\" parent=\"HBoxContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"StartGameButton\" type=\"Button\" parent=\"HBoxContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 4\ntooltip_text = \"WAVE_STATUS_TOOLTIP_NEXT_WAVE\"\nfocus_mode = 0\ntheme_override_font_sizes/font_size = 25\nshortcut = SubResource(\"Shortcut_u7iub\")\nshortcut_in_tooltip = false\ntext = \"WAVE_STATS_START\"\n\n[node name=\"StartNextWaveButton\" type=\"Button\" parent=\"HBoxContainer2\"]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 4\ntooltip_text = \"WAVE_STATUS_TOOLTIP_NEXT_WAVE\"\nfocus_mode = 0\ntheme_override_font_sizes/font_size = 25\nshortcut = SubResource(\"Shortcut_u7iub\")\nshortcut_in_tooltip = false\ntext = \"WAVE_STATS_NEXT_WAVE\"\n\n[connection signal=\"pressed\" from=\"HBoxContainer2/StartGameButton\" to=\".\" method=\"_on_start_game_button_pressed\"]\n[connection signal=\"pressed\" from=\"HBoxContainer2/StartNextWaveButton\" to=\".\" method=\"_on_start_next_wave_button_pressed\"]\n"
  },
  {
    "path": "src/ui/tower_stash_menu/tower_stash_menu.gd",
    "content": "class_name TowerStashMenu extends PanelContainer\n\n\nenum FilterType {\n\tRARITY,\n\tELEMENT\n}\n\n\nconst BUTTON_SIZE: Vector2 = Vector2(120, 120)\nconst COLUMN_COUNT: int = 4\nconst ROW_COUNT: int = 5\n\n\n@export var _background_grid: GridContainer\n@export var _tower_grid: GridContainer\n@export var _rarity_filter: RarityFilter\n@export var _element_filter: ElementsContainer\n\nvar _button_list: Array[TowerButton] = []\nvar _prev_tower_list: Array = []\nvar _filter_type: FilterType = FilterType.RARITY\n\n\n#########################\n###     Built-in      ###\n#########################\n\n# NOTE: in Build mode, use element filter for tower stash\n# because in Build mode all towers are visible from the\n# start and filtering by rarity would show too many towers.\n# \n# In random modes, it's better to filter by rarity because\n# players typically research only 2-3 elements and a small\n# amount of towers is randomly distributed after each wave.\nfunc _ready():\n\tif Globals.get_game_mode() == GameMode.enm.BUILD:\n\t\t_filter_type = TowerStashMenu.FilterType.ELEMENT\n\telse:\n\t\t_filter_type = TowerStashMenu.FilterType.RARITY\n\n\t_rarity_filter.visible = _filter_type == FilterType.RARITY\n\t_element_filter.visible = _filter_type == FilterType.ELEMENT\n\t\n\t_update_button_visibility()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc connect_to_local_player(local_player: Player):\n\tlocal_player.element_level_changed.connect(_on_element_level_changed)\n\t_on_element_level_changed()\n\n\tvar local_team: Team = local_player.get_team()\n\tlocal_team.level_changed.connect(_on_wave_level_changed)\n\t_on_wave_level_changed()\n\n\tvar tower_stash: TowerStash = local_player.get_tower_stash()\n\ttower_stash.changed.connect(_on_tower_stash_changed)\n\n\t\n#########################\n###      Private      ###\n#########################\n\nfunc _add_tower_button(tower_id: int, index: int):\n\tvar tower_button: TowerButton = TowerButton.make()\n\t_button_list.append(tower_button)\n\t_tower_grid.add_child(tower_button)\n\t_tower_grid.move_child(tower_button, index)\n\ttower_button.pressed.connect(_on_tower_button_pressed.bind(tower_id))\n\n\ttower_button.set_tower_id(tower_id)\n\ttower_button.set_locked(true)\n\n\tif Globals.get_game_mode() == GameMode.enm.TOTALLY_RANDOM:\n\t\ttower_button.set_tier_visible(true)\n\n\nfunc _unlock_tower_buttons_if_possible():\n\tfor button in _button_list:\n\t\tif !button.disabled:\n\t\t\tcontinue\n\n\t\tvar tower_id: int = button.get_tower_id()\n\t\tvar local_player: Player = PlayerManager.get_local_player()\n\t\tvar can_build_tower: bool = TowerProperties.requirements_are_satisfied(tower_id, local_player)\n\n\t\tif can_build_tower:\n\t\t\tbutton.set_locked(false)\n\n\nfunc _update_button_visibility():\n\tvar selected_rarity_list: Array[Rarity.enm] = _rarity_filter.get_filter()\n\tvar selected_element: Element.enm = _element_filter.get_element()\n\t\n\tfor tower_button in _button_list:\n\t\tvar tower_id: int = tower_button.get_tower_id()\n\t\tvar rarity: Rarity.enm = TowerProperties.get_rarity(tower_id)\n\t\tvar element: Element.enm = TowerProperties.get_element(tower_id)\n\t\t\n\t\tvar filter_match: bool\n\t\tmatch _filter_type:\n\t\t\tFilterType.RARITY: filter_match = selected_rarity_list.has(rarity)\n\t\t\tFilterType.ELEMENT: filter_match = selected_element == element\n\t\t\n\t\ttower_button.visible = filter_match\n\t\t\n\tvar visible_tower_count: int = 0\n\tfor tower_button in _button_list:\n\t\tif tower_button.visible:\n\t\t\tvisible_tower_count += 1\n\t\n\tvar current_background_count: int = _background_grid.get_child_count()\n\tvar min_background_count: int = ROW_COUNT * COLUMN_COUNT\n\tvar expected_background_count: int = ceili(visible_tower_count / float(COLUMN_COUNT)) * COLUMN_COUNT\n\texpected_background_count = max(expected_background_count, min_background_count)\n\t\n\tvar need_more_background: bool = expected_background_count > current_background_count\n\t\n\tif need_more_background:\n\t\twhile _background_grid.get_child_count() < expected_background_count:\n\t\t\tvar background_button: EmptyUnitButton = _make_background_button()\n\t\t\t_background_grid.add_child(background_button)\n\t\n\tvar background_button_list: Array = _background_grid.get_children()\n\tfor background_button in background_button_list:\n\t\tbackground_button.visible = background_button.get_index() < expected_background_count\n\n\nfunc _make_background_button() -> EmptyUnitButton:\n\tvar button: Button = EmptyUnitButton.make()\n\tbutton.custom_minimum_size = BUTTON_SIZE\n\t\n\treturn button\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_tower_stash_changed():\n\tvar local_player: Player = PlayerManager.get_local_player()\n\tvar tower_stash: TowerStash = local_player.get_tower_stash()\n\tvar tower_map: Dictionary = tower_stash.get_towers()\n\tvar tower_list: Array = tower_map.keys()\n\n\ttower_list.sort_custom(\n\t\tfunc(a, b) -> bool:\n\t\t\tvar rarity_a: Rarity.enm = TowerProperties.get_rarity(a)\n\t\t\tvar rarity_b: Rarity.enm = TowerProperties.get_rarity(b)\n\t\t\tvar cost_a: int = TowerProperties.get_cost(a)\n\t\t\tvar cost_b: int = TowerProperties.get_cost(b)\n\t\t\t\n\t\t\tif rarity_a == rarity_b:\n\t\t\t\treturn cost_a < cost_b\n\t\t\telse:\n\t\t\t\treturn rarity_a < rarity_b\n\t)\n\n# \tRemove buttons for towers which were removed from stash\n\tvar removed_button_list: Array[TowerButton] = []\n\n\tfor button in _button_list:\n\t\tvar tower_id: int = button.get_tower_id()\n\t\tvar tower_was_removed: bool = !tower_map.has(tower_id)\n\n\t\tif tower_was_removed:\n\t\t\tremoved_button_list.append(button)\n\n\tfor button in removed_button_list:\n\t\t_tower_grid.remove_child(button)\n\t\tbutton.queue_free()\n\t\t_button_list.erase(button)\n\n# \tAdd buttons for towers which were added to stash\n#\tNOTE: preserve order\n\tfor i in range(0, tower_list.size()):\n\t\tvar tower_id: int = tower_list[i]\n\t\tvar tower_was_added: bool = !_prev_tower_list.has(tower_id)\n\t\t\n\t\tif tower_was_added:\n\t\t\t_add_tower_button(tower_id, i)\n\t\n\t_prev_tower_list = tower_list.duplicate()\n\n# \tUpdate tower counts\n\tfor button in _button_list:\n\t\tvar tower_id: int = button.get_tower_id()\n\t\tvar tower_count: int = tower_map[tower_id]\n\t\tbutton.set_count(tower_count)\n\n\t_unlock_tower_buttons_if_possible()\n\t_update_button_visibility()\n\n\nfunc _on_close_button_pressed():\n\thide()\n\n\nfunc _on_tower_button_pressed(tower_id: int):\n\tEventBus.player_requested_to_build_tower.emit(tower_id)\n\n\nfunc _on_rarity_filter_container_filter_changed():\n\t_update_button_visibility()\n\n\nfunc _on_element_filter_element_changed():\n\t_update_button_visibility()\n\n\nfunc _on_element_level_changed():\n\t_unlock_tower_buttons_if_possible()\n\n\nfunc _on_wave_level_changed():\n\t_unlock_tower_buttons_if_possible()\n"
  },
  {
    "path": "src/ui/tower_stash_menu/tower_stash_menu.tscn",
    "content": "[gd_scene load_steps=9 format=3 uid=\"uid://donslrrviy807\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/tower_stash_menu/tower_stash_menu.gd\" id=\"1_3360v\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8xsklkw4jhlw\" path=\"res://src/ui/buttons/empty_unit_button.tscn\" id=\"3_egows\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"3_o2dlo\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://cwmhuo2ppjfx2\" path=\"res://resources/theme/common/rect_container_m.tres\" id=\"4_jlt7a\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://qcct52drete4\" path=\"res://src/ui/filter_buttons/rarity_filter.tscn\" id=\"6_x6hx1\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://l8hrrql7ne16\" path=\"res://src/ui/filter_buttons/element_filter.tscn\" id=\"7_s88kh\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_h654a\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_wh5fy\"]\natlas = ExtResource(\"3_o2dlo\")\nregion = Rect2(896, 0, 128, 128)\n\n[node name=\"TowerStashMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_background_grid\", \"_tower_grid\", \"_rarity_filter\", \"_element_filter\")]\ncustom_minimum_size = Vector2(630, 850)\noffset_right = 622.0\noffset_bottom = 827.0\nmouse_force_pass_scroll_events = false\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_h654a\")\nscript = ExtResource(\"1_3360v\")\n_background_grid = NodePath(\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\")\n_tower_grid = NodePath(\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/TowerGrid\")\n_rarity_filter = NodePath(\"MarginContainer3/RarityFilter\")\n_element_filter = NodePath(\"MarginContainer3/ElementFilter\")\n\n[node name=\"TabContainer\" type=\"TabContainer\" parent=\".\"]\nlayout_mode = 2\ncurrent_tab = 0\ntabs_visible = false\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"TabContainer\"]\nlayout_mode = 2\nmetadata/_tab_index = 0\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"TabContainer/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 4\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"TabContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 0\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2\"]\ncustom_minimum_size = Vector2(0, 640)\nlayout_mode = 2\nhorizontal_scroll_mode = 0\n\n[node name=\"BackgroundGrid\" type=\"GridContainer\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nmouse_filter = 0\ntheme_override_constants/h_separation = 10\ntheme_override_constants/v_separation = 10\ncolumns = 4\n\n[node name=\"EmptyUnitButton1\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton12\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton11\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton4\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton5\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton6\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton7\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton8\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton9\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton10\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton2\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton3\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton13\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton14\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton15\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton16\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton17\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton18\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton19\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton20\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer/BackgroundGrid\" instance=ExtResource(\"3_egows\")]\nlayout_mode = 2\n\n[node name=\"TowerGrid\" type=\"GridContainer\" parent=\"TabContainer/MarginContainer/VBoxContainer/PanelContainer/MarginContainer2/ScrollContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\nmouse_filter = 0\ntheme_override_constants/h_separation = 10\ntheme_override_constants/v_separation = 10\ncolumns = 4\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nicon = SubResource(\"AtlasTexture_wh5fy\")\nicon_alignment = 1\nexpand_icon = true\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_top = -15\n\n[node name=\"TitleLabel\" type=\"Label\" parent=\"MarginContainer2\"]\ncustom_minimum_size = Vector2(200, 0)\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_font_sizes/font_size = 26\ntheme_override_styles/normal = ExtResource(\"4_jlt7a\")\ntext = \"TOWER_STASH_MENU_TITLE\"\nhorizontal_alignment = 1\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\nmouse_filter = 2\ntheme_override_constants/margin_left = -30\ntheme_override_constants/margin_top = 40\n\n[node name=\"RarityFilter\" parent=\"MarginContainer3\" instance=ExtResource(\"6_x6hx1\")]\nlayout_mode = 2\n\n[node name=\"ElementFilter\" parent=\"MarginContainer3\" instance=ExtResource(\"7_s88kh\")]\nvisible = false\nlayout_mode = 2\n\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n[connection signal=\"filter_changed\" from=\"MarginContainer3/RarityFilter\" to=\".\" method=\"_on_rarity_filter_container_filter_changed\"]\n[connection signal=\"element_changed\" from=\"MarginContainer3/ElementFilter\" to=\".\" method=\"_on_element_filter_element_changed\"]\n"
  },
  {
    "path": "src/ui/unit_menu/buff_container.gd",
    "content": "class_name BuffContainer extends VBoxContainer\n\n\n# Displays buffs of a unit.\n\n# NOTE: The weird setup of two grid containers for two rows\n# is needed to make buffs appear on second row first, then\n# on second when first row runs out of space.\n\n\nvar _buff_display_list: Array[BuffDisplay] = []\n\n@export var _row_top: GridContainer\n@export var _row_bottom: GridContainer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar top_list: Array[Node] = _row_top.get_children()\n\tvar bottom_list: Array[Node] = _row_bottom.get_children()\n\t\n\tvar combined_list: Array = []\n\tcombined_list.append_array(bottom_list)\n\tcombined_list.append_array(top_list)\n\t\n\tfor child_node in combined_list:\n\t\tvar buff_display: BuffDisplay = child_node as BuffDisplay\n\t\t_buff_display_list.append(buff_display)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc load_buffs_for_unit(unit: Unit):\n\tvar buff_list: Array[Buff] = unit.get_buff_list()\n\n\tvar hidden_buff_list: Array[Buff] = []\n\n\tfor buff in buff_list:\n\t\tif buff.is_hidden():\n\t\t\thidden_buff_list.append(buff)\n\n\tif !Config.show_hidden_buffs():\n\t\tfor buff in hidden_buff_list:\n\t\t\tbuff_list.erase(buff)\n\n\tvar perma_buff_list: Array[Buff] = []\n\tfor buff in buff_list:\n\t\tvar buff_is_perma: bool = buff.get_original_duration() < 0\n\t\tif buff_is_perma:\n\t\t\tperma_buff_list.append(buff)\n\n#\tNOTE: need to put permanent buffs first, otherwise they\n#\twill just around too much due to temporary buffs\n#\texpiring\n\tfor buff in perma_buff_list:\n\t\tbuff_list.erase(buff)\n\t\tbuff_list.insert(0, buff)\n\n\tfor buff_display in _buff_display_list:\n\t\tbuff_display.set_buff(null)\n\n\tfor i in range(0, buff_list.size()):\n\t\tif i >= _buff_display_list.size():\n\t\t\tbreak\n\t\t\n\t\tvar buff_display: BuffDisplay = _buff_display_list[i]\n\t\tvar buff: Buff = buff_list[i]\n\t\tbuff_display.set_buff(buff)\n\n#\tNOTE: need to be careful with how visibility is updated.\n#\tThe method of \"hide all, then show only valid buffs\" is\n#\tbad because it disrupts tooltips. Instead, use method of\n#\t\"hide only invalid\"\n\tfor buff_display in _buff_display_list:\n\t\tvar has_assigned_buff: bool = buff_display.get_buff() != null\n\t\tbuff_display.visible = has_assigned_buff\n"
  },
  {
    "path": "src/ui/unit_menu/buff_container.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://7hnklay7gedu\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/buff_container.gd\" id=\"1_5eut6\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://d4mgo5v7j01kj\" path=\"res://src/ui/unit_menu/buff_display.tscn\" id=\"2_nldtx\"]\n\n[node name=\"BuffContainer\" type=\"VBoxContainer\" node_paths=PackedStringArray(\"_row_top\", \"_row_bottom\")]\noffset_right = 412.0\noffset_bottom = 100.0\nscript = ExtResource(\"1_5eut6\")\n_row_top = NodePath(\"RowTop\")\n_row_bottom = NodePath(\"RowBottom\")\n\n[node name=\"RowTop\" type=\"GridContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(0, 48)\nlayout_mode = 2\ncolumns = 8\n\n[node name=\"BuffDisplay9\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay10\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay11\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay12\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay13\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay14\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay15\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay16\" parent=\"RowTop\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"RowBottom\" type=\"GridContainer\" parent=\".\"]\ncustom_minimum_size = Vector2(0, 48)\nlayout_mode = 2\ncolumns = 8\n\n[node name=\"BuffDisplay\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay2\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay3\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay4\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay5\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay6\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay7\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n\n[node name=\"BuffDisplay8\" parent=\"RowBottom\" instance=ExtResource(\"2_nldtx\")]\nlayout_mode = 2\n"
  },
  {
    "path": "src/ui/unit_menu/buff_display.gd",
    "content": "class_name BuffDisplay extends PanelContainer\n\n\nconst FALLBACK_BUFF_ICON: String = \"res://resources/icons/generic_icons/egg.tres\"\n\n\n@export var _texture_rect: TextureRect\n@export var _stacks_label: Label\n@export var _time_indicator: TimeIndicator\n\nvar _buff: Buff = null\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _process(_delta: float):\n\tif _buff == null:\n\t\treturn\n\n\tif !is_instance_valid(_buff):\n\t\treturn\n\n#\tNOTE: format stacks text to fit within icon bounds\n\tvar stacks: int = _buff.get_displayed_stacks()\n\tvar stacks_text: String\n\tif stacks == 0:\n\t\tstacks_text = \"\"\n\telif stacks < 1000:\n\t\tstacks_text = str(stacks)\n\telse:\n#\t\tShow as \"k\" format with 1 decimal place (e.g., \"1.2k\", \"15.7k\")\n\t\tvar stacks_k: float = stacks / 1000.0\n\t\tstacks_text = \"%.1fk\" % stacks_k\n\n\t_stacks_label.text = stacks_text\n\t\n\tvar remaining_duration: float = _buff.get_remaining_duration()\n\tvar overall_duration: float = _buff.get_original_duration()\n\tvar elapsed_duration: float = overall_duration - remaining_duration\n\tvar buff_is_permanent: bool = overall_duration < 0\n\n\tif buff_is_permanent:\n\t\t_time_indicator.set_time_values(0.0, 1.0)\n\telse:\n\t\t_time_indicator.set_time_values(elapsed_duration, overall_duration)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_buff(buff: Buff):\n\t_buff = buff\n\t\n\tif buff == null:\n\t\treturn\n\n\tvar buff_icon_path: String = buff.get_buff_icon()\n\n\tif !ResourceLoader.exists(buff_icon_path):\n\t\tbuff_icon_path = FALLBACK_BUFF_ICON\n\t\n\tvar texture: Texture2D = load(buff_icon_path)\n\t_texture_rect.texture = texture\n\n\tvar tooltip: String = buff.get_tooltip_text()\n\tset_tooltip_text(tooltip)\n\n\tvar color: Color = buff.get_buff_icon_color()\n\t_texture_rect.modulate = color\n\n\nfunc get_buff() -> Buff:\n\treturn _buff\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _make_custom_tooltip(for_text: String) -> Object:\n\tvar label: RichTextLabel = Utils.make_rich_text_tooltip(for_text)\n\n\treturn label\n"
  },
  {
    "path": "src/ui/unit_menu/buff_display.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://d4mgo5v7j01kj\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/buff_display.gd\" id=\"1_k2kus\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://bv7gu3v3jconv\" path=\"res://resources/icons/generic_icons/alligator_clip.tres\" id=\"2_ofmfc\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://d1i5vdh8yrhbx\" path=\"res://src/ui/buttons/time_indicator.tscn\" id=\"3_3v1eu\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleBoxFlat_si6yn\"]\nbg_color = Color(0.0509804, 0.0509804, 0.0509804, 1)\nborder_width_left = 2\nborder_width_top = 2\nborder_width_right = 2\nborder_width_bottom = 2\nborder_color = Color(0.776471, 0.788235, 0.788235, 1)\ncorner_radius_top_left = 7\ncorner_radius_top_right = 7\ncorner_radius_bottom_right = 7\ncorner_radius_bottom_left = 7\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_xdrdp\"]\n\n[node name=\"BuffDisplay\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_texture_rect\", \"_stacks_label\", \"_time_indicator\")]\ncustom_minimum_size = Vector2(48, 48)\ntheme_override_styles/panel = SubResource(\"StyleBoxFlat_si6yn\")\nscript = ExtResource(\"1_k2kus\")\n_texture_rect = NodePath(\"TextureRect\")\n_stacks_label = NodePath(\"StacksLabel\")\n_time_indicator = NodePath(\"TimeIndicator\")\n\n[node name=\"TextureRect\" type=\"TextureRect\" parent=\".\"]\nlayout_mode = 2\ntexture = ExtResource(\"2_ofmfc\")\nexpand_mode = 2\n\n[node name=\"TimeIndicator\" parent=\".\" instance=ExtResource(\"3_3v1eu\")]\nlayout_mode = 2\noverlay_color = Color(0, 0, 0, 0.54902)\ndraw_style = 0\n\n[node name=\"StacksLabel\" type=\"Label\" parent=\".\"]\ncustom_minimum_size = Vector2(25, 20)\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 8\ntheme_override_colors/font_outline_color = Color(0, 0, 0, 1)\ntheme_override_constants/shadow_offset_x = 0\ntheme_override_constants/shadow_offset_y = 1\ntheme_override_constants/outline_size = 7\ntheme_override_font_sizes/font_size = 30\ntheme_override_styles/normal = SubResource(\"StyleBoxEmpty_xdrdp\")\ntext = \"3\"\nhorizontal_alignment = 1\nvertical_alignment = 2\n"
  },
  {
    "path": "src/ui/unit_menu/buff_group_editor.gd",
    "content": "class_name BuffGroupEditor extends HBoxContainer\n\n\n# Editor for changing modes of tower buff groups.\n\n\nvar _button_list: Array[BuffGroupButton] = []\nvar _tower: Tower = null\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar child_list: Array[Node] = get_children()\n\t\n\tfor child in child_list:\n\t\tvar button: BuffGroupButton = child as BuffGroupButton\n\t\t\n\t\tif button == null:\n\t\t\tcontinue\n\t\t\n\t\t_button_list.append(button)\n\t\tbutton.pressed.connect(_on_button_pressed.bind(button))\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_tower(tower: Tower):\n\tvar prev_tower: Tower = _tower\n\t_tower = tower\n\t\n\tif prev_tower != null && prev_tower.buff_group_changed.is_connected(_on_tower_buff_group_changed):\n\t\tprev_tower.buff_group_changed.disconnect(_on_tower_buff_group_changed)\n\n\tif tower != null:\n\t\ttower.buff_group_changed.connect(_on_tower_buff_group_changed)\n\t\t_update_displayed_buff_group_modes()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _update_displayed_buff_group_modes():\n\tfor button in _button_list:\n\t\tvar buff_group_number: int = button.get_buff_group_number()\n\t\tvar buff_group_mode: BuffGroupMode.enm = _tower.get_buff_group_mode(buff_group_number)\n\t\tbutton.set_buff_group_mode(buff_group_mode)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_button_pressed(button: BuffGroupButton):\n\tvar buff_group_number: int = button.get_buff_group_number()\n\tEventBus.player_clicked_tower_buff_group.emit(_tower, buff_group_number)\n\n\nfunc _on_tower_buff_group_changed():\n\t_update_displayed_buff_group_modes()\n"
  },
  {
    "path": "src/ui/unit_menu/buff_group_editor.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://ccys3jpdwu3ft\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/buff_group_editor.gd\" id=\"1_8s3be\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dfid7khpwu0i8\" path=\"res://src/ui/buttons/buff_group_button.tscn\" id=\"1_c3k71\"]\n\n[node name=\"BuffGroupEditor\" type=\"HBoxContainer\"]\nscript = ExtResource(\"1_8s3be\")\n\n[node name=\"BuffGroupButton1\" parent=\".\" instance=ExtResource(\"1_c3k71\")]\nlayout_mode = 2\n_buff_group_number = 1\n\n[node name=\"BuffGroupButton2\" parent=\".\" instance=ExtResource(\"1_c3k71\")]\nlayout_mode = 2\n_buff_group_number = 2\n\n[node name=\"BuffGroupButton3\" parent=\".\" instance=ExtResource(\"1_c3k71\")]\nlayout_mode = 2\n_buff_group_number = 3\n\n[node name=\"BuffGroupButton4\" parent=\".\" instance=ExtResource(\"1_c3k71\")]\nlayout_mode = 2\n_buff_group_number = 4\n\n[node name=\"BuffGroupButton5\" parent=\".\" instance=ExtResource(\"1_c3k71\")]\nlayout_mode = 2\n_buff_group_number = 5\n\n[node name=\"BuffGroupButton6\" parent=\".\" instance=ExtResource(\"1_c3k71\")]\nlayout_mode = 2\n_buff_group_number = 6\n"
  },
  {
    "path": "src/ui/unit_menu/creep_details.gd",
    "content": "class_name CreepDetails extends PanelContainer\n\n\n@export var _creep_name_label: Label\n\n# Movespeed\n@export var _base_movespeed: Label\n@export var _movespeed_bonus: Label\n@export var _movespeed_bonus_perc: Label\n@export var _overall_movespeed: Label\n@export var _damage_reduction: Label\n\n# Armor\n@export var _base_armor: Label\n@export var _armor_bonus: Label\n@export var _armor_bonus_perc: Label\n@export var _overall_armor: Label\n\n# Damage from element\n@export var _dmg_from_astral: Label\n@export var _dmg_from_darkness: Label\n@export var _dmg_from_nature: Label\n@export var _dmg_from_ice: Label\n@export var _dmg_from_fire: Label\n@export var _dmg_from_storm: Label\n@export var _dmg_from_iron: Label\n\n# Defense\n@export var _dmg_from_attacks: Label\n@export var _dmg_from_spells: Label\n\n# Health\n@export var _base_health: Label\n@export var _health_bonus: Label\n@export var _health_bonus_perc: Label\n@export var _overall_health: Label\n@export var _base_health_regen: Label\n@export var _health_regen_bonus: Label\n@export var _health_regen_bonus_perc: Label\n@export var _overall_health_regen: Label\n\n# Mana\n@export var _base_mana: Label\n@export var _mana_bonus: Label\n@export var _mana_bonus_perc: Label\n@export var _overall_mana: Label\n@export var _base_mana_regen: Label\n@export var _mana_regen_bonus: Label\n@export var _mana_regen_bonus_perc: Label\n@export var _overall_mana_regen: Label\n\n# Misc\n@export var _bounty_ratio: Label\n@export var _exp_ratio: Label\n@export var _item_drop_ratio: Label\n@export var _item_quality_ratio: Label\n@export var _buff_duration: Label\n@export var _debuff_duration: Label\n\nvar _creep: Creep = null\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_creep(creep: Creep):\n\t_creep = creep\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc update_text():\n\tif _creep == null:\n\t\treturn\n\t\n\tvar creep_name: String = _creep.get_display_name()\n\t_creep_name_label.text = creep_name\n\n#\tMovespeed\n\tvar base_movespeed: float = _creep.get_base_movespeed()\n\tvar base_movespeed_string: String = Utils.format_float(base_movespeed, 0)\n\t_base_movespeed.set_text(base_movespeed_string)\n\n\tvar movespeed_bonus: float = _creep.get_prop_move_speed_absolute()\n\tvar movespeed_bonus_string: String = Utils.format_float(movespeed_bonus, 0)\n\t_movespeed_bonus.set_text(movespeed_bonus_string)\n\n\tvar movespeed_bonus_perc: float = _creep.get_prop_move_speed() - 1.0\n\tvar movespeed_bonus_perc_string: String = Utils.format_percent(movespeed_bonus_perc, 0)\n\t_movespeed_bonus_perc.set_text(movespeed_bonus_perc_string)\n\n\tvar overall_movespeed: float = _creep.get_current_movespeed()\n\tvar overall_movespeed_string: String = Utils.format_float(overall_movespeed, 0)\n\t_overall_movespeed.set_text(overall_movespeed_string)\n\n#\tArmor\n\tvar base_armor: float = _creep.get_base_armor()\n\tvar base_armor_string: String = Utils.format_float(base_armor, 1)\n\t_base_armor.set_text(base_armor_string)\n\n\tvar armor_bonus: float = _creep.get_base_armor_bonus()\n\tvar armor_bonus_string: String = Utils.format_float(armor_bonus, 1)\n\t_armor_bonus.set_text(armor_bonus_string)\n\n\tvar armor_bonus_perc: float = _creep.get_base_armor_bonus_percent() - 1.0\n\tvar armor_bonus_perc_string: String = Utils.format_percent(armor_bonus_perc, 0)\n\t_armor_bonus_perc.set_text(armor_bonus_perc_string)\n\n\tvar overall_armor: float = _creep.get_overall_armor()\n\tvar overall_armor_string: String = Utils.format_float(overall_armor, 1)\n\t_overall_armor.set_text(overall_armor_string)\n\n\tvar damage_reduction: float = _creep.get_current_armor_damage_reduction()\n\tvar damage_reduction_string: String = Utils.format_percent(damage_reduction, 0)\n\t_damage_reduction.set_text(damage_reduction_string)\n\n#\tDefense\n\tvar dmg_from_attacks: float = _creep.get_prop_atk_damage_received()\n\tvar dmg_from_attacks_string: String = Utils.format_percent(dmg_from_attacks, 0)\n\t_dmg_from_attacks.set_text(dmg_from_attacks_string)\n\n\tvar dmg_from_spells: float = _creep.get_prop_spell_damage_received()\n\tvar dmg_from_spells_string: String = Utils.format_percent(dmg_from_spells, 0)\n\t_dmg_from_spells.set_text(dmg_from_spells_string)\n\n#\tDamage from element\n\tvar dmg_from_astral: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_ASTRAL]\n\tvar dmg_from_astral_string: String = Utils.format_percent(dmg_from_astral, 0)\n\t_dmg_from_astral.set_text(dmg_from_astral_string)\n\n\tvar dmg_from_darkness: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_DARKNESS]\n\tvar dmg_from_darkness_string: String = Utils.format_percent(dmg_from_darkness, 0)\n\t_dmg_from_darkness.set_text(dmg_from_darkness_string)\n\n\tvar dmg_from_nature: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_NATURE]\n\tvar dmg_from_nature_string: String = Utils.format_percent(dmg_from_nature, 0)\n\t_dmg_from_nature.set_text(dmg_from_nature_string)\n\n\tvar dmg_from_ice: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_ICE]\n\tvar dmg_from_ice_string: String = Utils.format_percent(dmg_from_ice, 0)\n\t_dmg_from_ice.set_text(dmg_from_ice_string)\n\n\tvar dmg_from_fire: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_FIRE]\n\tvar dmg_from_fire_string: String = Utils.format_percent(dmg_from_fire, 0)\n\t_dmg_from_fire.set_text(dmg_from_fire_string)\n\n\tvar dmg_from_storm: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_STORM]\n\tvar dmg_from_storm_string: String = Utils.format_percent(dmg_from_storm, 0)\n\t_dmg_from_storm.set_text(dmg_from_storm_string)\n\n\tvar dmg_from_iron: float = _creep._mod_value_map[ModificationType.enm.MOD_DMG_FROM_IRON]\n\tvar dmg_from_iron_string: String = Utils.format_percent(dmg_from_iron, 0)\n\t_dmg_from_iron.set_text(dmg_from_iron_string)\n\n# \tHealth\n\tvar base_health: int = floori(_creep.get_base_health())\n\tvar base_health_string: String = TowerDetails.int_format(base_health)\n\t_base_health.set_text(base_health_string)\n\n\tvar health_bonus: int = floori(_creep.get_base_health_bonus())\n\tvar health_bonus_string: String = TowerDetails.int_format(health_bonus)\n\t_health_bonus.set_text(health_bonus_string)\n\n\tvar health_bonus_perc: float = _creep.get_base_health_bonus_percent() - 1.0\n\tvar health_bonus_perc_string: String = Utils.format_percent(health_bonus_perc, 0)\n\t_health_bonus_perc.set_text(health_bonus_perc_string)\n\n\tvar overall_health: int = floori(_creep.get_overall_health())\n\tvar overall_health_string: String = TowerDetails.int_format(overall_health)\n\t_overall_health.set_text(overall_health_string)\n\n\tvar base_health_regen: float = _creep.get_base_health_regen()\n\tvar base_health_regen_string: String = Utils.format_float(base_health_regen, 1)\n\t_base_health_regen.set_text(base_health_regen_string)\n\n\tvar health_regen_bonus: float = _creep.get_base_health_regen_bonus()\n\tvar health_regen_bonus_string: String = Utils.format_float(health_regen_bonus, 1)\n\t_health_regen_bonus.set_text(health_regen_bonus_string)\n\n\tvar health_regen_bonus_perc: float = _creep.get_base_health_regen_bonus_percent() - 1.0\n\tvar health_regen_bonus_perc_string: String = Utils.format_percent(health_regen_bonus_perc, 0)\n\t_health_regen_bonus_perc.set_text(health_regen_bonus_perc_string)\n\n\tvar overall_health_regen: float = _creep.get_overall_health_regen()\n\tvar overall_health_regen_string: String = Utils.format_float(overall_health_regen, 1)\n\t_overall_health_regen.set_text(overall_health_regen_string)\n\n# \tMana\n\tvar base_mana: int = floori(_creep.get_base_mana())\n\tvar base_mana_string: String = TowerDetails.int_format(base_mana)\n\t_base_mana.set_text(base_mana_string)\n\n\tvar mana_bonus: int = floori(_creep.get_base_mana_bonus())\n\tvar mana_bonus_string: String = TowerDetails.int_format(mana_bonus)\n\t_mana_bonus.set_text(mana_bonus_string)\n\n\tvar mana_bonus_perc: float = _creep.get_base_mana_bonus_percent() - 1.0\n\tvar mana_bonus_perc_string: String = Utils.format_percent(mana_bonus_perc, 0)\n\t_mana_bonus_perc.set_text(mana_bonus_perc_string)\n\n\tvar overall_mana: int = floori(_creep.get_overall_mana())\n\tvar overall_mana_string: String = TowerDetails.int_format(overall_mana)\n\t_overall_mana.set_text(overall_mana_string)\n\n\tvar base_mana_regen: float = _creep.get_base_mana_regen()\n\tvar base_mana_regen_string: String = Utils.format_float(base_mana_regen, 1)\n\t_base_mana_regen.set_text(base_mana_regen_string)\n\n\tvar mana_regen_bonus: float = _creep.get_base_mana_regen_bonus()\n\tvar mana_regen_bonus_string: String = Utils.format_float(mana_regen_bonus, 1)\n\t_mana_regen_bonus.set_text(mana_regen_bonus_string)\n\n\tvar mana_regen_bonus_perc: float = _creep.get_base_mana_regen_bonus_percent() - 1.0\n\tvar mana_regen_bonus_perc_string: String = Utils.format_percent(mana_regen_bonus_perc, 0)\n\t_mana_regen_bonus_perc.set_text(mana_regen_bonus_perc_string)\n\n\tvar overall_mana_regen: float = _creep.get_overall_mana_regen()\n\tvar overall_mana_regen_string: String = Utils.format_float(overall_mana_regen, 1)\n\t_overall_mana_regen.set_text(overall_mana_regen_string)\n\n#\tMisc\n\tvar bounty_ratio: float = _creep.get_prop_bounty_granted()\n\tvar bounty_ratio_string: String = Utils.format_percent(bounty_ratio, 0)\n\t_bounty_ratio.set_text(bounty_ratio_string)\n\n\tvar exp_ratio: float = _creep.get_prop_exp_granted()\n\tvar exp_ratio_string: String = Utils.format_percent(exp_ratio, 0)\n\t_exp_ratio.set_text(exp_ratio_string)\n\n\tvar item_drop_ratio: float = _creep.get_item_drop_ratio_on_death()\n\tvar item_drop_ratio_string: String = Utils.format_percent(item_drop_ratio, 0)\n\t_item_drop_ratio.set_text(item_drop_ratio_string)\n\n\tvar item_quality_ratio: float = _creep.get_item_quality_ratio_on_death()\n\tvar item_quality_ratio_string: String = Utils.format_percent(item_quality_ratio, 0)\n\t_item_quality_ratio.set_text(item_quality_ratio_string)\n\n\tvar buff_duration: float = _creep.get_prop_buff_duration()\n\tvar buff_duration_string: String = Utils.format_percent(buff_duration, 0)\n\t_buff_duration.set_text(buff_duration_string)\n\n\tvar debuff_duration: float = _creep.get_prop_debuff_duration()\n\tvar debuff_duration_string: String = Utils.format_percent(debuff_duration, 0)\n\t_debuff_duration.set_text(debuff_duration_string)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_selected_unit_changed(_prev_unit: Unit):\n\tupdate_text()\n\n\nfunc _on_refresh_timer_timeout():\n\tif !visible:\n\t\treturn\n\t\n\tupdate_text()\n\n\nfunc _on_close_button_pressed():\n\thide()\n"
  },
  {
    "path": "src/ui/unit_menu/creep_details.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://b1l5uiun5nhhx\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_m73wp\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/creep_details.gd\" id=\"2_a46i7\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"3_6vdvx\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_gcimn\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_i86hr\"]\natlas = ExtResource(\"3_6vdvx\")\nregion = Rect2(896, 0, 128, 128)\n\n[node name=\"CreepDetails\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_creep_name_label\", \"_base_movespeed\", \"_movespeed_bonus\", \"_movespeed_bonus_perc\", \"_overall_movespeed\", \"_damage_reduction\", \"_base_armor\", \"_armor_bonus\", \"_armor_bonus_perc\", \"_overall_armor\", \"_dmg_from_astral\", \"_dmg_from_darkness\", \"_dmg_from_nature\", \"_dmg_from_ice\", \"_dmg_from_fire\", \"_dmg_from_storm\", \"_dmg_from_iron\", \"_dmg_from_attacks\", \"_dmg_from_spells\", \"_base_health\", \"_health_bonus\", \"_health_bonus_perc\", \"_overall_health\", \"_base_health_regen\", \"_health_regen_bonus\", \"_health_regen_bonus_perc\", \"_overall_health_regen\", \"_base_mana\", \"_mana_bonus\", \"_mana_bonus_perc\", \"_overall_mana\", \"_base_mana_regen\", \"_mana_regen_bonus\", \"_mana_regen_bonus_perc\", \"_overall_mana_regen\", \"_bounty_ratio\", \"_exp_ratio\", \"_item_drop_ratio\", \"_item_quality_ratio\", \"_buff_duration\", \"_debuff_duration\")]\ncustom_minimum_size = Vector2(500, 0)\nsize_flags_horizontal = 3\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_gcimn\")\nscript = ExtResource(\"2_a46i7\")\n_creep_name_label = NodePath(\"PanelContainer/VBoxContainer/CreepNameLabel\")\n_base_movespeed = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer/BaseMovespeed\")\n_movespeed_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer/MovespeedBonus\")\n_movespeed_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer/MovespeedBonusPerc\")\n_overall_movespeed = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer/OverallMovespeed\")\n_damage_reduction = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer/DamageReduction\")\n_base_armor = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer/BaseArmor\")\n_armor_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer/ArmorBonus\")\n_armor_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer/ArmorBonusPerc\")\n_overall_armor = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer/OverallArmor\")\n_dmg_from_astral = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromAstral\")\n_dmg_from_darkness = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromDarkness\")\n_dmg_from_nature = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromNature\")\n_dmg_from_ice = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromIce\")\n_dmg_from_fire = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromFire\")\n_dmg_from_storm = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromStorm\")\n_dmg_from_iron = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer/DmgFromIron\")\n_dmg_from_attacks = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DefenseContainer/DmgFromAttacks\")\n_dmg_from_spells = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DefenseContainer/DmgFromSpells\")\n_base_health = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/BaseHealth\")\n_health_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/HealthBonus\")\n_health_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/HealthBonusPerc\")\n_overall_health = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/OverallHealth\")\n_base_health_regen = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/BaseHealthRegen\")\n_health_regen_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/HealthRegenBonus\")\n_health_regen_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/HealthRegenBonusPerc\")\n_overall_health_regen = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer/OverallHealthRegen\")\n_base_mana = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseMana\")\n_mana_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/ManaBonus\")\n_mana_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/ManaBonusPerc\")\n_overall_mana = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/OverallMana\")\n_base_mana_regen = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseManaRegen\")\n_mana_regen_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/ManaRegenBonus\")\n_mana_regen_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/ManaRegenBonusPerc\")\n_overall_mana_regen = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/OverallManaRegen\")\n_bounty_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer/BountyRatio\")\n_exp_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer/ExpRatio\")\n_item_drop_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer/ItemDropRatio\")\n_item_quality_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer/ItemQualityRatio\")\n_buff_duration = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer/BuffDuration\")\n_debuff_duration = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer/DebuffDuration\")\n\n[node name=\"RefreshTimer\" type=\"Timer\" parent=\".\"]\nautostart = true\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\nlayout_mode = 2\ntheme = ExtResource(\"1_m73wp\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer\"]\nlayout_mode = 2\n\n[node name=\"CreepNameLabel\" type=\"Label\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"Creep Name\"\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0.901961, 0.537255, 0.0392157, 1)\ntext = \"CREEP_DETAILS_ARMOR\"\n\n[node name=\"ArmorContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BASE\"\n\n[node name=\"BaseArmor\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS\"\n\n[node name=\"ArmorBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_PST\"\n\n[node name=\"ArmorBonusPerc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_OVERALL\"\n\n[node name=\"OverallArmor\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label6\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_ARMOR_DMG_RDT\"\n\n[node name=\"DamageReduction\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/ArmorContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label4\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0.388235, 0.709804, 0, 1)\ntext = \"CREEP_DETAILS_DEFENSE\"\n\n[node name=\"DefenseContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DefenseContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_DEFENSE_DFA\"\n\n[node name=\"DmgFromAttacks\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DefenseContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DefenseContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_DEFENSE_DFS\"\n\n[node name=\"DmgFromSpells\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DefenseContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0.168627, 0.662745, 0.760784, 1)\ntext = \"CREEP_DETAILS_DEFENSE_DFE\"\n\n[node name=\"DamageFromElementContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_ASTRAL\"\n\n[node name=\"DmgFromAstral\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_DARKNESS\"\n\n[node name=\"DmgFromDarkness\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label4\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_NATURE\"\n\n[node name=\"DmgFromNature\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_ICE\"\n\n[node name=\"DmgFromIce\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label6\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_FIRE\"\n\n[node name=\"DmgFromFire\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label7\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_STORM\"\n\n[node name=\"DmgFromStorm\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label8\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\ntext = \"ELEMENT_IRON\"\n\n[node name=\"DmgFromIron\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/DamageFromElementContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"PanelContainer2\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0.858824, 0.254902, 0.219608, 1)\ntext = \"CREEP_DETAILS_HEALTH\"\n\n[node name=\"HealthContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BASE\"\n\n[node name=\"BaseHealth\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS\"\n\n[node name=\"HealthBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_PST\"\n\n[node name=\"HealthBonusPerc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_OVERALL\"\n\n[node name=\"OverallHealth\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label4\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BASE_REG\"\n\n[node name=\"BaseHealthRegen\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label6\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_REG\"\n\n[node name=\"HealthRegenBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label7\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_REG_PST\"\n\n[node name=\"HealthRegenBonusPerc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label8\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_OVERALL_REG\"\n\n[node name=\"OverallHealthRegen\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/HealthContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0.380392, 0.517647, 1, 1)\ntext = \"CREEP_DETAILS_MANA\"\n\n[node name=\"ManaContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BASE\"\n\n[node name=\"BaseMana\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS\"\n\n[node name=\"ManaBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_PST\"\n\n[node name=\"ManaBonusPerc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_OVERALL\"\n\n[node name=\"OverallMana\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label4\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BASE_REG\"\n\n[node name=\"BaseManaRegen\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label6\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_REG\"\n\n[node name=\"ManaRegenBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label7\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_REG_PST\"\n\n[node name=\"ManaRegenBonusPerc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label8\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_OVERALL_REG\"\n\n[node name=\"OverallManaRegen\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"PanelContainer3\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(0.415686, 0.596078, 0.996078, 1)\ntext = \"CREEP_DETAILS_MOV_SPEED\"\n\n[node name=\"MovespeedContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BASE\"\n\n[node name=\"BaseMovespeed\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS\"\n\n[node name=\"MovespeedBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BONUS_PST\"\n\n[node name=\"MovespeedBonusPerc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_OVERALL\"\n\n[node name=\"OverallMovespeed\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MovespeedContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer\"]\nlayout_mode = 2\ntheme_override_colors/font_color = Color(1, 0.843137, 0, 1)\ntext = \"CREEP_DETAILS_MISC\"\n\n[node name=\"MiscContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer\"]\nlayout_mode = 2\ncolumns = 2\n\n[node name=\"Label2\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BOUNTY_RAT\"\n\n[node name=\"BountyRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label3\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_EXP_RAT\"\n\n[node name=\"ExpRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label4\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_DROP_RAT\"\n\n[node name=\"ItemDropRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_QUALITY_RAT\"\n\n[node name=\"ItemQualityRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label6\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_BUFF_DUR\"\n\n[node name=\"BuffDuration\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"Label7\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\ntext = \"CREEP_DETAILS_DEBUFF_DUR\"\n\n[node name=\"DebuffDuration\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/VBoxContainer/MiscContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntext = \"123%\"\nhorizontal_alignment = 2\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nicon = SubResource(\"AtlasTexture_i86hr\")\nicon_alignment = 1\nexpand_icon = true\n\n[connection signal=\"timeout\" from=\"RefreshTimer\" to=\".\" method=\"_on_refresh_timer_timeout\"]\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/unit_menu/creep_mini_details.gd",
    "content": "class_name CreepMiniDetails extends TabContainer\n\n\n# Displays creep stats inside unit menu\n\nvar _creep: Creep = null\n\n@export var _stats_left_label: RichTextLabel\n@export var _stats_right_label: RichTextLabel\n@export var _dmg_left_label: RichTextLabel\n@export var _dmg_right_label: RichTextLabel\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_creep(creep: Creep):\n\t_creep = creep\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: this code consumes a lot of frametime so it needs to\n# be called sparingly. That's why it's not called every\n# frame in _process().\nfunc _update_labels():\n\tif _creep == null:\n\t\treturn\n\t\n\tvar stats_left_text: String = _get_stats_left_text()\n\t_stats_left_label.clear()\n\t_stats_left_label.append_text(stats_left_text)\n\t\n\tvar stats_right_text: String = _get_stats_right_text()\n\t_stats_right_label.clear()\n\t_stats_right_label.append_text(stats_right_text)\n\t\n\tvar dmg_left_text: String = _get_dmg_left_text()\n\t_dmg_left_label.clear()\n\t_dmg_left_label.append_text(dmg_left_text)\n\t\n\tvar dmg_right_text: String = _get_dmg_right_text()\n\t_dmg_right_label.clear()\n\t_dmg_right_label.append_text(dmg_right_text)\n\n\nfunc _get_stats_left_text() -> String:\n\tvar slow_amount: float = _creep.get_prop_move_speed() - 1.0\n\tvar slow_amount_string: String = Utils.format_percent(slow_amount, 0)\n\n\tvar overall_armor: float = _creep.get_overall_armor()\n\tvar overall_armor_string: String = Utils.format_float(overall_armor, 1)\n\n\tvar exp_ratio: float = _creep.get_prop_exp_granted()\n\tvar exp_ratio_string: String = Utils.format_percent(exp_ratio, 0)\n\n\tvar item_drop_ratio: float = _creep.get_item_drop_ratio_on_death()\n\tvar item_drop_ratio_string: String = Utils.format_percent(item_drop_ratio, 0)\n\t\n\tvar item_quality_ratio: float = _creep.get_item_quality_ratio_on_death()\n\tvar item_quality_ratio_string: String = Utils.format_percent(item_quality_ratio, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=6495ed]res://resources/icons/generic_icons/barefoot.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_SPEED\"), slow_amount_string] \\\n\t+ \"[hint=%s][img=30 color=d2b48c]res://resources/icons/generic_icons/abdominal_armor.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_ARMOR\"), overall_armor_string] \\\n\t+ \"[hint=%s][img=30 color=9630f0]res://resources/icons/generic_icons/moebius_trefoil.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_DETAILS_EXP_RAT\"), exp_ratio_string] \\\n\t+ \"[hint=%s][img=30 color=bcde35]res://resources/icons/generic_icons/polar_star.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_DETAILS_DROP_RAT\"), item_drop_ratio_string] \\\n\t+ \"[hint=%s][img=30 color=bcde35]res://resources/icons/generic_icons/gold_bar.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_DETAILS_QUALITY_RAT\"), item_quality_ratio_string] \\\n\t+ \"\"\n\t\n\treturn text\n\n\nfunc _get_stats_right_text() -> String:\n\tvar overall_health_regen: float = _creep.get_overall_health_regen()\n\tvar overall_health_regen_string: String = Utils.format_float(overall_health_regen, 1)\n\n\tvar overall_mana_regen: float = _creep.get_overall_mana_regen()\n\tvar overall_mana_regen_string: String = Utils.format_float(overall_mana_regen, 1)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=32cd32]res://resources/icons/generic_icons/rolling_energy.tres[/img] %s/s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_HEALTH_REGEN\"), overall_health_regen_string] \\\n\t+ \"[hint=%s][img=30 color=31cde8]res://resources/icons/generic_icons/rolling_energy.tres[/img] %s/s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_MANA_REGEN\"), overall_mana_regen_string] \\\n\t+ \"\"\n\t\n\treturn text\n\n\nfunc _get_dmg_left_text() -> String:\n\tvar attack_damage_received: float = _creep.get_prop_atk_damage_received()\n\tvar attack_damage_received_string: String = Utils.format_percent(attack_damage_received, 0)\n\n\tvar spell_damage_received: float = _creep.get_prop_spell_damage_received()\n\tvar spell_damage_received_string: String = Utils.format_percent(spell_damage_received, 0)\n\t\n\tvar dmg_from_ice: float = _creep.get_damage_from_element(Element.enm.ICE)\n\tvar dmg_from_ice_string: String = Utils.format_percent(dmg_from_ice, 0)\n\tvar dmg_from_nature: float = _creep.get_damage_from_element(Element.enm.NATURE)\n\tvar dmg_from_nature_string: String = Utils.format_percent(dmg_from_nature, 0)\n\n\tvar dmg_from_fire: float = _creep.get_damage_from_element(Element.enm.FIRE)\n\tvar dmg_from_fire_string: String = Utils.format_percent(dmg_from_fire, 0)\n\n\tvar dmg_from_astral: float = _creep.get_damage_from_element(Element.enm.ASTRAL)\n\tvar dmg_from_astral_string: String = Utils.format_percent(dmg_from_astral, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=eb4f34]res://resources/icons/generic_icons/hammer_drop.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_ATTACK_DAMAGE_RECEIVED\"), attack_damage_received_string] \\\n\t+ \"[hint=%s][img=30 color=31e896]res://resources/icons/generic_icons/flame.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_SPELL_DAMAGE_RECEIVED\"), spell_damage_received_string] \\\n\t+ \"[hint=%s][img=30 color=6495ed]res://resources/icons/generic_icons/azul_flake.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_ICE\"), dmg_from_ice_string] \\\n\t+ \"[hint=%s][img=30 color=32cd32]res://resources/icons/generic_icons/root_tip.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_NATURE\"), dmg_from_nature_string] \\\n\t+ \"[hint=%s][img=30 color=ff4500]res://resources/icons/generic_icons/flame.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_FIRE\"), dmg_from_fire_string] \\\n\t+ \"[hint=%s][img=30 color=66cdaa]res://resources/icons/generic_icons/star_swirl.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_ASTRAL\"), dmg_from_astral_string] \\\n\t+ \"\"\n\t\n\treturn text\n\n\nfunc _get_dmg_right_text() -> String:\n\tvar dmg_from_darkness: float = _creep.get_damage_from_element(Element.enm.DARKNESS)\n\tvar dmg_from_darkness_string: String = Utils.format_percent(dmg_from_darkness, 0)\n\n\tvar dmg_from_iron: float = _creep.get_damage_from_element(Element.enm.IRON)\n\tvar dmg_from_iron_string: String = Utils.format_percent(dmg_from_iron, 0)\n\n\tvar dmg_from_storm: float = _creep.get_damage_from_element(Element.enm.STORM)\n\tvar dmg_from_storm_string: String = Utils.format_percent(dmg_from_storm, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=9370db]res://resources/icons/generic_icons/animal_skull.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_DARKNESS\"), dmg_from_darkness_string] \\\n\t+ \"[hint=%s][img=30 color=d2b48c]res://resources/icons/generic_icons/pokecog.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_IRON\"), dmg_from_iron_string] \\\n\t+ \"[hint=%s][img=30 color=ffffe0]res://resources/icons/generic_icons/rolling_energy.tres[/img] %s[/hint]\\n\" % [tr(\"CREEP_MINI_DETAILS_DAMAGE_FROM_STORM\"), dmg_from_storm_string] \\\n\t+ \"\"\n\t\n\treturn text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_update_timer_timeout() -> void:\n\t_update_labels()\n\n\nfunc _on_visibility_changed() -> void:\n\t_update_labels()\n"
  },
  {
    "path": "src/ui/unit_menu/creep_mini_details.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://bkknomxku1jcv\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/creep_mini_details.gd\" id=\"1_0rr73\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b5kapr6gujqbt\" path=\"res://src/ui/unit_menu/mini_details_label.tscn\" id=\"2_swo34\"]\n\n[node name=\"CreepMiniDetails\" type=\"TabContainer\" node_paths=PackedStringArray(\"_stats_left_label\", \"_stats_right_label\", \"_dmg_left_label\", \"_dmg_right_label\")]\ncustom_minimum_size = Vector2(400, 300)\nsize_flags_vertical = 8\ncurrent_tab = 0\ntab_focus_mode = 0\nscript = ExtResource(\"1_0rr73\")\n_stats_left_label = NodePath(\"CREEP_MINI_DETAILS_STATS/StatsLeftLabel\")\n_stats_right_label = NodePath(\"CREEP_MINI_DETAILS_STATS/StatsRightLabel\")\n_dmg_left_label = NodePath(\"CREEP_MINI_DETAILS_DMG/DmgLeftLabel\")\n_dmg_right_label = NodePath(\"CREEP_MINI_DETAILS_DMG/DmgRightLabel\")\n\n[node name=\"UpdateTimer\" type=\"Timer\" parent=\".\"]\nautostart = true\n\n[node name=\"CREEP_MINI_DETAILS_STATS\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\nmetadata/_tab_index = 0\n\n[node name=\"StatsLeftLabel\" parent=\"CREEP_MINI_DETAILS_STATS\" instance=ExtResource(\"2_swo34\")]\nlayout_mode = 2\n\n[node name=\"StatsRightLabel\" parent=\"CREEP_MINI_DETAILS_STATS\" instance=ExtResource(\"2_swo34\")]\nlayout_mode = 2\n\n[node name=\"CREEP_MINI_DETAILS_DMG\" type=\"HBoxContainer\" parent=\".\"]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 1\n\n[node name=\"DmgLeftLabel\" parent=\"CREEP_MINI_DETAILS_DMG\" instance=ExtResource(\"2_swo34\")]\nlayout_mode = 2\n\n[node name=\"DmgRightLabel\" parent=\"CREEP_MINI_DETAILS_DMG\" instance=ExtResource(\"2_swo34\")]\nlayout_mode = 2\n\n[connection signal=\"visibility_changed\" from=\".\" to=\".\" method=\"_on_visibility_changed\"]\n[connection signal=\"timeout\" from=\"UpdateTimer\" to=\".\" method=\"_on_update_timer_timeout\"]\n"
  },
  {
    "path": "src/ui/unit_menu/item_container_panel.gd",
    "content": "class_name ItemContainerPanel extends MarginContainer\n\n\n# Displays contents of an item container and allows moving items within container.\n# Intended for item containers with limited capacity (tower inventory, horadric cube). Should not be used for item stash because it is\n# scrollable and infinite.\n\n\nvar _item_container: ItemContainer = null\n\n\n@export var _button_tooltip_location: ButtonTooltip.Location = ButtonTooltip.Location.BOTTOM\n@export var show_slot_borders: bool = true\n@export var _show_horadric_lock: bool = true\n@export var _background_grid: GridContainer\n@export var _slot_grid: GridContainer\n@export var _item_grid: GridContainer\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\tvar item_button_list: Array[Node] = _item_grid.get_children()\n\tfor button in item_button_list:\n#\t\tNOTE: show button, it's hidden in scene so that it doesn't animate in editor\n\t\tbutton.show()\n\t\t\n\t\tbutton.set_tooltip_location(_button_tooltip_location)\n\t\tbutton.set_horadric_lock_visible(_show_horadric_lock)\n\t\tbutton.pressed.connect(_on_item_button_pressed.bind(button))\n\t\tbutton.shift_right_clicked.connect(_on_item_button_shift_right_clicked.bind(button))\n\t\tbutton.right_clicked.connect(_on_item_button_right_clicked.bind(button))\n\t\tvar item_button = button as ItemButton\n\t\titem_button.ctrl_right_clicked.connect(_on_item_button_ctrl_right_clicked.bind(item_button))\n\n\tvar slot_button_list: Array[Node] = _slot_grid.get_children()\n\tfor button in slot_button_list:\n\t\tif !show_slot_borders:\n\t\t\tbutton.modulate = Color.TRANSPARENT\n\n\t_update_buttons()\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_item_container(item_container: ItemContainer):\n\tvar prev_item_container: ItemContainer = _item_container\n\t_item_container = item_container\n\t\n\tvar item_container_is_tower_inventory: bool = _item_container != null && _item_container is TowerItemContainer\n\t\n\tvar item_button_list: Array = _item_grid.get_children()\n\tfor button in item_button_list:\n\t\tbutton.set_cooldown_indicator_visible(true)\n\t\tbutton.set_auto_mode_indicator_visible(item_container_is_tower_inventory)\n\t\tbutton.set_charges_visible(true)\n\t\n\tif prev_item_container != null:\n\t\tprev_item_container.items_changed.disconnect(_on_items_changed)\n\n\tif _item_container != null:\n\t\titem_container.items_changed.connect(_on_items_changed)\n\t\n\t_update_buttons()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _on_item_button_ctrl_right_clicked(item_button: ItemButton):\n\tvar item: Item = item_button.get_item()\n\titem.toggle_horadric_lock()\n\n\nfunc _update_buttons():\n\tvar inventory_capacity: int\n\tif _item_container != null:\n\t\tinventory_capacity = _item_container.get_capacity()\n\telse:\n\t\tinventory_capacity = 0\n\n#\tUpdate color of background cells based on capacity\n\tvar background_button_list: Array[Node] = _background_grid.get_children()\n\tfor background_button in background_button_list:\n\t\tvar index: int = background_button.get_index()\n\t\tvar within_capacity: bool = index < inventory_capacity\n\t\n\t\tvar background_color: Color\n\t\tif within_capacity:\n\t\t\tbackground_color = Color.WHITE\n\t\telse:\n\t\t\tbackground_color = Color.WHITE.darkened(0.6)\n\t\t\n\t\tbackground_button.modulate = background_color\n\n\tvar slot_button_list: Array[Node] = _slot_grid.get_children()\n\tfor slot_button in slot_button_list:\n\t\tvar slot_is_within_capacity: bool = slot_button.get_index() < inventory_capacity\n\t\tslot_button.visible = slot_is_within_capacity\n\n\tvar item_button_list: Array[Node] = _item_grid.get_children()\n\tfor item_button in item_button_list:\n\t\tvar index: int = item_button.get_index()\n\n\t\tvar item: Item\n\t\tif _item_container != null:\n\t\t\titem = _item_container.get_item_at_index(index)\n\t\telse:\n\t\t\titem = null\n\n\t\titem_button.set_item(item)\n\t\n\nfunc _process_click_on_generic_button(button: Button):\n\tvar clicked_index: int = button.get_index()\n\tEventBus.player_clicked_in_item_container.emit(_item_container, clicked_index)\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_items_changed():\n\t_update_buttons()\n\n\nfunc _on_item_button_pressed(item_button: ItemButton):\n\t_process_click_on_generic_button(item_button)\n\n\nfunc _on_slot_button_pressed(button: Button):\n\t_process_click_on_generic_button(button)\n\n\nfunc _on_item_button_right_clicked(item_button: ItemButton):\n\tvar item: Item = item_button.get_item()\n\tEventBus.player_right_clicked_item.emit(item)\n\n\nfunc _on_item_button_shift_right_clicked(item_button: ItemButton):\n\tvar item: Item = item_button.get_item()\n\tEventBus.player_shift_right_clicked_item.emit(item)\n"
  },
  {
    "path": "src/ui/unit_menu/item_container_panel.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://beu73m131qhyk\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_663hy\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/item_container_panel.gd\" id=\"2_uxpon\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8xsklkw4jhlw\" path=\"res://src/ui/buttons/empty_unit_button.tscn\" id=\"3_6p1q1\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://fwj77pscccxg\" path=\"res://src/ui/buttons/inventory_slot_button.tscn\" id=\"4_mvykn\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://cj8l153f630bb\" path=\"res://src/ui/buttons/item_button.tscn\" id=\"5_22vk1\"]\n\n[node name=\"ItemContainerPanel\" type=\"MarginContainer\" node_paths=PackedStringArray(\"_background_grid\", \"_slot_grid\", \"_item_grid\")]\ntheme = ExtResource(\"1_663hy\")\nscript = ExtResource(\"2_uxpon\")\n_background_grid = NodePath(\"BackgroundGrid\")\n_slot_grid = NodePath(\"SlotGrid\")\n_item_grid = NodePath(\"ItemGrid\")\n\n[node name=\"BackgroundGrid\" type=\"GridContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 4\ntheme_override_constants/v_separation = 4\ncolumns = 3\n\n[node name=\"EmptyUnitButton\" parent=\"BackgroundGrid\" instance=ExtResource(\"3_6p1q1\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton2\" parent=\"BackgroundGrid\" instance=ExtResource(\"3_6p1q1\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton3\" parent=\"BackgroundGrid\" instance=ExtResource(\"3_6p1q1\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton4\" parent=\"BackgroundGrid\" instance=ExtResource(\"3_6p1q1\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton5\" parent=\"BackgroundGrid\" instance=ExtResource(\"3_6p1q1\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton6\" parent=\"BackgroundGrid\" instance=ExtResource(\"3_6p1q1\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"SlotGrid\" type=\"GridContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 4\ntheme_override_constants/v_separation = 4\ncolumns = 3\n\n[node name=\"InventorySlotButton\" parent=\"SlotGrid\" instance=ExtResource(\"4_mvykn\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"InventorySlotButton2\" parent=\"SlotGrid\" instance=ExtResource(\"4_mvykn\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"InventorySlotButton3\" parent=\"SlotGrid\" instance=ExtResource(\"4_mvykn\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"InventorySlotButton4\" parent=\"SlotGrid\" instance=ExtResource(\"4_mvykn\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"InventorySlotButton5\" parent=\"SlotGrid\" instance=ExtResource(\"4_mvykn\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"InventorySlotButton6\" parent=\"SlotGrid\" instance=ExtResource(\"4_mvykn\")]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\n\n[node name=\"ItemGrid\" type=\"GridContainer\" parent=\".\"]\nlayout_mode = 2\ntheme_override_constants/h_separation = 4\ntheme_override_constants/v_separation = 4\ncolumns = 3\n\n[node name=\"ItemButton\" parent=\"ItemGrid\" instance=ExtResource(\"5_22vk1\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"ItemButton2\" parent=\"ItemGrid\" instance=ExtResource(\"5_22vk1\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"ItemButton3\" parent=\"ItemGrid\" instance=ExtResource(\"5_22vk1\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"ItemButton4\" parent=\"ItemGrid\" instance=ExtResource(\"5_22vk1\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"ItemButton5\" parent=\"ItemGrid\" instance=ExtResource(\"5_22vk1\")]\nvisible = false\nlayout_mode = 2\n\n[node name=\"ItemButton6\" parent=\"ItemGrid\" instance=ExtResource(\"5_22vk1\")]\nvisible = false\nlayout_mode = 2\n"
  },
  {
    "path": "src/ui/unit_menu/mini_details_label.tscn",
    "content": "[gd_scene format=3 uid=\"uid://b5kapr6gujqbt\"]\n\n[node name=\"MiniDetailsLlabel\" type=\"RichTextLabel\"]\nsize_flags_horizontal = 3\nsize_flags_vertical = 3\ntheme_override_constants/line_separation = 4\nbbcode_enabled = true\ntext = \"[img=25 color=ff0000]res://resources/icons/generic_icons/alligator_clip.tres[/img] 32\n[img=25]res://resources/icons/generic_icons/open_wound.tres[/img] 1.2\n[img=25 color=0aff0a\n]res://resources/icons/generic_icons/alligator_clip.tres[/img] 32\n[img=25]res://resources/icons/generic_icons/open_wound.tres[/img] 1.2\n[img=25\n]res://resources/icons/generic_icons/alligator_clip.tres[/img] 32\n[img=25]res://resources/icons/generic_icons/open_wound.tres[/img] 1.2\"\nscroll_active = false\nhint_underlined = false\n"
  },
  {
    "path": "src/ui/unit_menu/progress_bar_with_label.gd",
    "content": "class_name ProgressBarWithLabel extends ProgressBar\n\n\n# Simple progress bar with label. Need this because the default ProgressBar only allows showing percentage.\n\n\n@export var _label: Label\n\n\nfunc set_text(text: String):\n\t_label.text = text\n\n\n# This function makes sure that the text will fit into the\n# width of the progress bar\nfunc set_ratio_custom(left: int, right: int):\n\tvar left_string: String = TowerDetails.int_format_shortest(left)\n\tvar right_string: String = TowerDetails.int_format_shortest(right)\n\tvar text: String = \"%s/%s\" % [left_string, right_string]\n\tset_text(text)\n\n\tvar value_ratio: float = Utils.divide_safe(left, right)\n\tvalue_ratio = clampf(value_ratio, 0.0, 1.0)\n\tset_as_ratio(value_ratio)\n"
  },
  {
    "path": "src/ui/unit_menu/progress_bar_with_label.tscn",
    "content": "[gd_scene load_steps=5 format=3 uid=\"uid://bscc3lifv4bx4\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/progress_bar_with_label.gd\" id=\"1_cdogi\"]\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"2_78qlh\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://cefr72vfj04ja\" path=\"res://resources/theme/unit_menu/mana_bar_background.tres\" id=\"2_dcp3a\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://rku7yxxl0iit\" path=\"res://resources/theme/unit_menu/mana_bar_fill.tres\" id=\"3_dyv6x\"]\n\n[node name=\"ProgressBarWithLabel\" type=\"ProgressBar\" node_paths=PackedStringArray(\"_label\")]\ncustom_minimum_size = Vector2(100, 25)\ntheme = ExtResource(\"2_78qlh\")\ntheme_override_styles/background = ExtResource(\"2_dcp3a\")\ntheme_override_styles/fill = ExtResource(\"3_dyv6x\")\nvalue = 30.0\nshow_percentage = false\nscript = ExtResource(\"1_cdogi\")\n_label = NodePath(\"MarginContainer/Label\")\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\".\"]\nlayout_mode = 1\nanchors_preset = 15\nanchor_right = 1.0\nanchor_bottom = 1.0\ngrow_horizontal = 2\ngrow_vertical = 2\ntheme_override_constants/margin_top = 5\n\n[node name=\"Label\" type=\"Label\" parent=\"MarginContainer\"]\nlayout_mode = 2\ntheme = ExtResource(\"2_78qlh\")\ntheme_type_variation = &\"LabelSmall\"\ntext = \"30/100\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n"
  },
  {
    "path": "src/ui/unit_menu/tower_details.gd",
    "content": "class_name TowerDetails extends PanelContainer\n\n# Displays detailed information about the stats of the\n# currently selected tower. Can be toggled in unit menu by\n# pressing the \"info\" button.\n\n\n@export var _tower_name_label: Label\n\n# Attack\n@export var _base_damage: Label\n@export var _base_damage_bonus: Label\n@export var _base_damage_bonus_perc: Label\n@export var _damage_add: Label\n@export var _damage_add_perc: Label\n@export var _overall_damage: Label\n@export var _base_attack_speed: Label\n@export var _attack_speed_modifier: Label\n@export var _overall_attack_speed: Label\n@export var _overall_dps: Label\n@export var _crit_chance: Label\n@export var _crit_damage: Label\n@export var _multicrit: Label\n@export var _dps_with_crit: Label\n\n# Spells\n@export var _spell_damage: Label\n@export var _spell_crit_chance: Label\n@export var _spell_crit_damage: Label\n\n# Veteran\n@export var _total_damage: Label\n@export var _total_damage_recent: Label\n@export var _best_hit: Label\n@export var _kills: Label\n@export var _experience: Label\n@export var _level_x_at_left: Label\n@export var _level_x_at_right: Label\n\n# Mana\n@export var _base_mana: Label\n@export var _mana_bonus: Label\n@export var _mana_bonus_perc: Label\n@export var _overall_mana: Label\n@export var _base_mana_regen: Label\n@export var _mana_regen_bonus: Label\n@export var _mana_regen_bonus_perc: Label\n@export var _overall_mana_regen: Label\n\n# Misc\n@export var _bounty_ratio: Label\n@export var _exp_ratio: Label\n@export var _item_drop_ratio: Label\n@export var _item_quality_ratio: Label\n@export var _trigger_chances: Label\n@export var _buff_duration: Label\n@export var _debuff_duration: Label\n\n# Damage to race\n@export var _dmg_to_undead: Label\n@export var _dmg_to_magical: Label\n@export var _dmg_to_nature: Label\n@export var _dmg_to_orc: Label\n@export var _dmg_to_humanoid: Label\n@export var _dmg_to_challenge: Label\n\n# Damage to size\n@export var _dmg_to_mass: Label\n@export var _dmg_to_normal: Label\n@export var _dmg_to_air: Label\n@export var _dmg_to_champion: Label\n@export var _dmg_to_boss: Label\n\n@export var _total_dmg_multiplier: Label\n\n# Details\n@export var _tower_details_label: RichTextLabel\n\nvar _tower: Tower = null\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_tower(tower: Tower):\n\t_tower = tower\n\tupdate_text()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc update_text():\n\tif _tower == null:\n\t\treturn\n\n#\tNOTE: don't set tooltips for towers that haven't been\n#\tadded to scene tree yet because their _ready() functions\n#\thaven't been called so they aren't setup completely.\n#\tThis can happen while hovering over tower build buttons.\n\tif !_tower.is_inside_tree():\n\t\treturn\n\n\tvar tower_id: int = _tower.get_id()\n\tvar tower_name: String = TowerProperties.get_display_name(tower_id)\n\t_tower_name_label.text = tower_name\n\n#\tAttack\n\tvar base_damage: int = roundi(_tower.get_current_attack_damage_base())\n\t_base_damage.text = TowerDetails.int_format(base_damage)\n\n\tvar base_damage_bonus: int = roundi(_tower.get_base_damage_bonus())\n\t_base_damage_bonus.text = TowerDetails.int_format(base_damage_bonus)\n\n\tvar base_damage_bonus_perc: float = _tower.get_base_damage_bonus_percent() - 1.0\n\t_base_damage_bonus_perc.text = TowerDetails.percent_signed_format(base_damage_bonus_perc)\n\n#\tNOTE: it's intentional that damage_add shows \"overall\"\n#\tdamage_add, which includes bonus from MOD_DPS_ADD. This\n#\tis how it works in original game.\n\tvar damage_add_overall: int = roundi(_tower.get_damage_add_overall())\n\t_damage_add.text = TowerDetails.int_format(damage_add_overall)\n\n\tvar damage_add_perc: float = _tower.get_damage_add_percent() - 1.0\n\t_damage_add_perc.text = TowerDetails.percent_signed_format(damage_add_perc)\n\n\tvar overall_damage: int = roundi(_tower.get_current_attack_damage_with_bonus())\n\t_overall_damage.text = TowerDetails.int_format(overall_damage)\n\n\tvar base_attack_speed: float = _tower.get_base_attack_speed()\n\t_base_attack_speed.text = Utils.format_float(base_attack_speed, 2)\n\n\tvar attack_speed_modifier: float = _tower.get_attack_speed_modifier()\n\t_attack_speed_modifier.text = Utils.format_percent(attack_speed_modifier, 0)\n\n\tvar overall_attack_speed: float = _tower.get_current_attack_speed()\n\t_overall_attack_speed.text = Utils.format_float(overall_attack_speed, 2)\n\n\tvar overall_dps: int = roundi(_tower.get_overall_dps())\n\t_overall_dps.text = TowerDetails.int_format(overall_dps)\n\n\tvar crit_chance: float = _tower.get_prop_atk_crit_chance()\n\t_crit_chance.text = Utils.format_percent(crit_chance, 1)\n\n\tvar crit_damage: float = _tower.get_prop_atk_crit_damage()\n\t_crit_damage.text = TowerDetails.multiplier_format(crit_damage)\n\n\tvar multicrit: int = _tower.get_prop_multicrit_count()\n\t_multicrit.text = TowerDetails.int_format(multicrit)\n\n\tvar dps_with_crit: int = roundi(_tower.get_dps_with_crit())\n\t_dps_with_crit.text = TowerDetails.int_format(dps_with_crit)\n\n#\tSpells\n\tvar spell_damage: float = _tower.get_prop_spell_damage_dealt()\n\t_spell_damage.text = Utils.format_percent(spell_damage, 0)\n\t\n\tvar spell_crit_chance: float = _tower.get_spell_crit_chance()\n\t_spell_crit_chance.text = Utils.format_percent(spell_crit_chance, 1)\n\n\tvar spell_crit_damage: float = _tower.get_spell_crit_damage()\n\t_spell_crit_damage.text = TowerDetails.multiplier_format(spell_crit_damage)\n\n#\tVeteran\n\tvar total_damage: int = roundi(_tower.get_total_damage())\n\t_total_damage.text = TowerDetails.int_format(total_damage)\n\t\n\tvar total_damage_recent: int = roundi(_tower.get_total_damage_recent())\n\t_total_damage_recent.text = TowerDetails.int_format(total_damage_recent)\n\n\tvar best_hit: int = roundi(_tower.get_best_hit())\n\t_best_hit.text = TowerDetails.int_format(best_hit)\n\n\tvar kills: int = _tower.get_kills()\n\t_kills.text = TowerDetails.int_format(kills)\n\n\tvar experience: int = floori(_tower.get_exp())\n\t_experience.text = TowerDetails.int_format(experience)\n\n\tvar next_level: int = _tower.get_level() + 1\n\tvar exp_for_next_level: int = Experience.get_exp_for_level(next_level)\n\t\n\tif _tower.reached_max_level():\n\t\t_level_x_at_left.text = tr(\"MAX_LVL_REACHED\")\n\t\t_level_x_at_right.text = \"\"\n\telse:\n\t\t_level_x_at_left.text = tr(\"LEVEL_AT_LABEL\").format({NEXT_LEVEL = next_level})\n\t\t_level_x_at_right.text = TowerDetails.int_format(exp_for_next_level)\n\n# \tMana\n\tvar base_mana: int = floori(_tower.get_base_mana())\n\t_base_mana.text = TowerDetails.int_format(base_mana)\n\n\tvar mana_bonus: int = floori(_tower.get_base_mana_bonus())\n\t_mana_bonus.text = TowerDetails.int_format(mana_bonus)\n\n\tvar mana_bonus_perc: float = _tower.get_base_mana_bonus_percent() - 1.0\n\t_mana_bonus_perc.text = TowerDetails.percent_signed_format(mana_bonus_perc)\n\n\tvar overall_mana: int = floori(_tower.get_overall_mana())\n\t_overall_mana.text = TowerDetails.int_format(overall_mana)\n\n\tvar base_mana_regen: float = _tower.get_base_mana_regen()\n\t_base_mana_regen.text = Utils.format_float(base_mana_regen, 1)\n\n\tvar mana_regen_bonus: float = _tower.get_base_mana_regen_bonus()\n\t_mana_regen_bonus.text = Utils.format_float(mana_regen_bonus, 1)\n\n\tvar mana_regen_bonus_perc: float = _tower.get_base_mana_regen_bonus_percent() - 1.0\n\t_mana_regen_bonus_perc.text = TowerDetails.percent_signed_format(mana_regen_bonus_perc)\n\n\tvar overall_mana_regen: float = _tower.get_overall_mana_regen()\n\t_overall_mana_regen.text = Utils.format_float(overall_mana_regen, 1)\n\n#\tMisc\n\tvar bounty_ratio: float = _tower.get_prop_bounty_received()\n\t_bounty_ratio.text = Utils.format_percent(bounty_ratio, 0)\n\n\tvar exp_ratio: float = _tower.get_prop_exp_received()\n\t_exp_ratio.text = Utils.format_percent(exp_ratio, 0)\n\n\tvar item_drop_ratio: float = _tower.get_item_drop_ratio()\n\t_item_drop_ratio.text = Utils.format_percent(item_drop_ratio, 0)\n\n\tvar item_quality_ratio: float = _tower.get_item_quality_ratio()\n\t_item_quality_ratio.text = Utils.format_percent(item_quality_ratio, 0)\n\n\tvar trigger_chances: float = _tower.get_prop_trigger_chances()\n\t_trigger_chances.text = Utils.format_percent(trigger_chances, 0)\n\n\tvar buff_duration: float = _tower.get_prop_buff_duration()\n\t_buff_duration.text = Utils.format_percent(buff_duration, 0)\n\n\tvar debuff_duration: float = _tower.get_prop_debuff_duration()\n\t_debuff_duration.text = Utils.format_percent(debuff_duration, 0)\n\n#\tDamage to race\n\tvar dmg_to_undead: float = _tower.get_damage_to_undead()\n\t_dmg_to_undead.text = Utils.format_percent(dmg_to_undead, 0)\n\n\tvar dmg_to_magical: float = _tower.get_damage_to_magic()\n\t_dmg_to_magical.text = Utils.format_percent(dmg_to_magical, 0)\n\n\tvar dmg_to_nature: float = _tower.get_damage_to_nature()\n\t_dmg_to_nature.text = Utils.format_percent(dmg_to_nature, 0)\n\n\tvar dmg_to_orc: float = _tower.get_damage_to_orc()\n\t_dmg_to_orc.text = Utils.format_percent(dmg_to_orc, 0)\n\n\tvar dmg_to_humanoid: float = _tower.get_damage_to_humanoid()\n\t_dmg_to_humanoid.text = Utils.format_percent(dmg_to_humanoid, 0)\n\t\n\tvar dmg_to_challenge: float = _tower.get_damage_to_challenge()\n\t_dmg_to_challenge.text = Utils.format_percent(dmg_to_challenge, 0)\n\t\n#\tDamage to size\n\tvar dmg_to_mass: float = _tower.get_damage_to_mass()\n\t_dmg_to_mass.text = Utils.format_percent(dmg_to_mass, 0)\n\n\tvar dmg_to_normal: float = _tower.get_damage_to_normal()\n\t_dmg_to_normal.text = Utils.format_percent(dmg_to_normal, 0)\n\n\tvar dmg_to_air: float = _tower.get_damage_to_air()\n\t_dmg_to_air.text = Utils.format_percent(dmg_to_air, 0)\n\n\tvar dmg_to_champion: float = _tower.get_damage_to_champion()\n\t_dmg_to_champion.text = Utils.format_percent(dmg_to_champion, 0)\n\n\tvar dmg_to_boss: float = _tower.get_damage_to_boss()\n\t_dmg_to_boss.text = Utils.format_percent(dmg_to_boss, 0)\n\t\n\tvar total_dmg_multiplier: float = _tower.get_total_damage_multiplier()\n\t_total_dmg_multiplier.text = Utils.format_percent(total_dmg_multiplier, 0)\n\t\n#\tDetails\n\tvar tower_details_text: String = _get_tower_details_text(_tower)\n\t_tower_details_label.clear()\n\t_tower_details_label.append_text(tower_details_text)\n\n\n# Formats numbers which can go above million and need to be\n# shortened.\n# Examples:\n# 1340 = \"1,340\"\n# 1340000 = \"1.34M\"\n# 1340000000 = \"1.34G\"\nstatic func int_format(num: float) -> String:\n\t# Determine the appropriate suffix for the number\n\tvar suffix = \"\"\n\tif num >= 1_000_000_000_000_000:\n\t\tnum /= 1_000_000_000_000_000\n\t\tsuffix = \"Q\"\n\telif num >= 1_000_000_000_000:\n\t\tnum /= 1_000_000_000_000\n\t\tsuffix = \"T\"\n\telif num >= 1_000_000_000:\n\t\tnum /= 1_000_000_000\n\t\tsuffix = \"G\"\n\telif num >= 1_000_000:\n\t\tnum /= 1_000_000\n\t\tsuffix = \"M\"\n\n\t# Convert the number to a string and handle the fractional part\n\tvar num_str = \"\"\n\tif num >= 1:\n\t\tnum_str = str(int(num))\n\telse:\n\t\tnum_str = \"0\"\n\tvar frac_str = \"\"\n\tif suffix != \"\":\n\t\tvar num_float_str: String = Utils.format_float(num, 2)\n\t\tif num_float_str.contains(\".\"):\n\t\t\tvar num_float_str_split: Array = num_float_str.split(\".\")\n\t\t\tfrac_str = \".%s\" % num_float_str_split[1]\n\n\t# Add commas to the integer part of the number\n\tvar digits = num_str.length()\n\tfor i in range(digits - 3, 0, -3):\n\t\tnum_str = num_str.insert(i, \",\")\n\t\n\t# Combine the integer part, fractional part, and suffix into the final string\n\treturn num_str + frac_str + suffix\n\n\n# This variant shortens thousands as well and doesn't\n# include fractional part.\nstatic func int_format_shortest(num: float) -> String:\n\t# Determine the appropriate suffix for the number\n\tvar suffix = \"\"\n\tif num >= 1_000_000_000_000_000:\n\t\tnum /= 1_000_000_000_000_000\n\t\tsuffix = \"Q\"\n\telif num >= 1_000_000_000_000:\n\t\tnum /= 1_000_000_000_000\n\t\tsuffix = \"T\"\n\telif num >= 1_000_000_000:\n\t\tnum /= 1_000_000_000\n\t\tsuffix = \"G\"\n\telif num >= 1_000_000:\n\t\tnum /= 1_000_000\n\t\tsuffix = \"M\"\n\telif num >= 1_000:\n\t\tnum /= 1_000\n\t\tsuffix = \"K\"\n\n\tvar num_str = \"\"\n\tif num >= 1:\n\t\tnum_str = str(int(num))\n\telse:\n\t\tnum_str = \"0\"\n\t\n\treturn num_str + suffix\n\n\nstatic func percent_signed_format(number: float) -> String:\n\tvar formatted: String = Utils.format_percent(number, 0)\n\n\tif int(number) > 0:\n\t\tformatted = \"+%s\" % formatted\n\n\treturn formatted\n\n\nstatic func multiplier_format(number) -> String:\n\treturn \"x%.2f\" % number\n\n\nstatic func float_format(number) -> String:\n\treturn Utils.format_float(number, 2)\n\n\nfunc _get_tower_details_text(tower: Tower) -> String:\n\tvar text: String = \"\"\n\t\n\tvar tower_multiboard: MultiboardValues = tower.on_tower_details()\n\tvar item_multiboard_list: Array[MultiboardValues] = tower.get_item_tower_details()\n\n\tvar all_multiboard_list: Array[MultiboardValues] = item_multiboard_list\n\tall_multiboard_list.insert(0, tower_multiboard)\n\n\ttext += \"[color=GOLD]%s[/color]\\n \\n\" % tr(\"TOWER_DETAILS_TITLE\")\n\n\ttext += \"[table=2]\"\n\n\tfor multiboard in all_multiboard_list:\n\t\tfor row in range(0, multiboard.size()):\n\t\t\tvar key: String = multiboard.get_key(row)\n\t\t\tvar value: String = multiboard.get_value(row)\n\n\t\t\ttext += \"[cell]%s:[/cell][cell]%s[/cell]\\n\" % [key, value]\n\n\ttext += \"[/table]\"\n\n\treturn text\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_refresh_timer_timeout():\n\tif !visible:\n\t\treturn\n\t\n\tupdate_text()\n\n\nfunc _on_close_button_pressed():\n\thide()\n"
  },
  {
    "path": "src/ui/unit_menu/tower_details.tscn",
    "content": "[gd_scene load_steps=6 format=3 uid=\"uid://b6l4hi00yx7js\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_p3jli\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/tower_details.gd\" id=\"2_arilw\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"3_3n5aj\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_w837r\"]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_ipd82\"]\natlas = ExtResource(\"3_3n5aj\")\nregion = Rect2(896, 0, 128, 128)\n\n[node name=\"TowerDetails\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_tower_name_label\", \"_base_damage\", \"_base_damage_bonus\", \"_base_damage_bonus_perc\", \"_damage_add\", \"_damage_add_perc\", \"_overall_damage\", \"_base_attack_speed\", \"_attack_speed_modifier\", \"_overall_attack_speed\", \"_overall_dps\", \"_crit_chance\", \"_crit_damage\", \"_multicrit\", \"_dps_with_crit\", \"_spell_damage\", \"_spell_crit_chance\", \"_spell_crit_damage\", \"_total_damage\", \"_total_damage_recent\", \"_best_hit\", \"_kills\", \"_experience\", \"_level_x_at_left\", \"_level_x_at_right\", \"_base_mana\", \"_mana_bonus\", \"_mana_bonus_perc\", \"_overall_mana\", \"_base_mana_regen\", \"_mana_regen_bonus\", \"_mana_regen_bonus_perc\", \"_overall_mana_regen\", \"_bounty_ratio\", \"_exp_ratio\", \"_item_drop_ratio\", \"_item_quality_ratio\", \"_trigger_chances\", \"_buff_duration\", \"_debuff_duration\", \"_dmg_to_undead\", \"_dmg_to_magical\", \"_dmg_to_nature\", \"_dmg_to_orc\", \"_dmg_to_humanoid\", \"_dmg_to_challenge\", \"_dmg_to_mass\", \"_dmg_to_normal\", \"_dmg_to_air\", \"_dmg_to_champion\", \"_dmg_to_boss\", \"_total_dmg_multiplier\", \"_tower_details_label\")]\noffset_right = 1219.0\noffset_bottom = 600.0\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_w837r\")\nscript = ExtResource(\"2_arilw\")\n_tower_name_label = NodePath(\"PanelContainer/VBoxContainer/TowerNameLabel\")\n_base_damage = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer/BaseDamage\")\n_base_damage_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer/BaseDamageBonus\")\n_base_damage_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer/BaseDamageBonusPercent\")\n_damage_add = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer/DamageAdd\")\n_damage_add_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer/DamageAddPercent\")\n_overall_damage = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer/OverallDamage\")\n_base_attack_speed = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer/BaseAttackSpeed\")\n_attack_speed_modifier = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer/AttackSpeedModifier\")\n_overall_attack_speed = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer/OverallAttackSpeed\")\n_overall_dps = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer5/GridContainer/OverallDPS\")\n_crit_chance = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer/PropAtkCritChance\")\n_crit_damage = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer/PropAtkCritDamage\")\n_multicrit = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer/PropMulticritCount\")\n_dps_with_crit = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer7/GridContainer/DPS_WithCrit\")\n_spell_damage = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer/PropSpellDamageDealt\")\n_spell_crit_chance = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer/SpellCritChance\")\n_spell_crit_damage = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer/SpellCritDamage\")\n_total_damage = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/Damage\")\n_total_damage_recent = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/TotalDamageRecent\")\n_best_hit = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/BestHit\")\n_kills = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/Kills\")\n_experience = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/Exp\")\n_level_x_at_left = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/LevelXAt\")\n_level_x_at_right = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer/ExperienceForNextLevel\")\n_base_mana = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseMana\")\n_mana_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseManaBonus\")\n_mana_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseManaBonusPercent\")\n_overall_mana = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/OverallMana\")\n_base_mana_regen = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseManaRegen\")\n_mana_regen_bonus = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseManaRegenBonus\")\n_mana_regen_bonus_perc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/BaseManaRegenBonusPercent\")\n_overall_mana_regen = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer/OverallManaRegen\")\n_bounty_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/PropBountyReceived\")\n_exp_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/ExpRatio\")\n_item_drop_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/ItemDropRatio\")\n_item_quality_ratio = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/ItemQualityRatio\")\n_trigger_chances = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/PropTriggerChances\")\n_buff_duration = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/PropBuffDuration\")\n_debuff_duration = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer/PropDebuffDuration\")\n_dmg_to_undead = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer/DamageToUndead\")\n_dmg_to_magical = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer/DamageToMagic\")\n_dmg_to_nature = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer/DamageToNature\")\n_dmg_to_orc = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer/DamageToOrc\")\n_dmg_to_humanoid = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer/DamageToHumanoid\")\n_dmg_to_challenge = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer/DamageToChallenge\")\n_dmg_to_mass = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer/DamageToMass\")\n_dmg_to_normal = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer/DamageToNormal\")\n_dmg_to_air = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer/DamageToAir\")\n_dmg_to_champion = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer/DamageToChampion\")\n_dmg_to_boss = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer/DamageToBoss\")\n_total_dmg_multiplier = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer7/TotalDmgMultiplier\")\n_tower_details_label = NodePath(\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MultiboardContainer/TowerDetailsLabel\")\n\n[node name=\"RefreshTimer\" type=\"Timer\" parent=\".\"]\nautostart = true\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\".\"]\nlayout_mode = 2\ntheme = ExtResource(\"1_p3jli\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer\"]\nlayout_mode = 2\n\n[node name=\"TowerNameLabel\" type=\"Label\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\ntext = \"Tower name\"\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"PanelContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"Attack\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer\"]\nmodulate = Color(1, 0.32549, 0.32549, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_ATK\"\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"AttackContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_BASE_DMG\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_DMG\"\n\n[node name=\"BaseDamage\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"4,522\"\nhorizontal_alignment = 2\n\n[node name=\"Label11\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_BASE_BONUS\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_BONUS\"\n\n[node name=\"BaseDamageBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0\"\nhorizontal_alignment = 2\n\n[node name=\"Label17\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_BASE_BONUS_PST\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_BONUS_PST\"\n\n[node name=\"BaseDamageBonusPercent\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"+717%\"\nhorizontal_alignment = 2\n\n[node name=\"Label23\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_DMG_ADD\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_DNG_ADD\"\n\n[node name=\"DamageAdd\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"38,881\"\nhorizontal_alignment = 2\n\n[node name=\"Label29\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_DMG_ADD_PST\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_DNG_ADD_PST\"\n\n[node name=\"DamageAddPercent\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"+423%\"\nhorizontal_alignment = 2\n\n[node name=\"Label34\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_OVERALL_DNG\"\n\n[node name=\"OverallDamage\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer2/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"396,416\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label38\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_ATK_SPEED\"\n\n[node name=\"BaseAttackSpeed\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"160\"\nhorizontal_alignment = 2\n\n[node name=\"Label44\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_ATK_SPEED_MOD\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_ATK_SPEED_MOD\"\n\n[node name=\"AttackSpeedModifier\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"493%\"\nhorizontal_alignment = 2\n\n[node name=\"Label50\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_ATK_SPEED\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_OVERALL_ATK_SPEED\"\n\n[node name=\"OverallAttackSpeed\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer3/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0.33\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer5\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer5\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label62\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer5/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_OVERALL_DPS\"\n\n[node name=\"OverallDPS\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer5/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"122M\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer6\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label68\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_CRIT_CHANCE\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_CRIT_CHANCE\"\n\n[node name=\"PropAtkCritChance\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"106.6%\"\nhorizontal_alignment = 2\n\n[node name=\"Label74\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_CRIT_DMG\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_CRIT_DMG\"\n\n[node name=\"PropAtkCritDamage\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"10%\"\nhorizontal_alignment = 2\n\n[node name=\"Label80\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_MULTICRIT_COUNT\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MULTICRIT_COUNT\"\n\n[node name=\"PropMulticritCount\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer6/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"10\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer7\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"GridContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer7\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label68\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer7/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_DPS_WITH_CRIT\"\n\n[node name=\"DPS_WithCrit\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer7/GridContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"18.67M\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer8\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"PanelContainer2\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"Spells\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nmodulate = Color(0.145098, 0.831373, 1, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_SPELLS\"\n\n[node name=\"AttackContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label5\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_SPELL_DMG\"\n\n[node name=\"PropSpellDamageDealt\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"651%\"\nhorizontal_alignment = 2\n\n[node name=\"Label11\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_SPELL_CRIT_CHANCE\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_SPELL_CRIT_CHANCE\"\n\n[node name=\"SpellCritChance\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"114.0%\"\nhorizontal_alignment = 2\n\n[node name=\"Label17\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_SPELLS_CRIT_DMG\"\n\n[node name=\"SpellCritDamage\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/AttackContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"x10.63\"\nhorizontal_alignment = 2\n\n[node name=\"Mana\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nmodulate = Color(0.423529, 0.458824, 1, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MANA\"\n\n[node name=\"ManaContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label40\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_MANA\"\n\n[node name=\"BaseMana\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0\"\nhorizontal_alignment = 2\n\n[node name=\"Label46\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MANA_BONUS\"\n\n[node name=\"BaseManaBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0\"\nhorizontal_alignment = 2\n\n[node name=\"Label52\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MANA_BONUS_PST\"\n\n[node name=\"BaseManaBonusPercent\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"+32%\"\nhorizontal_alignment = 2\n\n[node name=\"Label58\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_OVERALL_MANA\"\n\n[node name=\"OverallMana\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0\"\nhorizontal_alignment = 2\n\n[node name=\"Label66\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BASE_MANA_REG\"\n\n[node name=\"BaseManaRegen\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0.0\"\nhorizontal_alignment = 2\n\n[node name=\"Label70\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MANA_REG_BONUS\"\n\n[node name=\"BaseManaRegenBonus\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0.0\"\nhorizontal_alignment = 2\n\n[node name=\"Label76\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MANA_REG_BONUS_PST\"\n\n[node name=\"BaseManaRegenBonusPercent\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"-27%\"\nhorizontal_alignment = 2\n\n[node name=\"Label78\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MANA_OVERALL_MANA_REG\"\n\n[node name=\"OverallManaRegen\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer2/MarginContainer/VBoxContainer/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"0.0\"\nhorizontal_alignment = 2\n\n[node name=\"PanelContainer4\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer2\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2\"]\nlayout_mode = 2\ntheme_override_constants/separation = 20\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"Veteran\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer\"]\nmodulate = Color(0.47451, 1, 0.470588, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_VETERAN\"\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"VeteranContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label7\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_VETERAN_DMG\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_VETERAN_DMG\"\n\n[node name=\"Damage\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"12.19G\"\nhorizontal_alignment = 2\n\n[node name=\"TotalDamageRecentLeft\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_VETERAN_RCT_DMG\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_VETERAN_RCT_DMG\"\n\n[node name=\"TotalDamageRecent\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\ntext = \"3M\"\nhorizontal_alignment = 2\n\n[node name=\"Label13\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_VETERAN_BEST_HIT\"\n\n[node name=\"BestHit\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"292.87M\"\nhorizontal_alignment = 2\n\n[node name=\"Label19\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_VETERAN_KILLS\"\n\n[node name=\"Kills\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"1957\"\nhorizontal_alignment = 2\n\n[node name=\"Label25\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_VETERAN_EXP\"\n\n[node name=\"Exp\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"9136\"\nhorizontal_alignment = 2\n\n[node name=\"LevelXAt\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Level X at\n\"\n\n[node name=\"ExperienceForNextLevel\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer2/VeteranContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer4\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"MarginContainer5\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"Misc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer5\"]\nmodulate = Color(1, 0.733333, 0.129412, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"TOWER_DETAILS_MISC\"\n\n[node name=\"MarginContainer6\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2\"]\nlayout_mode = 2\n\n[node name=\"ManaContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label40\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_BOUNTY_RAT\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BOUNTY_RAT\"\n\n[node name=\"PropBountyReceived\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"160%\"\nhorizontal_alignment = 2\n\n[node name=\"Label46\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_EXP_RAT\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_EXP_RAT\"\n\n[node name=\"ExpRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"186%\"\nhorizontal_alignment = 2\n\n[node name=\"Label52\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_DROP_RAT\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_DROP_RAT\"\n\n[node name=\"ItemDropRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"80%\"\nhorizontal_alignment = 2\n\n[node name=\"Label58\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_QUALITY_RAT\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_QUALITY_RAT\"\n\n[node name=\"ItemQualityRatio\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"Label66\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_TRIGGER_CHANCES\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_TRIGGER_CHANCES\"\n\n[node name=\"PropTriggerChances\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"160%\"\nhorizontal_alignment = 2\n\n[node name=\"Label70\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_BUFF_DUR\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_BUFF_DUR\"\n\n[node name=\"PropBuffDuration\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"170%\"\nhorizontal_alignment = 2\n\n[node name=\"Label76\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntooltip_text = \"TOWER_DETAILS_TOOLTIP_DEBUFF_DUR\"\nmouse_filter = 1\ntext = \"TOWER_DETAILS_DEBUFF_DUR\"\n\n[node name=\"PropDebuffDuration\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer4/MarginContainer2/VBoxContainer2/MarginContainer6/ManaContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"31%\"\nhorizontal_alignment = 2\n\n[node name=\"PanelContainer3\" type=\"PanelContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(300, 0)\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"VBoxContainer3\" type=\"VBoxContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ntheme_override_constants/separation = 20\n\n[node name=\"MarginContainer3\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"DamageRace\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer3\"]\nmodulate = Color(0.6, 0.341176, 0.113725, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"DMG_TO_RACE\"\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"DamageRaceContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label9\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"RACE_UNDEAD\"\n\n[node name=\"DamageToUndead\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"114%\"\nhorizontal_alignment = 2\n\n[node name=\"Label15\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"RACE_MAGICAL\"\n\n[node name=\"DamageToMagic\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"Label21\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"RACE_NATURE\"\n\n[node name=\"DamageToNature\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"80%\"\nhorizontal_alignment = 2\n\n[node name=\"Label27\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"RACE_ORC\"\n\n[node name=\"DamageToOrc\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"126%\"\nhorizontal_alignment = 2\n\n[node name=\"Label32\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"RACE_HUMANOID\"\n\n[node name=\"DamageToHumanoid\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"Label33\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Challenge\"\n\n[node name=\"DamageToChallenge\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer/DamageRaceContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer4\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"DamageSize\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer4\"]\nmodulate = Color(0.6, 0.341176, 0.113725, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"DMG_TO_SIZE\"\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"DamageSizeContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label42\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"SIZE_MASS\"\n\n[node name=\"DamageToMass\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"125%\"\nhorizontal_alignment = 2\n\n[node name=\"Label48\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"SIZE_NORMAL\"\n\n[node name=\"DamageToNormal\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"Label54\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"SIZE_AIR\"\n\n[node name=\"DamageToAir\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"95%\"\nhorizontal_alignment = 2\n\n[node name=\"Label60\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"SIZE_CHAMPION\"\n\n[node name=\"DamageToChampion\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"Label64\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"SIZE_BOSS\"\n\n[node name=\"DamageToBoss\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer2/DamageSizeContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"MarginContainer7\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"DamageTotal\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer7\"]\nmodulate = Color(0.6, 0.341176, 0.113725, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Total damage:\"\n\n[node name=\"TotalDmgMultiplier\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer7\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"100%\"\nhorizontal_alignment = 2\n\n[node name=\"MultiboardContainer\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 10\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"TowerDetailsLabel\" type=\"RichTextLabel\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MultiboardContainer\"]\nlayout_mode = 2\ntheme_override_constants/table_h_separation = 10\ntext = \"Specials:\nPLACEHOLDER\nKey: value\"\nfit_content = true\n\n[node name=\"MarginContainer5\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"ItemSpecific\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer5\"]\nmodulate = Color(0.6, 0.341176, 0.113725, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Item Specific\"\n\n[node name=\"MarginContainer6\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"ItemSpecificContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label9\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Damage\"\n\n[node name=\"Label10\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"1,032,268\"\n\n[node name=\"Label15\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"DPS Gained\"\n\n[node name=\"Label16\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"4,000\"\n\n[node name=\"Label11\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Crit Bonus\"\n\n[node name=\"Label12\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"x3.005\"\n\n[node name=\"Label17\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Crit Bonus\"\n\n[node name=\"Label18\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer6/ItemSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"x3.005\"\n\n[node name=\"MarginContainer9\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"UnitSpecific\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer9\"]\nmodulate = Color(0.6, 0.341176, 0.113725, 1)\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Unit Specific\"\n\n[node name=\"MarginContainer10\" type=\"MarginContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3\"]\nvisible = false\nlayout_mode = 2\nsize_flags_horizontal = 3\n\n[node name=\"UnitSpecificContainer\" type=\"GridContainer\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer10\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\ncolumns = 2\n\n[node name=\"Label9\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer10/UnitSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"Skill Name 2\"\n\n[node name=\"Label10\" type=\"Label\" parent=\"PanelContainer/VBoxContainer/HBoxContainer/PanelContainer3/MarginContainer3/VBoxContainer3/MarginContainer10/UnitSpecificContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 3\nmouse_filter = 1\ntext = \"160\"\n\n[node name=\"CloseButton\" type=\"Button\" parent=\".\"]\ncustom_minimum_size = Vector2(40, 40)\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nicon = SubResource(\"AtlasTexture_ipd82\")\nicon_alignment = 1\nexpand_icon = true\n\n[connection signal=\"timeout\" from=\"RefreshTimer\" to=\".\" method=\"_on_refresh_timer_timeout\"]\n[connection signal=\"pressed\" from=\"CloseButton\" to=\".\" method=\"_on_close_button_pressed\"]\n"
  },
  {
    "path": "src/ui/unit_menu/tower_mini_details.gd",
    "content": "class_name TowerMiniDetails extends TabContainer\n\n\n# Displays tower stats inside unit menu\n\n\nvar _tower: Tower = null\n\n@export var _dmg_left_label: RichTextLabel\n@export var _dmg_right_label: RichTextLabel\n@export var _misc_left_label: RichTextLabel\n@export var _misc_right_label: RichTextLabel\n@export var _types_left_label: RichTextLabel\n@export var _types_right_label: RichTextLabel\n@export var _oils_label: RichTextLabel\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_tower(tower: Tower):\n\t_tower = tower\n\n\n#########################\n###      Private      ###\n#########################\n\n# NOTE: this code consumes a lot of frametime so it needs to\n# be called sparingly. That's why it's not called every\n# frame in _process().\nfunc _update_labels():\n\tif _tower == null:\n\t\treturn\n\t\n\tvar dmg_stats_left_text: String = _get_dmg_stats_left_text()\n\t_dmg_left_label.clear()\n\t_dmg_left_label.append_text(dmg_stats_left_text)\n\n\tvar dmg_stats_right_text: String = _get_dmg_stats_right_text()\n\t_dmg_right_label.clear()\n\t_dmg_right_label.append_text(dmg_stats_right_text)\n\t\n\tvar support_stats_left_text: String = _get_support_stats_left_text()\n\t_misc_left_label.clear()\n\t_misc_left_label.append_text(support_stats_left_text)\n\t\n\tvar support_stats_right_text: String = _get_support_stats_right_text()\n\t_misc_right_label.clear()\n\t_misc_right_label.append_text(support_stats_right_text)\n\t\n\tvar dmg_against_left_text: String = _get_dmg_against_left_text()\n\t_types_left_label.clear()\n\t_types_left_label.append_text(dmg_against_left_text)\n\t\n\tvar dmg_against_right_text: String = _get_dmg_against_right_text()\n\t_types_right_label.clear()\n\t_types_right_label.append_text(dmg_against_right_text)\n\t\n\tvar oils_text: String = _get_tower_oils_text()\n\t_oils_label.clear()\n\t_oils_label.append_text(oils_text)\n\n\nfunc _get_dmg_stats_left_text() -> String:\n\tvar base_damage: int = roundi(_tower.get_current_attack_damage_base())\n\tvar base_damage_string: String = TowerDetails.int_format(base_damage)\n\n\tvar overall_damage: int = roundi(_tower.get_current_attack_damage_with_bonus())\n\tvar overall_damage_string: String = TowerDetails.int_format(overall_damage)\n\n\tvar dps_with_crit: int = roundi(_tower.get_dps_with_crit())\n\tvar dps_with_crit_string: String = TowerDetails.int_format(dps_with_crit)\n\n\tvar crit_chance: float = _tower.get_prop_atk_crit_chance()\n\tvar crit_chance_string: String = Utils.format_percent(crit_chance, 1)\n\n\tvar crit_damage: float = _tower.get_prop_atk_crit_damage()\n\tvar crit_damage_string: String = TowerDetails.multiplier_format(crit_damage)\n\n\tvar multicrit: int = _tower.get_prop_multicrit_count()\n\tvar multicrit_string: String = TowerDetails.int_format(multicrit)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=e37c0e]res://resources/icons/generic_icons/hammer_drop.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_BASE_DMG\"), base_damage_string] \\\n\t+ \"[hint=%s][img=30 color=eb4f34]res://resources/icons/generic_icons/hammer_drop.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_OVERALL_DNG\"), overall_damage_string] \\\n\t+ \"[hint=%s][img=30 color=e83140]res://resources/icons/generic_icons/open_wound.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_DPS_WITH_CRIT\"), dps_with_crit_string] \\\n\t+ \"[hint=%s][img=30 color=eb3495]res://resources/icons/generic_icons/root_tip.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_ATTACK_CRIT_CHANCE\"), crit_chance_string] \\\n\t+ \"[hint=%s][img=30 color=eb3495]res://resources/icons/generic_icons/mine_explosion.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_ATTACK_CRIT_DAMAGE\"), crit_damage_string] \\\n\t+ \"[hint=%s][img=30 color=de3535]res://resources/icons/generic_icons/triple_scratches.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_MULTICRIT_COUNT\"), multicrit_string] \\\n\t+ \"\"\n\n\treturn text\n\n\nfunc _get_dmg_stats_right_text() -> String:\n\tvar overall_cooldown: float = _tower.get_current_attack_speed()\n\tvar overall_cooldown_string: String = Utils.format_float(overall_cooldown, 2)\n\n\tvar spell_damage: float = _tower.get_prop_spell_damage_dealt()\n\tvar spell_damage_string: String = Utils.format_percent(spell_damage, 0)\n\t\n\tvar spell_crit_chance: float = _tower.get_spell_crit_chance()\n\tvar spell_crit_chance_string: String = Utils.format_percent(spell_crit_chance, 1)\n\n\tvar spell_crit_damage: float = _tower.get_spell_crit_damage()\n\tvar spell_crit_damage_string: String = TowerDetails.multiplier_format(spell_crit_damage)\n\n\tvar overall_mana_regen: float = _tower.get_overall_mana_regen()\n\tvar overall_mana_regen_string: String = Utils.format_float(overall_mana_regen, 1)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=eb8f34]res://resources/icons/generic_icons/hourglass.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_ATTACK_SPEED\"), overall_cooldown_string] \\\n\t+ \"[hint=%s][img=30 color=31cde8]res://resources/icons/generic_icons/rolling_energy.tres[/img] %s/s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_MANA_REGEN\"), overall_mana_regen_string] \\\n\t+ \"[hint=%s][img=30 color=31e896]res://resources/icons/generic_icons/flame.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_SPELL_DAMAGE_BONUS\"), spell_damage_string] \\\n\t+ \"[hint=%s][img=30 color=35a8de]res://resources/icons/generic_icons/root_tip.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_SPELL_CRIT_CHANCE\"), spell_crit_chance_string] \\\n\t+ \"[hint=%s][img=30 color=35a8de]res://resources/icons/generic_icons/mine_explosion.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_SPELL_CRIT_DAMAGE\"), spell_crit_damage_string] \\\n\t+ \"\"\n\n\treturn text\n\n\nfunc _get_support_stats_left_text() -> String:\n\tvar bounty_ratio: float = _tower.get_prop_bounty_received()\n\tvar bounty_ratio_string: String = Utils.format_percent(bounty_ratio, 0)\n\n\tvar exp_ratio: float = _tower.get_prop_exp_received()\n\tvar exp_ratio_string: String = Utils.format_percent(exp_ratio, 0)\n\n\tvar item_drop_ratio: float = _tower.get_item_drop_ratio()\n\tvar item_drop_ratio_string: String = Utils.format_percent(item_drop_ratio, 0)\n\n\tvar item_quality_ratio: float = _tower.get_item_quality_ratio()\n\tvar item_quality_ratio_string: String = Utils.format_percent(item_quality_ratio, 0)\n\n\tvar trigger_chances: float = _tower.get_prop_trigger_chances()\n\tvar trigger_chances_string: String = Utils.format_percent(trigger_chances, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=deca35]res://resources/icons/generic_icons/shiny_omega.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_BOUNTY_RAT\"), bounty_ratio_string] \\\n\t+ \"[hint=%s][img=30 color=9630f0]res://resources/icons/generic_icons/moebius_trefoil.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_EXP_RAT\"), exp_ratio_string] \\\n\t+ \"[hint=%s][img=30 color=bcde35]res://resources/icons/generic_icons/polar_star.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_DROP_RAT\"), item_drop_ratio_string] \\\n\t+ \"[hint=%s][img=30 color=c2ae3c]res://resources/icons/generic_icons/gold_bar.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_QUALITY_RAT\"), item_quality_ratio_string] \\\n\t+ \"[hint=%s][img=30 color=35ded5]res://resources/icons/generic_icons/cog.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_TRIGGER_CHANCES\"), trigger_chances_string] \\\n\t+ \"\"\n\n\treturn text\n\n\nfunc _get_support_stats_right_text() -> String:\n\tvar buff_duration: float = _tower.get_prop_buff_duration()\n\tvar buff_duration_string: String = Utils.format_percent(buff_duration, 0)\n\n\tvar debuff_duration: float = _tower.get_prop_debuff_duration()\n\tvar debuff_duration_string: String = Utils.format_percent(debuff_duration, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=49c23c]res://resources/icons/generic_icons/hourglass.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_BUFF_DUR\"), buff_duration_string] \\\n\t+ \"[hint=%s][img=30 color=c2433c]res://resources/icons/generic_icons/hourglass.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_DETAILS_DEBUFF_DUR\"), debuff_duration_string] \\\n\t+ \"\"\n\n\treturn text\n\n\nfunc _get_dmg_against_left_text() -> String:\n\tvar dmg_to_undead: float = _tower.get_damage_to_undead()\n\tvar dmg_to_undead_string: String = Utils.format_percent(dmg_to_undead, 0)\n\n\tvar dmg_to_magic: float = _tower.get_damage_to_magic()\n\tvar dmg_to_magic_string: String = Utils.format_percent(dmg_to_magic, 0)\n\n\tvar dmg_to_nature: float = _tower.get_damage_to_nature()\n\tvar dmg_to_nature_string: String = Utils.format_percent(dmg_to_nature, 0)\n\n\tvar dmg_to_orc: float = _tower.get_damage_to_orc()\n\tvar dmg_to_orc_string: String = Utils.format_percent(dmg_to_orc, 0)\n\n\tvar dmg_to_humanoid: float = _tower.get_damage_to_humanoid()\n\tvar dmg_to_humanoid_string: String = Utils.format_percent(dmg_to_humanoid, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=9370db]res://resources/icons/generic_icons/animal_skull.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_UNDEAD\"), dmg_to_undead_string] \\\n\t+ \"[hint=%s][img=30 color=6495ed]res://resources/icons/generic_icons/polar_star.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_MAGIC\"), dmg_to_magic_string] \\\n\t+ \"[hint=%s][img=30 color=32cd32]res://resources/icons/generic_icons/root_tip.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_NATURE\"), dmg_to_nature_string] \\\n\t+ \"[hint=%s][img=30 color=8fbc8f]res://resources/icons/generic_icons/orc_head.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_ORC\"), dmg_to_orc_string] \\\n\t+ \"[hint=%s][img=30 color=d2b48c]res://resources/icons/generic_icons/armor_vest.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_HUMANOID\"), dmg_to_humanoid_string] \\\n\t+ \"\"\n\t\n\treturn text\n\n\nfunc _get_dmg_against_right_text() -> String:\n\tvar dmg_to_mass: float = _tower.get_damage_to_mass()\n\tvar dmg_to_mass_string: String = Utils.format_percent(dmg_to_mass, 0)\n\n\tvar dmg_to_normal: float = _tower.get_damage_to_normal()\n\tvar dmg_to_normal_string: String = Utils.format_percent(dmg_to_normal, 0)\n\n\tvar dmg_to_air: float = _tower.get_damage_to_air()\n\tvar dmg_to_air_string: String = Utils.format_percent(dmg_to_air, 0)\n\n\tvar dmg_to_champion: float = _tower.get_damage_to_champion()\n\tvar dmg_to_champion_string: String = Utils.format_percent(dmg_to_champion, 0)\n\n\tvar dmg_to_boss: float = _tower.get_damage_to_boss()\n\tvar dmg_to_boss_string: String = Utils.format_percent(dmg_to_boss, 0)\n\n\tvar text: String = \"\" \\\n\t+ \"[hint=%s][img=30 color=ffa500]res://resources/icons/generic_icons/sprint.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_MASS\"), dmg_to_mass_string] \\\n\t+ \"[hint=%s][img=30 color=8fbc8f]res://resources/icons/generic_icons/barbute.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_NORMAL\"), dmg_to_normal_string] \\\n\t+ \"[hint=%s][img=30 color=6495ed]res://resources/icons/generic_icons/liberty_wing.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_AIR\"), dmg_to_air_string] \\\n\t+ \"[hint=%s][img=30 color=9370db]res://resources/icons/generic_icons/horned_helm.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_CHAMPION\"), dmg_to_champion_string] \\\n\t+ \"[hint=%s][img=30 color=ff4500]res://resources/icons/generic_icons/bat_mask.tres[/img] %s[/hint]\\n\" % [tr(\"TOWER_MINI_DETAILS_DAMAGE_TO_BOSS\"), dmg_to_boss_string] \\\n\t+ \"\"\n\t\n\treturn text\n\n\nfunc _get_tower_oils_text() -> String:\n\tvar oil_count_map: Dictionary = _get_oil_count_map()\n\t\n\tif oil_count_map.is_empty():\n\t\treturn tr(\"TOWER_MINI_DETAILS_NO_OILS\")\n\n\tvar text: String = \"\"\n\n\tvar oil_name_list: Array = oil_count_map.keys()\n\toil_name_list.sort()\n\n\tfor oil_name in oil_name_list:\n\t\tvar count: int = oil_count_map[oil_name]\n\n\t\ttext += \"%s x %s\\n\" % [str(count), oil_name]\n\n\treturn text\n\n\nfunc _get_oil_count_map() -> Dictionary:\n\tvar oil_list: Array[Item] = _tower.get_item_container().get_oil_list()\n\n\tvar oil_count_map: Dictionary = {}\n\n\tfor oil in oil_list:\n\t\tvar oil_id: int = oil.get_id()\n\t\tvar oil_name: String = ItemProperties.get_display_name(oil_id)\n\t\tvar oil_rarity: Rarity.enm = ItemProperties.get_rarity(oil_id)\n\t\tvar rarity_color: Color = Rarity.get_color(oil_rarity)\n\t\tvar oil_name_colored: String = Utils.get_colored_string(oil_name, rarity_color)\n\n\t\tif !oil_count_map.has(oil_name_colored):\n\t\t\toil_count_map[oil_name_colored] = 0\n\n\t\toil_count_map[oil_name_colored] += 1\n\n\treturn oil_count_map\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_update_timer_timeout() -> void:\n\t_update_labels()\n\n\nfunc _on_visibility_changed() -> void:\n\t_update_labels()\n"
  },
  {
    "path": "src/ui/unit_menu/tower_mini_details.tscn",
    "content": "[gd_scene load_steps=3 format=3 uid=\"uid://dy7728ew6n4n\"]\n\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/tower_mini_details.gd\" id=\"1_nxq0b\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://b5kapr6gujqbt\" path=\"res://src/ui/unit_menu/mini_details_label.tscn\" id=\"2_tifx3\"]\n\n[node name=\"TowerMiniDetails\" type=\"TabContainer\" node_paths=PackedStringArray(\"_dmg_left_label\", \"_dmg_right_label\", \"_misc_left_label\", \"_misc_right_label\", \"_types_left_label\", \"_types_right_label\", \"_oils_label\")]\ncustom_minimum_size = Vector2(400, 300)\nsize_flags_vertical = 8\ncurrent_tab = 0\ntab_focus_mode = 0\nscript = ExtResource(\"1_nxq0b\")\n_dmg_left_label = NodePath(\"TOWER_MINI_DETAILS_DMG/DmgLeftLabel\")\n_dmg_right_label = NodePath(\"TOWER_MINI_DETAILS_DMG/DmgRightLabel\")\n_misc_left_label = NodePath(\"TOWER_MINI_DETAILS_MISC/MiscLeftLabel\")\n_misc_right_label = NodePath(\"TOWER_MINI_DETAILS_MISC/MiscRightLabel\")\n_types_left_label = NodePath(\"TOWER_MINI_DETAILS_TYPES/TypesLeftLabel\")\n_types_right_label = NodePath(\"TOWER_MINI_DETAILS_TYPES/TypesRightLabel\")\n_oils_label = NodePath(\"TOWER_MINI_DETAILS_OILS/ScrollContainer/OilsLabel\")\n\n[node name=\"UpdateTimer\" type=\"Timer\" parent=\".\"]\nautostart = true\n\n[node name=\"TOWER_MINI_DETAILS_DMG\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\nmetadata/_tab_index = 0\n\n[node name=\"DmgLeftLabel\" parent=\"TOWER_MINI_DETAILS_DMG\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\n\n[node name=\"DmgRightLabel\" parent=\"TOWER_MINI_DETAILS_DMG\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\n\n[node name=\"TOWER_MINI_DETAILS_MISC\" type=\"HBoxContainer\" parent=\".\"]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 1\n\n[node name=\"MiscLeftLabel\" parent=\"TOWER_MINI_DETAILS_MISC\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\n\n[node name=\"MiscRightLabel\" parent=\"TOWER_MINI_DETAILS_MISC\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\n\n[node name=\"TOWER_MINI_DETAILS_TYPES\" type=\"HBoxContainer\" parent=\".\"]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 2\n\n[node name=\"TypesLeftLabel\" parent=\"TOWER_MINI_DETAILS_TYPES\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\n\n[node name=\"TypesRightLabel\" parent=\"TOWER_MINI_DETAILS_TYPES\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\n\n[node name=\"TOWER_MINI_DETAILS_OILS\" type=\"VBoxContainer\" parent=\".\"]\nvisible = false\nlayout_mode = 2\nmetadata/_tab_index = 3\n\n[node name=\"ScrollContainer\" type=\"ScrollContainer\" parent=\"TOWER_MINI_DETAILS_OILS\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"OilsLabel\" parent=\"TOWER_MINI_DETAILS_OILS/ScrollContainer\" instance=ExtResource(\"2_tifx3\")]\nlayout_mode = 2\nmouse_force_pass_scroll_events = false\nscroll_active = true\n\n[connection signal=\"visibility_changed\" from=\".\" to=\".\" method=\"_on_visibility_changed\"]\n[connection signal=\"timeout\" from=\"UpdateTimer\" to=\".\" method=\"_on_update_timer_timeout\"]\n"
  },
  {
    "path": "src/ui/unit_menu/unit_menu.gd",
    "content": "class_name UnitMenu extends PanelContainer\n\n\n# This menu is displayed when a unit is selected. Displays\n# info about towers and creeps and allows performing actions\n# on them.\n\n\nsignal details_pressed()\n\n\nconst SELL_BUTTON_RESET_TIME: float = 5.0\n\n@export var _tower_button: TowerButton\n@export var _creep_button: Button\n@export var _level_label: Label\n@export var _reset_sell_button_timer: Timer\n@export var _upgrade_button: Button\n@export var _sell_button: Button\n@export var _buff_container: BuffContainer\n@export var _ability_grid: GridContainer\n@export var _exp_bar: ProgressBarWithLabel\n@export var _health_bar: ProgressBarWithLabel\n@export var _mana_bar: ProgressBarWithLabel\n@export var _tower_mini_details: TowerMiniDetails\n@export var _creep_mini_details: CreepMiniDetails\n@export var _tower_inventory_panel: ItemContainerPanel\n@export var _tower_inventory_outer_panel: PanelContainer\n@export var _buff_group_editor: BuffGroupEditor\n\nvar _selling_for_real: bool = false\nvar _unit: Unit = null\nvar _tower: Unit = null\nvar _creep: Creep = null\n\n@onready var _visible_controls_for_tower: Array[Control] = [\n\t_tower_button,\n\t_exp_bar,\n\t_upgrade_button,\n\t_sell_button,\n\t_buff_group_editor,\n\t_tower_mini_details,\n\t_tower_inventory_outer_panel,\n]\n\n@onready var _visible_controls_for_creep: Array[Control] = [\n\t_creep_button,\n\t_health_bar,\n\t_creep_mini_details,\n]\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _process(_delta: float):\n\tif _unit == null:\n\t\treturn\n\t\n\tvar health: int = floori(_unit.get_health())\n\tvar health_max: int = floori(_unit.get_overall_health())\n\t_health_bar.set_ratio_custom(health, health_max)\n\t\n\tvar mana: int = roundi(_unit.get_mana())\n\tvar mana_max: int = roundi(_unit.get_overall_mana())\n\t_mana_bar.set_ratio_custom(mana, mana_max)\n\t\n\tvar unit_level: int = _unit.get_level()\n\t\n\tvar max_unit_level: int = _unit.get_max_level()\n\t\t\n\tvar unit_is_max_level: bool = unit_level == max_unit_level\n\tif !unit_is_max_level:\n\t\tvar exp_for_current_level: int = Experience.get_exp_for_level(unit_level)\n\t\tvar exp_for_next_level: int = Experience.get_exp_for_level(unit_level + 1)\n\t\tvar current_exp: int = floori(_unit.get_exp())\n\t\tvar exp_over_current_level: int = current_exp - exp_for_current_level\n\t\tvar exp_until_next_level: int = exp_for_next_level - exp_for_current_level\n\t\t_exp_bar.set_ratio_custom(current_exp, exp_for_next_level)\n\n#\t\tNOTE: need to set ratio manually because exp bar\n#\t\tneeds to display:\n#\t\ttext - current total exp\n#\t\tratio - current total exp minus exp for prev level\n\t\tvar exp_ratio: float = Utils.divide_safe(exp_over_current_level, exp_until_next_level)\n\t\t_exp_bar.set_as_ratio(exp_ratio)\n\telse:\n\t\tvar current_exp: int = floori(_unit.get_exp())\n\t\tvar exp_for_max_level: int = Experience.get_exp_for_level(max_unit_level)\n\t\t_exp_bar.set_ratio_custom(current_exp, exp_for_max_level)\n\t\n\tif _tower != null:\n\t\t_update_upgrade_button()\n\t\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_unit() -> Unit:\n\treturn _unit\n\n\nfunc set_unit(unit: Unit):\n\tvar prev_unit: Unit = _unit\n\t\n\t_unit = unit\n\t_tower = unit as Tower\n\t_creep = unit as Creep\n\t\n\t_tower_mini_details.set_tower(_tower)\n\t_buff_group_editor.set_tower(_tower)\n\n\t_creep_mini_details.set_creep(_creep)\n\t\n\tif prev_unit != null:\n\t\tprev_unit.buff_list_changed.disconnect(_on_buff_list_changed)\n\t\n\t\tif prev_unit is Tower:\n\t\t\tvar prev_tower: Tower = prev_unit as Tower\n\t\t\tprev_tower.level_changed.disconnect(_on_tower_level_changed)\n\t\n#\tNOTE: need to setup visibility before calling _load_tower() because it can further hide some controls conditionally.\n\tfor control in _visible_controls_for_tower:\n\t\tcontrol.visible = unit is Tower\n\t\n\tfor control in _visible_controls_for_creep:\n\t\tcontrol.visible = unit is Creep\n\t\n\tvar prev_ability_list: Array = _ability_grid.get_children()\n\tfor button in prev_ability_list:\n\t\t_ability_grid.remove_child(button)\n\t\tbutton.queue_free()\n\t\n\tif unit != null && unit is Tower:\n\t\tvar tower_item_container: ItemContainer = _tower.get_item_container()\n\t\t_tower_inventory_panel.set_item_container(tower_item_container)\n\telse:\n\t\t_tower_inventory_panel.set_item_container(null)\n\t\n\tif unit != null:\n\t\t_load_unit()\n\t\n\tif unit is Tower:\n\t\t_load_tower()\n\telif unit is Creep:\n\t\t_load_creep()\n\n\n#########################\n###      Private      ###\n#########################\n\n# Setup stuff that is generic for all unit types\nfunc _load_unit():\n\t_unit.buff_list_changed.connect(_on_buff_list_changed)\n\t_on_buff_list_changed()\n\t\n\tvar overall_mana: float = _unit.get_overall_mana()\n\tvar unit_has_mana: bool = overall_mana > 0\n\t_mana_bar.visible = unit_has_mana\n\n\nfunc _load_tower():\n\t_tower.level_changed.connect(_on_tower_level_changed)\n\t_update_level_label()\n\n\t_update_sell_tooltip()\n\t_setup_tower_ability_buttons()\n\n\tvar tower_id: int = _tower.get_id()\n\t_tower_button.set_tower_id(tower_id)\n\t_tower_button.set_tier_visible(true)\n\n\t_set_selling_for_real(false)\n\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar upgrade_button_should_be_visible: bool = game_mode == GameMode.enm.BUILD || game_mode == GameMode.enm.RANDOM_WITH_UPGRADES\n\t_upgrade_button.visible = upgrade_button_should_be_visible\n\n\nfunc _load_creep():\n\tvar icon: Texture2D = UnitIcons.get_creep_icon(_creep)\n\t_creep_button.set_button_icon(icon)\n\n\t_setup_creep_ability_buttons()\n\n\tvar creep_level: int = _creep.get_spawn_level()\n\t_level_label.text = str(creep_level)\n\n\nfunc _connect_to_ability_button(button: AbilityButton):\n\tbutton.mouse_entered.connect(_on_ability_button_mouse_entered.bind(button))\n\t\n\tbutton.mouse_exited.connect(_on_ability_button_mouse_exited.bind(button))\n\tbutton.tree_exited.connect(_on_ability_button_mouse_exited.bind(button))\n\tbutton.hidden.connect(_on_ability_button_mouse_exited.bind(button))\n\n\nfunc _connect_to_autocast_button(button: AutocastButton):\n\tbutton.mouse_entered.connect(_on_autocast_button_mouse_entered.bind(button))\n\n\tbutton.mouse_exited.connect(_on_autocast_button_mouse_exited.bind(button))\n\tbutton.tree_exited.connect(_on_autocast_button_mouse_exited.bind(button))\n\tbutton.hidden.connect(_on_autocast_button_mouse_exited.bind(button))\n\n\nfunc _setup_tower_ability_buttons():\t\n\tvar button_data_list: Array[AbilityButton.Data] = _tower.get_ability_button_data_list()\n\t\n\tfor button_data in button_data_list:\n\t\tvar button: AbilityButton = AbilityButton.make_from_data(button_data)\n\t\t_ability_grid.add_child(button)\n\t\t_connect_to_ability_button(button)\n\n\tvar tower_id: int = _tower.get_id()\n\t\n\tvar ability_id_list: Array = TowerProperties.get_ability_id_list(tower_id)\n\tfor ability_id in ability_id_list:\n\t\tvar button: AbilityButton = AbilityButton.make_from_ability_id(ability_id)\n\t\t_ability_grid.add_child(button)\n\t\t_connect_to_ability_button(button)\n\n\tvar aura_id_list: Array = TowerProperties.get_aura_id_list(tower_id)\n\tfor aura_id in aura_id_list:\n\t\tvar aura_is_hidden: bool = AuraProperties.get_is_hidden(aura_id)\n\t\tif aura_is_hidden:\n\t\t\tcontinue\n\n\t\tvar button: AbilityButton = AbilityButton.make_from_aura_id(aura_id)\n\t\t_ability_grid.add_child(button)\n\t\t_connect_to_ability_button(button)\n\n#\tNOTE: add padding buttons so that autocasts abilities go\n#\ton the second row (for visual separation). If there are\n#\ttoo many passive abilities, then some of them will go to\n#\tsecond row.\n\tvar ability_count_without_autocasts: int = _ability_grid.get_child_count()\n\tvar column_count: int = _ability_grid.get_columns()\n\tif ability_count_without_autocasts < column_count:\n\t\tvar first_row_pad_count: int = column_count - ability_count_without_autocasts\n\n\t\t_pad_ability_grid(first_row_pad_count)\n\n\tvar autocast_list: Array[Autocast] = _tower.get_autocast_list()\n\tfor autocast in autocast_list:\n\t\tvar autocast_button: AutocastButton = AutocastButton.make(autocast)  \n\t\t_ability_grid.add_child(autocast_button)\n\t\t_connect_to_autocast_button(autocast_button)\n\n\tvar second_row_pad_count: int = column_count * 2 - _ability_grid.get_child_count()\n\t_pad_ability_grid(second_row_pad_count)\n\n\nfunc _setup_creep_ability_buttons():\n\tvar button_data_list: Array[AbilityButton.Data] = _creep.get_ability_button_data_list()\n\t\n\tfor button_data in button_data_list:\n\t\tvar button: AbilityButton = AbilityButton.make_from_data(button_data)\n\t\t_ability_grid.add_child(button)\n\t\t_connect_to_ability_button(button)\n\n\tvar column_count: int = _ability_grid.get_columns()\n\tvar pad_count: int = column_count * 2 - _ability_grid.get_child_count()\n\t_pad_ability_grid(pad_count)\n\n\nfunc _pad_ability_grid(pad_count: int):\n\tfor i in range(0, pad_count):\n\t\tvar padding_button: EmptyUnitButton = Preloads.empty_slot_button_scene.instantiate()\n\t\tpadding_button.custom_minimum_size = Constants.ABILITY_BUTTON_SIZE\n\t\t_ability_grid.add_child(padding_button)\n\n\nfunc _update_level_label():\n\t_level_label.text = str(_tower.get_level())\n\n\n# NOTE: upgrade button is disabled when wave/research\n# requirements are not satisfied. Gold/tomes/food costs are\n# not considered and this is on purpose.\nfunc _update_upgrade_button():\n\tvar upgrade_id: int = TowerProperties.get_upgrade_id_for_tower(_tower.get_id())\n\n\tvar can_upgrade: bool\n\tif upgrade_id != -1:\n\t\tvar local_player: Player = PlayerManager.get_local_player()\n\t\tvar requirements_are_satisfied: bool = TowerProperties.requirements_are_satisfied(upgrade_id, local_player)\n\t\tcan_upgrade = requirements_are_satisfied\n\telse:\n\t\tcan_upgrade = false\n\n\t_upgrade_button.set_disabled(!can_upgrade)\n\n\nfunc _update_sell_tooltip():\n\tvar game_mode: GameMode.enm = Globals.get_game_mode()\n\tvar sell_ratio: float = GameMode.get_sell_ratio(game_mode)\n\tvar sell_ratio_string: String = Utils.format_percent(sell_ratio, 0)\n\tvar tower_id: int = _tower.get_id()\n\tvar sell_price: int = TowerProperties.get_sell_price(tower_id)\n\tvar tooltip: String = tr(\"SELL_TOWER_BUTTON_TOOLTIP\").format({GOLD_AMOUNT = sell_price, SELL_RATIO = sell_ratio_string})\n\n\t_sell_button.set_tooltip_text(tooltip)\n\n\nfunc _set_selling_for_real(value: bool):\n\t_selling_for_real = value\n\n\tif _selling_for_real:\n\t\t_sell_button.modulate = Color(Color.CRIMSON)\n\telse:\n\t\t_sell_button.modulate = Color(Color.WHITE)\n\n\tif _selling_for_real:\n\t\t_reset_sell_button_timer.start(SELL_BUTTON_RESET_TIME)\n\telse:\n\t\t_reset_sell_button_timer.stop()\n\n\nfunc _set_autocast_range_visible(button: AutocastButton, value: bool):\n\tif _tower == null:\n\t\treturn\n\n\tvar autocast: Autocast = button.get_autocast()\n\tvar autocast_name_english: String = autocast.get_name_english()\n\t_tower.set_range_indicator_visible(autocast_name_english, value)\n\n\nfunc _set_ability_range_visible(button: AbilityButton, value: bool):\n\tif _tower == null:\n\t\treturn\n\n\tvar ability_name_english: String = button.get_ability_name_english()\n\t_tower.set_range_indicator_visible(ability_name_english, value)\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_upgrade_button_pressed():\n\tEventBus.player_requested_to_upgrade_tower.emit(_tower)\n\n#\tNOTE: hide and show upgrade button to trigger\n#\tmouse_entered() signal to refresh the button tooltip.\n#\tNote that we cannot manually call\n#\t_on_tower_upgrade_button_mouse_entered() because it\n#\tdoesn't work correctly for the case where upgrade button\n#\twas pressed using the keyboard shortcut.\n\t_upgrade_button.hide()\n\t_upgrade_button.show()\n\n\nfunc _on_reset_sell_button_timer_timeout():\n\t_set_selling_for_real(false)\n\n\nfunc _on_sell_button_pressed():\n\tif !_selling_for_real:\n\t\t_set_selling_for_real(true)\n\t\t\n\t\treturn\n\n\tEventBus.player_requested_to_sell_tower.emit(_tower)\n\n\nfunc _on_buff_list_changed():\n\t_buff_container.load_buffs_for_unit(_unit)\n\n\nfunc _on_upgrade_button_mouse_entered():\n\tvar upgrade_id: int = TowerProperties.get_upgrade_id_for_tower(_tower.get_id())\n\n\tvar local_player: Player = PlayerManager.get_local_player()\n\n\tvar tooltip: String\n\tif upgrade_id != -1:\n\t\ttooltip = \"[color=GOLD]%s[/color]\\n\" % tr(\"UPGRADE_TOWER_BUTTON_TITLE\") \\\n\t\t+ \" \\n\" \\\n\t\t+ RichTexts.get_tower_text(upgrade_id, local_player)\n\telse:\n\t\ttooltip = tr(\"UPGRADE_TOWER_BUTTON_CANNOT_UPGRADE\")\n\n\tButtonTooltip.show_tooltip(_upgrade_button, tooltip, ButtonTooltip.Location.BOTTOM)\n\n\n# When tower menu is closed, deselect the unit which will\n# also close the menu\nfunc _on_close_button_pressed():\n\thide()\n\n\nfunc _on_tower_level_changed(_level_increased: bool):\n\t_update_level_label()\n\n\nfunc _on_autocast_button_mouse_entered(button: AutocastButton):\n\t_set_autocast_range_visible(button, true)\n\n\nfunc _on_autocast_button_mouse_exited(button: AutocastButton):\n\t_set_autocast_range_visible(button, false)\n\n\nfunc _on_ability_button_mouse_entered(button: AbilityButton):\n\t_set_ability_range_visible(button, true)\n\n\nfunc _on_ability_button_mouse_exited(button: AbilityButton):\n\t_set_ability_range_visible(button, false)\n\n\nfunc _on_details_button_pressed():\n\tdetails_pressed.emit()\n\n\n# NOTE: need to clear current unit when hiding to avoid\n# leaving invalid references in case unit got removed from\n# the game\nfunc _on_hidden():\n\tset_unit(null)\n"
  },
  {
    "path": "src/ui/unit_menu/unit_menu.tscn",
    "content": "[gd_scene load_steps=27 format=3 uid=\"uid://dcqjart40vpjy\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://bql5sxaowafw3\" path=\"res://resources/theme/wc3_theme.tres\" id=\"1_trhe5\"]\n[ext_resource type=\"Script\" path=\"res://src/ui/unit_menu/unit_menu.gd\" id=\"2_maep6\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ni34yd5liwbj\" path=\"res://src/ui/buttons/tower_button.tscn\" id=\"3_muugt\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://8xsklkw4jhlw\" path=\"res://src/ui/buttons/empty_unit_button.tscn\" id=\"4_bl3rp\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://c2wcu6a3ywhdl\" path=\"res://resources/theme/unit_menu/unit_level_label_normal.tres\" id=\"4_mpyt6\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://d0aesr1u8n1xt\" path=\"res://src/ui/buttons/ability_button.tscn\" id=\"5_iq4vd\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://ccys3jpdwu3ft\" path=\"res://src/ui/unit_menu/buff_group_editor.tscn\" id=\"5_v3s2e\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://60qc7jcvckhh\" path=\"res://assets/hud/misc3.png\" id=\"5_xoeuc\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://7hnklay7gedu\" path=\"res://src/ui/unit_menu/buff_container.tscn\" id=\"8_1niac\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bscc3lifv4bx4\" path=\"res://src/ui/unit_menu/progress_bar_with_label.tscn\" id=\"8_7iile\"]\n[ext_resource type=\"Texture2D\" uid=\"uid://gjoldkg0ife\" path=\"res://resources/icons/creep_icons/orc_normal.tres\" id=\"9_7dqoj\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://bxmrnso7h7np1\" path=\"res://resources/theme/unit_menu/exp_bar_background.tres\" id=\"9_lvj74\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://dab1qvryjypqs\" path=\"res://resources/theme/unit_menu/exp_bar_fill.tres\" id=\"10_6udoc\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://bg0camfo41dqc\" path=\"res://resources/theme/unit_menu/health_bar_background.tres\" id=\"13_10x1w\"]\n[ext_resource type=\"StyleBox\" uid=\"uid://1g0617tasr0m\" path=\"res://resources/theme/unit_menu/health_bar_fill.tres\" id=\"14_sjp88\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://beu73m131qhyk\" path=\"res://src/ui/unit_menu/item_container_panel.tscn\" id=\"15_c66ma\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://dy7728ew6n4n\" path=\"res://src/ui/unit_menu/tower_mini_details.tscn\" id=\"18_q420s\"]\n[ext_resource type=\"PackedScene\" uid=\"uid://bkknomxku1jcv\" path=\"res://src/ui/unit_menu/creep_mini_details.tscn\" id=\"19_fhhud\"]\n\n[sub_resource type=\"StyleBoxEmpty\" id=\"StyleBoxEmpty_0es22\"]\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_3p2ki\"]\ndevice = -1\nphysical_keycode = 85\nunicode = 117\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_bdake\"]\nevents = [SubResource(\"InputEventKey_3p2ki\")]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_fwy80\"]\natlas = ExtResource(\"5_xoeuc\")\nregion = Rect2(0, 128, 128, 128)\nmargin = Rect2(10, 10, 0, 20)\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7m6wk\"]\natlas = ExtResource(\"5_xoeuc\")\nregion = Rect2(256, 256, 128, 128)\n\n[sub_resource type=\"InputEventKey\" id=\"InputEventKey_8sgsd\"]\ndevice = -1\nphysical_keycode = 82\nunicode = 114\n\n[sub_resource type=\"Shortcut\" id=\"Shortcut_ocraw\"]\nevents = [SubResource(\"InputEventKey_8sgsd\")]\n\n[sub_resource type=\"AtlasTexture\" id=\"AtlasTexture_7oyt8\"]\natlas = ExtResource(\"5_xoeuc\")\nregion = Rect2(128, 256, 128, 128)\nmargin = Rect2(10, 10, 20, 20)\n\n[node name=\"UnitMenu\" type=\"PanelContainer\" node_paths=PackedStringArray(\"_tower_button\", \"_creep_button\", \"_level_label\", \"_reset_sell_button_timer\", \"_upgrade_button\", \"_sell_button\", \"_buff_container\", \"_ability_grid\", \"_exp_bar\", \"_health_bar\", \"_mana_bar\", \"_tower_mini_details\", \"_creep_mini_details\", \"_tower_inventory_panel\", \"_tower_inventory_outer_panel\", \"_buff_group_editor\")]\noffset_right = 1282.0\noffset_bottom = 342.0\nmouse_filter = 2\ntheme = ExtResource(\"1_trhe5\")\ntheme_override_styles/panel = SubResource(\"StyleBoxEmpty_0es22\")\nscript = ExtResource(\"2_maep6\")\n_tower_button = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer/TowerButton\")\n_creep_button = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer/CreepButton\")\n_level_label = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/LevelLabel\")\n_reset_sell_button_timer = NodePath(\"ResetSellButtonTimer\")\n_upgrade_button = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer/UpgradeButton\")\n_sell_button = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer/SellButton\")\n_buff_container = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer2/MarginContainer/BuffContainer\")\n_ability_grid = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\")\n_exp_bar = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer/ExpBar\")\n_health_bar = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer/HealthBar\")\n_mana_bar = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer/ManaBar\")\n_tower_mini_details = NodePath(\"HBoxContainer/MarginContainer/TowerMiniDetails\")\n_creep_mini_details = NodePath(\"HBoxContainer/MarginContainer/CreepMiniDetails\")\n_tower_inventory_panel = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/TowerInventoryOuterPanel/MarginContainer2/TowerInventoryPanel\")\n_tower_inventory_outer_panel = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/TowerInventoryOuterPanel\")\n_buff_group_editor = NodePath(\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer2/BuffGroupEditor\")\n\n[node name=\"ResetSellButtonTimer\" type=\"Timer\" parent=\".\"]\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\".\"]\nlayout_mode = 2\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\nmouse_filter = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\nmouse_filter = 2\ntheme_override_constants/margin_left = 55\ntheme_override_constants/margin_right = 50\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer\"]\nlayout_mode = 2\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2\"]\nlayout_mode = 2\n\n[node name=\"PanelContainer\" type=\"PanelContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer\"]\nlayout_mode = 2\ntheme = ExtResource(\"1_trhe5\")\ntheme_type_variation = &\"MainPanelContainer\"\n\n[node name=\"HBoxContainer\" type=\"HBoxContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/separation = 10\n\n[node name=\"TowerButton\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer\" instance=ExtResource(\"3_muugt\")]\nlayout_mode = 2\nsize_flags_vertical = 0\ntheme_type_variation = &\"UnitButtonBright\"\n_tooltip_location = 1\n_show_freshness = false\n\n[node name=\"CreepButton\" type=\"Button\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer\"]\nvisible = false\ncustom_minimum_size = Vector2(120, 120)\nlayout_mode = 2\nmouse_filter = 2\ntheme = ExtResource(\"1_trhe5\")\ntheme_type_variation = &\"UnitButtonBright\"\nicon = ExtResource(\"9_7dqoj\")\nicon_alignment = 1\nexpand_icon = true\n\n[node name=\"ExpBar\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer\" instance=ExtResource(\"8_7iile\")]\nlayout_mode = 2\ntooltip_text = \"UNIT_MENU_TOOLTIP_EXP\"\ntheme_override_styles/background = ExtResource(\"9_lvj74\")\ntheme_override_styles/fill = ExtResource(\"10_6udoc\")\n\n[node name=\"HealthBar\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer\" instance=ExtResource(\"8_7iile\")]\nvisible = false\nlayout_mode = 2\ntooltip_text = \"UNIT_MENU_TOOLTIP_HEALTH\"\ntheme_override_styles/background = ExtResource(\"13_10x1w\")\ntheme_override_styles/fill = ExtResource(\"14_sjp88\")\n\n[node name=\"ManaBar\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/VBoxContainer\" instance=ExtResource(\"8_7iile\")]\nlayout_mode = 2\ntooltip_text = \"UNIT_MENU_TOOLTIP_MANA\"\n\n[node name=\"Abilities\" type=\"PanelContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer\"]\nlayout_mode = 2\nsize_flags_vertical = 3\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -10\n\n[node name=\"Label\" type=\"Label\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelSectionTitle\"\ntext = \"UNIT_MENU_ABILITIES\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 10\ntheme_override_constants/margin_top = 20\ntheme_override_constants/margin_right = 10\ntheme_override_constants/margin_bottom = 10\n\n[node name=\"BackgroundGridForSizing\" type=\"GridContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2\"]\nlayout_mode = 2\ncolumns = 4\n\n[node name=\"EmptyUnitButton\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton2\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton3\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton4\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton5\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton6\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton7\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"EmptyUnitButton8\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/BackgroundGridForSizing\" instance=ExtResource(\"4_bl3rp\")]\nmodulate = Color(1, 1, 1, 0)\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"AbilityGrid\" type=\"GridContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2\"]\nlayout_mode = 2\ncolumns = 4\n\n[node name=\"Placeholder\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"5_iq4vd\")]\nlayout_mode = 2\n\n[node name=\"Placeholder2\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"5_iq4vd\")]\nlayout_mode = 2\n\n[node name=\"Placeholder3\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"5_iq4vd\")]\nlayout_mode = 2\n\n[node name=\"PlaceholderEmpty\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"4_bl3rp\")]\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"PlaceholderEmpty2\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"4_bl3rp\")]\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"PlaceholderEmpty3\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"4_bl3rp\")]\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"PlaceholderEmpty4\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"4_bl3rp\")]\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"PlaceholderEmpty5\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/Abilities/MarginContainer2/AbilityGrid\" instance=ExtResource(\"4_bl3rp\")]\ncustom_minimum_size = Vector2(85, 85)\nlayout_mode = 2\n\n[node name=\"TowerInventoryOuterPanel\" type=\"PanelContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer\"]\ncustom_minimum_size = Vector2(0, 100)\nlayout_mode = 2\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/TowerInventoryOuterPanel\"]\nlayout_mode = 2\nsize_flags_horizontal = 4\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -10\n\n[node name=\"Label\" type=\"Label\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/TowerInventoryOuterPanel/MarginContainer\"]\nlayout_mode = 2\ntheme_type_variation = &\"LabelSectionTitle\"\ntext = \"UNIT_MENU_ITEMS\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/TowerInventoryOuterPanel\"]\nlayout_mode = 2\ntheme_override_constants/margin_left = 15\ntheme_override_constants/margin_top = 20\ntheme_override_constants/margin_right = 15\ntheme_override_constants/margin_bottom = 20\n\n[node name=\"TowerInventoryPanel\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/HBoxContainer/PanelContainer/HBoxContainer/TowerInventoryOuterPanel/MarginContainer2\" instance=ExtResource(\"15_c66ma\")]\nlayout_mode = 2\nsize_flags_vertical = 4\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nmouse_filter = 2\ntheme_override_constants/margin_left = -20\ntheme_override_constants/margin_top = -20\ntheme_override_constants/margin_bottom = 40\n\n[node name=\"VBoxContainer2\" type=\"VBoxContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nmouse_filter = 2\n\n[node name=\"LevelLabel\" type=\"Label\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2\"]\ncustom_minimum_size = Vector2(80, 80)\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntooltip_text = \"UNIT_MENU_TOOLTIP_TOWER_LEVEL\"\nmouse_filter = 0\ntheme_override_colors/font_color = Color(0, 0, 0, 1)\ntheme_override_colors/font_outline_color = Color(0, 0, 0, 1)\ntheme_override_constants/outline_size = 3\ntheme_override_font_sizes/font_size = 32\ntheme_override_styles/normal = ExtResource(\"4_mpyt6\")\ntext = \"25\"\nhorizontal_alignment = 1\nvertical_alignment = 1\n\n[node name=\"VBoxContainer\" type=\"VBoxContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 3\ntheme_override_constants/separation = 10\n\n[node name=\"UpgradeButton\" type=\"Button\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer\"]\ncustom_minimum_size = Vector2(50, 50)\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntooltip_text = \"UNIT_MENU_TOOLTIP_UPGRADE\"\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nshortcut = SubResource(\"Shortcut_bdake\")\nshortcut_in_tooltip = false\nicon = SubResource(\"AtlasTexture_fwy80\")\nexpand_icon = true\n\n[node name=\"DetailsButton\" type=\"Button\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer\"]\ncustom_minimum_size = Vector2(50, 50)\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntooltip_text = \"Stat Details\"\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nicon = SubResource(\"AtlasTexture_7m6wk\")\nexpand_icon = true\n\n[node name=\"SellButton\" type=\"Button\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer\"]\ncustom_minimum_size = Vector2(50, 50)\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntooltip_text = \"UNIT_MENU_TOOLTIP_SELL\"\nfocus_mode = 0\ntheme_type_variation = &\"CircleButton\"\nshortcut = SubResource(\"Shortcut_ocraw\")\nshortcut_in_tooltip = false\nicon = SubResource(\"AtlasTexture_7oyt8\")\nexpand_icon = true\n\n[node name=\"MarginContainer2\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_vertical = 0\nmouse_filter = 2\ntheme_override_constants/margin_left = 55\ntheme_override_constants/margin_top = -50\ntheme_override_constants/margin_right = 50\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer2\"]\nlayout_mode = 2\nsize_flags_horizontal = 0\nsize_flags_vertical = 0\ntheme_override_constants/margin_top = -50\n\n[node name=\"BuffContainer\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer2/MarginContainer\" instance=ExtResource(\"8_1niac\")]\nlayout_mode = 2\n\n[node name=\"BuffGroupEditor\" parent=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer2\" instance=ExtResource(\"5_v3s2e\")]\nlayout_mode = 2\nsize_flags_horizontal = 8\nsize_flags_vertical = 0\n\n[node name=\"MarginContainer\" type=\"MarginContainer\" parent=\"HBoxContainer\"]\nlayout_mode = 2\ntheme_override_constants/margin_top = -40\n\n[node name=\"CreepMiniDetails\" parent=\"HBoxContainer/MarginContainer\" instance=ExtResource(\"19_fhhud\")]\nvisible = false\ncustom_minimum_size = Vector2(400, 332)\nlayout_mode = 2\nsize_flags_vertical = 0\n\n[node name=\"TowerMiniDetails\" parent=\"HBoxContainer/MarginContainer\" instance=ExtResource(\"18_q420s\")]\ncustom_minimum_size = Vector2(400, 332)\nlayout_mode = 2\nsize_flags_vertical = 0\n\n[connection signal=\"hidden\" from=\".\" to=\".\" method=\"_on_hidden\"]\n[connection signal=\"mouse_entered\" from=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer/UpgradeButton\" to=\".\" method=\"_on_upgrade_button_mouse_entered\"]\n[connection signal=\"pressed\" from=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer/UpgradeButton\" to=\".\" method=\"_on_upgrade_button_pressed\"]\n[connection signal=\"pressed\" from=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer/DetailsButton\" to=\".\" method=\"_on_details_button_pressed\"]\n[connection signal=\"pressed\" from=\"HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/VBoxContainer2/VBoxContainer/SellButton\" to=\".\" method=\"_on_sell_button_pressed\"]\n"
  },
  {
    "path": "src/unit/dummy_unit.gd",
    "content": "class_name DummyUnit extends Node2D\n\n# Base class for Projectiles and SpellDummy. A simpler\n# version of Unit that can't be buffed, has less events,\n# etc.\n\n\nvar _caster: Unit = null\nvar _damage_ratio: float = 1.0\nvar _crit_ratio: float = 0.0\nvar _damage_event_handler: Callable = Callable()\nvar _kill_event_handler: Callable = Callable()\nvar _cleanup_handler: Callable = Callable()\nvar _damage_bonus_to_size_map: Dictionary = {}\nvar _cleanup_done: bool = false\nvar _position_wc3: Vector3\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _ready():\n\t_caster.tree_exited.connect(_on_caster_tree_exited)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc set_position_wc3(value: Vector3):\n\t_position_wc3 = value\n\tposition.x = Utils.to_pixels(_position_wc3.x)\n\tposition.y = Utils.to_pixels(_position_wc3.y / 2)\n\n\nfunc set_position_wc3_2d(value: Vector2):\n\tset_position_wc3(Vector3(value.x, value.y, get_z()))\n\n\nfunc set_z(z: float):\n\tvar new_position_wc3: Vector3 = Vector3(_position_wc3.x, _position_wc3.y, z)\n\tset_position_wc3(new_position_wc3)\n\n\nfunc get_position_canvas() -> Vector2:\n\treturn position\n\n\nfunc get_position_wc3_2d() -> Vector2:\n\tvar position_2d: Vector2 = Vector2(_position_wc3.x, _position_wc3.y)\n\n\treturn position_2d\n\n\nfunc get_position_wc3() -> Vector3:\n\treturn _position_wc3\n\n\n# NOTE: unit.getX() in JASS\nfunc get_x() -> float:\n\treturn _position_wc3.x\n\n\n# NOTE: unit.getY() in JASS\nfunc get_y() -> float:\n\treturn _position_wc3.y\n\n\n# NOTE: unit.getZ() in JASS\nfunc get_z() -> float:\n\treturn _position_wc3.z\n\n\n# NOTE: dummyUnit.doSpellDamage() in JASS\n# \n# NOTE: crit ratio is used directly, without doing a random\n# roll because it's intended that tower does a random roll\n# once and then passes the result to DummyUnit(Projectile or\n# Spell). The DummyUnit then becomes crit or non-crit at the\n# moment of creation and stays that way while it is alive.\nfunc do_spell_damage(target: Unit, damage: float):\n#\tNOTE: caster may become invalid if tower launches a\n#\tprojectile and is then sold before projectile reaches\n#\tthe target.\n\tvar caster_is_valid: bool = Utils.unit_is_valid(_caster)\n\tif !caster_is_valid:\n\t\treturn\n\n\tvar size_mod: float = _get_mod_for_size(target)\n\tvar damage_intermediate: float = damage * _damage_ratio * size_mod\n\tvar damage_killed_unit: bool = _caster.do_spell_damage(target, damage_intermediate, _crit_ratio)\n\n\tif damage_killed_unit:\n\t\tif _kill_event_handler.is_valid():\n\t\t\tvar killed_event: Event = Event.new(target)\n\t\t\t_kill_event_handler.call(killed_event, self)\n\telse:\n\t\tif _damage_event_handler.is_valid():\n\t\t\tvar damage_event: Event = Event.new(target)\n\t\t\t_damage_event_handler.call(damage_event, self)\n\n\n# NOTE: dummyUnit.doSpellDamageAoE() in JASS\nfunc do_spell_damage_aoe(center: Vector2, radius: float, damage: float, sides_ratio: float):\n\tvar creep_list: Array = Utils.get_units_in_range(_caster, TargetType.new(TargetType.CREEPS), center, radius)\n\n\tfor creep in creep_list:\n\t\tvar damage_for_creep: float = Utils.get_aoe_damage(center, creep, radius, damage, sides_ratio)\n\t\tdo_spell_damage(creep, damage_for_creep)\n\n\n# Deals aoe damage from the position of the dummy unit\n# NOTE: dummyUnit.doSpellDamagePBAoE() in JASS\nfunc do_spell_damage_pb_aoe(radius: float, damage: float, sides_ratio: float):\n\tvar center: Vector2 = get_position_wc3_2d()\n\tdo_spell_damage_aoe(center, radius, damage, sides_ratio)\n\n\n# NOTE: you must call this instead of queue_free(), so that\n# tree_exited() signal is emitted immediately\nfunc remove_from_game():\n\tvar parent: Node = get_parent()\n\n\tif parent != null && is_inside_tree():\n\t\tparent.remove_child(self)\n\n\tqueue_free()\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _cleanup():\n\tif _cleanup_done:\n\t\treturn\n\n\t_cleanup_done = true\n\n#\tNOTE: cleanup handler is valid only in Projectile\n#\tsubclass\n\tif _cleanup_handler.is_valid():\n\t\t_cleanup_handler.call(self)\n\n\tremove_from_game()\n\n\n# Returns damage modifier based on custom damage table.\n# Normally this will be just 1.0.\n# \n# NOTE: this is a bit tricky because Unit._do_damage()\n# applies tower's \"dmg to size\" modifier on top of this modifier.\n# For example, if tower has DMG_TO_MASS = 0.3 and bonus damage\n# in custom damage table is +95% then total damage should be\n# 30%+95%=125%. For this, we need to divide the damage bonus\n# by \"dmg to size\" mod.\n# 0.95 / 0.3 = 3.166\n# mod_for_size then equals = 1.0 + 3.166 = 4.166\n# Then later, during final calculations the tower's size mod is applied:\n# 4.166 * 0.3 = 1.25\n# And we get the desired end result\nfunc _get_mod_for_size(target: Unit) -> float:\n\tif !target is Creep:\n\t\treturn 1.0\n\n\tvar creep: Creep = target as Creep\n\tvar creep_size: CreepSize.enm = creep.get_size()\n\tvar dmg_to_size_mod: float = _caster.get_damage_to_size(creep_size)\n\tvar damage_bonus: float = _damage_bonus_to_size_map.get(creep_size, 0.0)\n\tvar mod_for_size: float = 1.0 + Utils.divide_safe(damage_bonus, dmg_to_size_mod)\n\n\treturn mod_for_size\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_caster_tree_exited():\n\t_cleanup()\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc get_caster() -> Unit:\n\treturn _caster\n\n\n# NOTE: dummyUnit.setDamageEvent() in JASS\nfunc set_damage_event(handler: Callable):\n\t_damage_event_handler = handler\n\n\n# NOTE: dummyUnit.setKillEvent() in JASS\nfunc set_kill_event(handler: Callable):\n\t_kill_event_handler = handler\n\n\nfunc get_dmg_ratio() -> float:\n\treturn _damage_ratio\n\n\nfunc get_crit_ratio() -> float:\n\treturn _crit_ratio\n"
  },
  {
    "path": "src/unit/dummy_unit.tscn",
    "content": "[gd_scene load_steps=2 format=3 uid=\"uid://by01sg1a1yihc\"]\n\n[ext_resource type=\"Script\" path=\"res://src/unit/dummy_unit.gd\" id=\"1_5wu48\"]\n\n[node name=\"DummyUnit\" type=\"Node2D\"]\nscript = ExtResource(\"1_5wu48\")\n"
  },
  {
    "path": "src/unit/iterate.gd",
    "content": "class_name Iterate\n\n\n# Iterate is a wrapper over get_units_in_range() f-n which\n# stores the resulting unit list and allows iterating over\n# units.\n\n\nvar _next_list: Array[Unit] = []\n\n\nfunc _init(caster: Unit, center_pos: Vector2, target_type: TargetType, radius: float):\n\t_next_list = Utils.get_units_in_range(caster, target_type, center_pos, radius)\n\n\n# NOTE: Iterate.overUnitsInRangeOf() in JASS\nstatic func over_units_in_range_of(caster: Unit, target_type: TargetType, center_pos: Vector2, radius: float) -> Iterate:\n\tvar it: Iterate = Iterate.new(caster, center_pos, target_type, radius)\n\n\treturn it\n\n\n# NOTE: Iterate.overUnitsInRangeOfCaster() in JASS\nstatic func over_units_in_range_of_caster(caster: Unit, target_type: TargetType, radius: float) -> Iterate:\n\tvar center_pos: Vector2 = caster.get_position_wc3_2d()\n\tvar it: Iterate = Iterate.new(caster, center_pos, target_type, radius)\n\n\treturn it\n\n\n# NOTE: Iterate.overUnitsInRangeOfUnit() in JASS\nstatic func over_units_in_range_of_unit(caster: Unit, target_type: TargetType, center: Unit, radius: float) -> Iterate:\n\tvar center_pos: Vector2 = center.get_position_wc3_2d()\n\tvar it: Iterate = Iterate.new(caster, center_pos, target_type, radius)\n\n\treturn it\n\n\nstatic func over_corpses_in_range(caster: Unit, center_pos: Vector2, radius: float) -> Iterate:\n\tvar it: Iterate = Iterate.new(caster, center_pos, TargetType.new(TargetType.CORPSES), radius)\n\n\treturn it\n\n\n# NOTE: iterate.next() in JASS\nfunc next() -> Unit:\n\t_remove_invalid_units()\n\n\tvar next_unit: Unit\n\n\tif !_next_list.is_empty():\n\t\tnext_unit = _next_list.pop_front()\n\telse:\n\t\tnext_unit = null\n\n\treturn next_unit\n\n\n# NOTE: iterate.nextRandom() in JASS\nfunc next_random() -> Unit:\n\t_remove_invalid_units()\n\t\n\tvar next_unit: Unit\n\n\tif !_next_list.is_empty():\n\t\tnext_unit = Utils.pick_random(Globals.synced_rng, _next_list)\n\t\t_next_list.erase(next_unit)\n\telse:\n\t\tnext_unit = null\n\n\treturn next_unit\n\n\n# NOTE: iterate.nextCorpse() in JASS\nfunc next_corpse() -> Unit:\n\tvar corpse: Unit = next()\n\n\treturn corpse\n\n\n# NOTE: iterate.destroy() in JASS\n# JASS engine had this f-n but it's not needed in Godot\n# engine - do not call it.\n# func destroy():\n\t# pass\n\n\n# NOTE: iterate.count() in JASS\nfunc count() -> int:\n\t_remove_invalid_units()\n\n\treturn _next_list.size()\n\n\n# NOTE: need to remove invalid units before each call to\n# next() or count() because units may be killed or removed\n# from the game while Iterate is used.\nfunc _remove_invalid_units():\n\t_next_list = _next_list.filter(\n\t\tfunc(unit) -> bool:\n\t\t\tvar unit_is_valid: bool = Utils.unit_is_valid(unit)\n\n\t\t\treturn unit_is_valid\n\t)\n"
  },
  {
    "path": "src/unit/selection_indicator.gd",
    "content": "class_name SelectionIndicator extends Node2D\n\n# Draws a circle to indicate unit being selected or unit\n# being hovered by mouse.\n\n# NOTE: set this to change size of drawn circle\nvar visual_size: float = 10.0\n\n\nfunc _ready():\n\ttransform = Transform2D().scaled(Vector2(1, 0.5))\n\n\nfunc _draw():\n\tdraw_arc(Vector2.ZERO, visual_size, deg_to_rad(0), deg_to_rad(360), 100, Color.WHITE, 10, true)\n"
  },
  {
    "path": "src/unit/unit.gd",
    "content": "class_name Unit\nextends Node2D\n\n# Unit is a base class for Towers and Creeps. Keeps track of\n# buffs and modifications. Emits signals for events which are used by buffs.\n\n# NOTE: can't use static typing for Buff because of cyclic\n# dependency\n\n# NOTE: see comments in buff_type.gd for detailed info about\n# unit events. For example, add_event_on_level_changed()\n# function.\n# \n# NOTE: if a tower is created at level greater than 0, this\n# level_changed() signal will NOT be emitted. If your tower\n# script needs to scale some values with tower level, then\n# you should add such logic to BOTH on_level_changed() and\n# TowerBehavior.on_create().\nsignal level_changed(level_increased: bool)\nsignal attack(event)\nsignal attacked(event)\nsignal dealt_damage(event)\nsignal damaged(event)\nsignal kill(event)\nsignal death(event)\nsignal health_changed()\nsignal mana_changed()\nsignal spell_casted(event: Event)\nsignal spell_targeted(event: Event)\nsignal buff_list_changed()\nsignal buff_group_changed()\nsignal selected_changed()\nsignal hovered_changed()\n\n\nenum DamageSource {\n\tAttack,\n\tSpell\n}\n\nenum BodyPart {\n\tOVERHEAD,\n\tHEAD,\n\tCHEST,\n\tORIGIN\n}\n\n\nconst REGEN_PERIOD: float = 1.0\n\n# NOTE: need to have \"_unit_\" prefix in names to avoid\n# conflicts with variables in subclasses\nvar _visual_node: Node2D = null\nvar _unit_sprite: Node2D = null\nvar _unit_sprite_parent: Node2D = null\nvar _unit_selection_outline_parent: Node2D = null\nvar _sprite_dimensions: Vector2 = Vector2(100, 100)\n\n# NOTE: userInt/userInt2/... in JASS\nvar user_int: int = 0\nvar user_int2: int = 0\nvar user_int3: int = 0\nvar user_real: float = 0.0\nvar user_real2: float = 0.0\nvar user_real3: float = 0.0\n\n# NOTE: crit bonus in terms of number of crits. The logic is\n# different for attack vs spell. For attack crits, the bonus\n# is applied only to normal tower attacks. Bonus is not\n# applied to do_attack_damage() called from other scripts.\n# This is because it would be confusing for an item like\n# \"every 5th attack is critical\" to produce no visible\n# change because tower is consuming crit bonus via some\n# other attack damage which is not visible to the player.\n# For spells, the bonus is applied to all instances of spell\n# damage, which includes calls to do_spell_damage(), spells\n# casted using Cast class, etc.\nvar _bonus_crit_count_for_next_attack: int = 0\nvar _bonus_crit_ratio_for_next_attack: float = 0.0\nvar _bonus_crit_count_for_next_spell: int = 0\n\nvar _level: int = 0\nvar _buff_map: Dictionary\nvar _buff_list: Array[Buff] = []\nvar _direct_modifier_list: Array\nvar _base_health: float = 100.0\nvar _health: float = 0.0\nvar _lowest_health: float = 0.0\nvar _base_health_regen: float = 0.0\nvar _immune: bool = false\nvar _selected: bool = false\nvar _hovered: bool = false\n# NOTE: experience is stored as centiunits (multiply by 100)\n# to preserve fractional values while avoiding float precision\n# issues in multiplayer. For example, 1.5 exp is stored as 150.\nvar _experience_centi: int = 0\nvar _mana: float = 0.0\nvar _base_mana: float = 0.0\nvar _base_mana_regen: float = 0.0\nvar _base_armor: float = 0.0\nvar _kill_count: int = 0\nvar _best_hit: float = 0.0\nvar _attack_damage_dealt: float = 0.0\nvar _spell_damage_dealt: float = 0.0\nvar _damage_dealt_total: float = 0.0\nvar _damage_dealt_to_wave_map: Dictionary = {}\nvar _attack_damage_dealt_to_wave_map: Dictionary = {}\nvar _spell_damage_dealt_to_wave_map: Dictionary = {}\nvar _ethereal_count: int = 0\nvar _silence_count: int = 0\nvar _stun_count: int = 0\nvar _stun_effect_id: int = -1\nvar _autocast_list: Array[Autocast] = []\nvar _aura_list: Array[Aura] = []\nvar _target_bitmask: int = 0x0\nvar _buff_groups: Dictionary = {}\nvar _player: Player = null\nstatic var _uid_max: int = 1\nvar _uid: int = 0\n# NOTE: up axis is positive z, down axis is negative z.\nvar _position_wc3: Vector3\nvar _total_stun_duration: float = 0.0\n\nvar _selection_indicator: Node = null\nvar _unit_selection_outline: Node = null\n\n\n# NOTE: logic for default values is the following. If\n# property is multiplied, then it's default is 1.0 so that\n# by default it doesn't change anything. If property is\n# added, then default is 0.0 so that by default it doesn't\n# change anything.\n#\n# Execeptions are MOD_ATK_CRIT_DAMAGE, MOD_SPELL_CRIT_DAMAGE\n# which start at 1.5 because by default crits increase\n# damage by 50%. MOD_ATK_CRIT_CHANCE and\n# MOD_SPELL_CRIT_CHANCE start at 0.01 because by default\n# crit chance is 1%.\nvar _mod_value_map: Dictionary = {\n\tModificationType.enm.MOD_ATK_CRIT_CHANCE: Constants.INNATE_MOD_ATK_CRIT_CHANCE,\n\tModificationType.enm.MOD_ATK_CRIT_DAMAGE: Constants.INNATE_MOD_ATK_CRIT_DAMAGE,\n\tModificationType.enm.MOD_TRIGGER_CHANCES: 1.0,\n\tModificationType.enm.MOD_SPELL_DAMAGE_DEALT: 1.0,\n\tModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED: 1.0,\n\tModificationType.enm.MOD_SPELL_CRIT_DAMAGE: Constants.INNATE_MOD_SPELL_CRIT_DAMAGE,\n\tModificationType.enm.MOD_SPELL_CRIT_CHANCE: Constants.INNATE_MOD_SPELL_CRIT_CHANCE,\n\tModificationType.enm.MOD_BOUNTY_GRANTED: 1.0,\n\tModificationType.enm.MOD_BOUNTY_RECEIVED: 1.0,\n\tModificationType.enm.MOD_EXP_GRANTED: 1.0,\n\tModificationType.enm.MOD_EXP_RECEIVED: 1.0,\n\tModificationType.enm.MOD_BUFF_DURATION: 1.0,\n\tModificationType.enm.MOD_DEBUFF_DURATION: 1.0,\n\tModificationType.enm.MOD_MOVESPEED: 1.0,\n\tModificationType.enm.MOD_MOVESPEED_ABSOLUTE: 0.0,\n\tModificationType.enm.MOD_MULTICRIT_COUNT: 1.0,\n\tModificationType.enm.MOD_ATK_DAMAGE_RECEIVED: 1.0,\n\tModificationType.enm.MOD_ATTACKSPEED: 1.0,\n\tModificationType.enm.MOD_DPS_ADD: 0.0,\n\n\tModificationType.enm.MOD_ITEM_CHANCE_ON_KILL: 1.0,\n\tModificationType.enm.MOD_ITEM_QUALITY_ON_KILL: 1.0,\n\tModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH: 1.0,\n\tModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH: 1.0,\n\n\tModificationType.enm.MOD_ARMOR: 0.0,\n\tModificationType.enm.MOD_ARMOR_PERC: 1.0,\n\n\tModificationType.enm.MOD_DAMAGE_BASE: 0.0,\n\tModificationType.enm.MOD_DAMAGE_BASE_PERC: 1.0,\n\tModificationType.enm.MOD_DAMAGE_ADD: 0.0,\n\tModificationType.enm.MOD_DAMAGE_ADD_PERC: 1.0,\n\n\tModificationType.enm.MOD_MANA: 0.0,\n\tModificationType.enm.MOD_MANA_PERC: 1.0,\n\tModificationType.enm.MOD_MANA_REGEN: 0.0,\n\tModificationType.enm.MOD_MANA_REGEN_PERC: 1.0,\n\tModificationType.enm.MOD_HP: 0.0,\n\tModificationType.enm.MOD_HP_PERC: 1.0,\n\tModificationType.enm.MOD_HP_REGEN: 0.0,\n\tModificationType.enm.MOD_HP_REGEN_PERC: 1.0,\n\n\tModificationType.enm.MOD_DMG_TO_MASS: 1.0,\n\tModificationType.enm.MOD_DMG_TO_NORMAL: 1.0,\n\tModificationType.enm.MOD_DMG_TO_CHAMPION: 1.0,\n\tModificationType.enm.MOD_DMG_TO_BOSS: 1.0,\n\tModificationType.enm.MOD_DMG_TO_AIR: 1.0,\n\n\tModificationType.enm.MOD_DMG_TO_UNDEAD: 1.0,\n\tModificationType.enm.MOD_DMG_TO_MAGIC: 1.0,\n\tModificationType.enm.MOD_DMG_TO_NATURE: 1.0,\n\tModificationType.enm.MOD_DMG_TO_ORC: 1.0,\n\tModificationType.enm.MOD_DMG_TO_HUMANOID: 1.0,\n\tModificationType.enm.MOD_DMG_TO_CHALLENGE: 1.0,\n\n\tModificationType.enm.MOD_DMG_FROM_ASTRAL: 1.0,\n\tModificationType.enm.MOD_DMG_FROM_DARKNESS: 1.0,\n\tModificationType.enm.MOD_DMG_FROM_NATURE: 1.0,\n\tModificationType.enm.MOD_DMG_FROM_FIRE: 1.0,\n\tModificationType.enm.MOD_DMG_FROM_ICE: 1.0,\n\tModificationType.enm.MOD_DMG_FROM_STORM: 1.0,\n\tModificationType.enm.MOD_DMG_FROM_IRON: 1.0,\n\t\n\tModificationType.enm.MOD_DMG_TOTAL_MULTIPLIER: 1.0,\n}\n\n\n#########################\n###     Built-in      ###\n#########################\n\nfunc _init():\n\tfor mod_type in ModificationType.enm.values():\n\t\tif !_mod_value_map.has(mod_type):\n\t\t\tpush_error(\"No default value defined for modification type: \", mod_type)\n\n\tfor buff_group in range(1, Constants.BUFFGROUP_COUNT + 1):\n\t\t_buff_groups[buff_group] = BuffGroupMode.enm.NONE\n\n\nfunc _ready():\n\tif _player == null:\n\t\tpush_error(\"Unit was not assigned a player. You must assign a player to unit before adding it to tree, using Unit.set_player().\")\n\n#\tNOTE: UID must be assigned before _ready() is called (in\n#\tset_player()) to ensure deterministic multiplayer sync.\n\tif _uid == 0:\n\t\tpush_error(\"Unit UID was not assigned before _ready(). This should never happen. UID must be assigned in set_player().\")\n\n\tGroupManager.add(\"units\", self, get_uid())\n\n\t_target_bitmask = TargetType.make_unit_bitmask(self)\n\n\t_selection_indicator = SelectionIndicator.new()\n\t_selection_indicator.hide()\n\t_selection_indicator.z_index = -1\n\tadd_child(_selection_indicator)\n\t\n\tvar regen_timer: ManualTimer = ManualTimer.new()\n\tregen_timer.one_shot = false\n\tregen_timer.wait_time = REGEN_PERIOD\n\tregen_timer.timeout.connect(_on_regen_timer_timeout)\n\tadd_child(regen_timer)\n\tregen_timer.start()\n\n\tvar builder: Builder = get_player().get_builder()\n\tbuilder.apply_effects(self)\n\n#\tNOTE: add dummy sprite and selection outline, in case\n#\tsome Unit subclass doesn't set them up. This prevents\n#\tnull access.\n\t_unit_sprite = Sprite2D.new()\n\t_unit_sprite_parent = Node2D.new()\n\t_unit_sprite_parent.add_child(_unit_sprite)\n\tadd_child(_unit_sprite_parent)\n\n\t_unit_selection_outline = Sprite2D.new()\n\tvar selection_shader: ShaderMaterial = Preloads.outline_shader.duplicate()\n\t_unit_selection_outline.set_material(selection_shader)\n\t_unit_selection_outline_parent = Node2D.new()\n\t_unit_selection_outline_parent.add_child(_unit_selection_outline)\n\tadd_child(_unit_selection_outline_parent)\n\n\n#########################\n###       Public      ###\n#########################\n\nfunc get_buff_list() -> Array[Buff]:\n\treturn _buff_list\n\n\nfunc update(delta: float):\n\tif is_stunned():\n\t\t_total_stun_duration += delta\n\n\nfunc set_unit_scale(value: float):\n\t_unit_sprite_parent.scale = value * Vector2.ONE\n\t_unit_selection_outline_parent.scale = value * Vector2.ONE\n\n\nfunc get_unit_scale() -> float:\n\treturn _unit_sprite_parent.scale.x\n\n\nfunc get_uid() -> int:\n\treturn _uid\n\n\n# NOTE: you must call this instead of queue_free(), so that\n# tree_exited() signal is emitted immediately\nfunc remove_from_game():\n\tvar parent: Node = get_parent()\n\n\tif parent != null && is_inside_tree():\n\t\tparent.remove_child(self)\n\n\tqueue_free()\n\n\nfunc set_player(player: Player):\n\t_player = player\n\n#\tNOTE: assign UID here instead of in _ready() to ensure\n#\tdeterministic assignment based on spawn order. UIDs must\n#\tbe the same on all clients for multiplayer sync.\n#\tThe _ready() function can be called in different order\n#\ton different clients, causing UID mismatches.\n\tif _uid == 0:\n\t\t_uid = _uid_max\n\t\t_uid_max += 1\n\n\n# Removes the most recent buff. Returns true if there was a\n# buff to remove and false otherwise.\n# NOTE: unit.purgeBuff() in JASS\nfunc purge_buff(friendly: bool) -> bool:\n\tvar target_buff: Buff = null\n\n\tfor buff in _buff_list:\n\t\tvar friendly_match: bool = buff.is_friendly() == friendly\n\n\t\tif buff.is_purgable() && friendly_match:\n\t\t\ttarget_buff = buff\n\n\t\t\tbreak\n\n\tif target_buff != null:\n\t\ttarget_buff.purge_buff()\n\n\t\treturn true\n\telse:\n\t\treturn false\n\n\n# Triggers REFRESH event for all buffs applied by auras of\n# this unit.\n# NOTE: Unit.refreshAuras() in JASS\nfunc refresh_auras():\n\tfor aura in _aura_list:\n\t\taura.refresh()\n\n\n# NOTE: this f-n and add_modified_attack_crit() affect only\n# the tower's regular attack. They have no effect on calls\n# to do_attack_damage() in tower scripts.\n# NOTE: unit.addAttackCrit() in JASS\nfunc add_attack_crit():\n\t_bonus_crit_count_for_next_attack = _bonus_crit_count_for_next_attack + 1\n\t_bonus_crit_ratio_for_next_attack += get_prop_atk_crit_damage() - 1.0\n\n\n# NOTE: unit.addCustomAttackCrit() in JASS\nfunc add_custom_attack_crit(custom_crit_ratio: float):\n\t_bonus_crit_count_for_next_attack = _bonus_crit_count_for_next_attack + 1\n\t_bonus_crit_ratio_for_next_attack = custom_crit_ratio\n\n\n# NOTE: unit.addModifiedAttackCrit() in JASS\nfunc add_modified_attack_crit(crit_damage_add: float, crit_damage_multiply: float):\n\t_bonus_crit_count_for_next_attack = _bonus_crit_count_for_next_attack + 1\n\t_bonus_crit_ratio_for_next_attack = (get_prop_atk_crit_damage() - 1.0) * crit_damage_multiply + crit_damage_add\n\n\n# NOTE: this f-n affects all instances of spell damage,\n# including calls to do_spell_damage() in tower scripts.\n# NOTE: unit.addSpellCrit() in JASS\nfunc add_spell_crit():\n\t_bonus_crit_count_for_next_spell += 1\n\n\n# NOTE: unit.addManaPerc() in JASS\nfunc add_mana_perc(ratio: float):\n\tvar overall_mana: float = get_overall_mana()\n\tvar mana_added: float = ratio * overall_mana\n\tadd_mana(mana_added)\n\n\n# NOTE: unit.addMana() in JASS\nfunc add_mana(mana_added: float):\n\tvar new_mana: float = _mana + mana_added\n\tset_mana(new_mana)\n\n\nfunc add_autocast(autocast: Autocast):\n\tautocast.set_caster(self)\n\t_autocast_list.append(autocast)\n\tadd_child(autocast)\n\n\nfunc add_aura(aura_id: int, object_with_buff_var: Object):\n\tvar aura: Aura = Aura.make(aura_id, object_with_buff_var, self)\n\t_aura_list.append(aura)\n\tadd_child(aura)\n\n\n# Unaffected by tower exp ratios. Levels up unit if added\n# exp pushes the unit past the level up threshold.\n# NOTE: unit.addExpFlat() in JASS\nfunc add_exp_flat(amount: float):\n\t_change_experience(amount)\n\n\n# Affected by tower exp ratios.\n# NOTE: unit.addExp() in JASS\nfunc add_exp(amount_no_bonus: float):\n\tvar received_mod: float = get_prop_exp_received()\n\tvar amount: float = amount_no_bonus * received_mod\n\t_change_experience(amount)\n\n\n# Unaffected by tower exp ratios. Returns how much\n# experience was actually removed. How much was actually\n# removed may be less than requested if the unit has less\n# mana than should be removed. In that case unit's mana gets\n# set to 0.\n# NOTE: unit.removeExpFlat() in JASS\nfunc remove_exp_flat(amount: float) -> float:\n\tvar actual_change: float = _change_experience(-amount)\n\tvar actual_removed: float = abs(actual_change)\n\n\treturn actual_removed\n\n\n# Affected by \"exp received\" modification.\n# NOTE: unit.removeExp() in JASS\nfunc remove_exp(amount_no_bonus: float) -> float:\n\tvar received_mod: float = get_prop_exp_received()\n\tvar amount: float = Utils.divide_safe(amount_no_bonus, received_mod)\n\tvar actual_change: float = _change_experience(-amount)\n\tvar actual_removed: float = abs(actual_change)\n\n\treturn actual_removed\n\n\n# NOTE: unit.calcChance() in JASS\nfunc calc_chance(chance_base: float) -> bool:\n\tvar mod_trigger_chances: float = get_prop_trigger_chances()\n\tvar chance: float = chance_base * mod_trigger_chances\n\tvar success: bool = Utils.rand_chance(Globals.synced_rng, chance)\n\n\treturn success\n\n\n# \"Bad\" chance is for events that decrease tower's\n# perfomance, for example missing attack. Higher value of\n# MOD_TRIGGER_CHANCES decreases the chance of bad things\n# happening.\n# NOTE: unit.calcBadChance() in JASS\nfunc calc_bad_chance(chance: float) -> bool:\n\tvar mod_trigger_chances: float = get_prop_trigger_chances()\n\tvar final_chance: float = Utils.divide_safe(chance, mod_trigger_chances)\n\tvar success: bool = Utils.rand_chance(Globals.synced_rng, final_chance)\n\n\treturn success\n\n\n# NOTE: normally spells can't multicrit but if both normal\n# crit and extra crit from add_spell_crit() happen at the\n# same time, then that's effectively a multicrit.\n# NOTE: unit.calcSpellCrit() in JASS\nfunc calc_spell_crit(bonus_chance: float, bonus_damage: float) -> float:\n\tvar crit_chance: float = get_spell_crit_chance() + bonus_chance\n\tvar crit_damage: float = get_spell_crit_damage() + bonus_damage\n\n\tvar crit_count: int = 0\n\n\tvar crit_success: bool = Utils.rand_chance(Globals.synced_rng, crit_chance)\n\tif crit_success:\n\t\tcrit_count += 1\n\n\tcrit_count += _bonus_crit_count_for_next_spell\n\t_bonus_crit_count_for_next_spell = 0\n\n\tvar crit_ratio: float = 1.0\n\n\tfor i in range(0, crit_count):\n\t\tcrit_ratio += crit_damage - 1.0\n\n\treturn crit_ratio\n\n\n# NOTE: unit.calcSpellCritNoBonus() in JASS\nfunc calc_spell_crit_no_bonus() -> float:\n\tvar result: float = calc_spell_crit(0.0, 0.0)\n\n\treturn result\n\n\n# Returns a randomly calculate crit bonus, no multicrit,\n# either crit or not crit.\n# NOTE: unit.calcAttackCrit() in JASS\nfunc calc_attack_crit(bonus_chance: float, bonus_damage: float) -> float:\n\tvar crit_chance: float = get_prop_atk_crit_chance() + bonus_chance\n\tvar crit_damage: float = get_prop_atk_crit_damage() + bonus_damage\n\n\tvar crit_success: bool = Utils.rand_chance(Globals.synced_rng, crit_chance)\n\n\tif crit_success:\n\t\treturn crit_damage\n\telse:\n\t\treturn 1.0\n\n\n# NOTE: unit.calcAttackCritNoBonus() in JASS\nfunc calc_attack_crit_no_bonus() -> float:\n\tvar result: float = calc_attack_crit(0.0, 0.0)\n\n\treturn result\n\n\n# Returns a randomly calculated crit bonus (starts at 1.0),\n# taking into account multicrit.\n# 0 crits, 150% crit damage = 1.0\n# 1 crit, 150% crit damage = 1.5\n# 3 crits, 150% crit damage = 1.0 + 0.5 + 0.5 + 0.5 = 2.5\n# NOTE: unit.calcAttackMulticrit() in JASS\nfunc calc_attack_multicrit(bonus_multicrit: float, bonus_chance: float, bonus_damage: float) -> float:\n\tvar crit_count: int = _generate_crit_count(bonus_multicrit, bonus_chance)\n\tvar crit_damage: float = _calc_attack_multicrit_from_crit_count(crit_count, bonus_damage)\n\n\treturn crit_damage\n\n\n# NOTE: no such function in JASS. Added for convenience\n# because calc_attack_multicrit(0, 0, 0) is called very\n# often.\nfunc calc_attack_multicrit_no_bonus() -> float:\n\treturn calc_attack_multicrit(0, 0, 0)\n\n\n# NOTE: unit.doSpellDamage() in JASS\nfunc do_spell_damage(target: Unit, damage: float, crit_ratio: float) -> bool:\n\tvar caster: Unit = self\n\tvar dealt_mod: float = caster.get_prop_spell_damage_dealt()\n\tvar received_mod: float = target.get_prop_spell_damage_received()\n\tvar damage_total: float = damage * dealt_mod * received_mod\n\tvar is_main_target: bool = false\n\tvar emit_damage_event: bool = false\n\n\tvar killed_unit: bool = _do_damage(target, damage_total, crit_ratio, DamageSource.Spell, is_main_target, emit_damage_event)\n\n\treturn killed_unit\n\n\n# NOTE: unit.doAttackDamage() in JASS\nfunc do_attack_damage(target: Unit, damage_base: float, crit_ratio: float, crit_count: int = -1, is_main_target: bool = false, emit_damage_event: bool = false):\n\tvar attack_type: AttackType.enm = get_attack_type()\n\tdo_custom_attack_damage(target, damage_base, crit_ratio, attack_type, crit_count, is_main_target, emit_damage_event)\n\n\n# NOTE: unit.doCustomAttackDamage() in JASS\nfunc do_custom_attack_damage(target: Unit, damage_base: float, crit_ratio: float, attack_type: AttackType.enm, crit_count: int = -1, is_main_target: bool = false, emit_damage_event: bool = false):\n\tvar armor_mod: float = 1.0 - target.get_current_armor_damage_reduction()\n\tvar received_mod: float = target.get_prop_atk_damage_received()\n\n\tvar damage: float = damage_base * armor_mod * received_mod\n\n\tvar deals_no_damage_to_immune: bool = AttackType.deals_no_damage_to_immune(attack_type)\n\n\tif target.is_immune() && deals_no_damage_to_immune:\n\t\tdamage = 0\n\n\t_do_damage(target, damage, crit_ratio, DamageSource.Attack, is_main_target, emit_damage_event, attack_type, crit_count)\n\n\n# NOTE: sides_ratio parameter specifies how much less damage\n# is dealt to units that are on the \"sides\" of the aoe\n# circle. For example, if sides_ratio is set to 0.3 then\n# units on the sides will receive 30% less damage than those\n# in the center.\n# \n# NOTE: unit.doAttackDamageAoEUnit() in JASS\nfunc do_attack_damage_aoe_unit(target: Unit, radius: float, damage: float, crit_ratio: float, sides_ratio: float):\n\tvar aoe_center: Vector2 = target.get_position_wc3_2d()\n\tvar creep_list: Array = Utils.get_units_in_range(self, TargetType.new(TargetType.CREEPS), aoe_center, radius)\n\n\tfor creep in creep_list:\n\t\tvar damage_for_creep: float = Utils.get_aoe_damage(aoe_center, creep, radius, damage, sides_ratio)\n\t\tdo_attack_damage(creep, damage_for_creep, crit_ratio)\n\n\n# NOTE: unit.doSpellDamageAoEUnit() in JASS\nfunc do_spell_damage_aoe_unit(target: Unit, radius: float, damage: float, crit_ratio: float, sides_ratio: float):\n\tdo_spell_damage_aoe(Vector2(target.get_x(), target.get_y()), radius, damage, crit_ratio, sides_ratio)\n\n\n# NOTE: unit.doSpellDamageAoE() in JASS\nfunc do_spell_damage_aoe(aoe_center: Vector2, radius: float, damage: float, crit_ratio: float, sides_ratio: float):\n\tvar creep_list: Array = Utils.get_units_in_range(self, TargetType.new(TargetType.CREEPS), aoe_center, radius)\n\n\tfor creep in creep_list:\n\t\tvar damage_for_creep: float = Utils.get_aoe_damage(aoe_center, creep, radius, damage, sides_ratio)\n\t\tdo_spell_damage(creep, damage_for_creep, crit_ratio)\n\n\n# Deals aoe damage from the position of the unit\n# NOTE: unit.doSpellDamagePBAoE() in JASS\nfunc do_spell_damage_pb_aoe(radius: float, damage: float, crit_ratio: float, sides_ratio: float):\n\tdo_spell_damage_aoe(Vector2(get_x(), get_y()), radius, damage, crit_ratio, sides_ratio)\n\n\n# NOTE: unit.killInstantly() in JASS\nfunc kill_instantly(target: Unit):\n\tCombatLog.log_ability(self, target, \"Instant Kill\")\n\ttarget._killed_by_unit(self)\n\n\n# NOTE: unit.modifyProperty() in JASS\nfunc modify_property(mod_type: ModificationType.enm, value: float):\n\t_modify_property_internal(mod_type, value, 1)\n\n\n# Adds modifier directly to unit. Modifier will\n# automatically scale with this unit's level.\nfunc add_modifier(modifier: Modifier):\n\t_apply_modifier(modifier, _level, 1)\n\t_direct_modifier_list.append(modifier)\n\n\nfunc remove_modifier(modifier: Modifier):\n\tif _direct_modifier_list.has(modifier):\n\t\t_apply_modifier(modifier, _level, -1)\n\t\t_direct_modifier_list.erase(modifier)\n\n\nfunc change_modifier_level(modifier: Modifier, old_level: int, new_level: int):\n\t_apply_modifier(modifier, old_level, -1)\n\t_apply_modifier(modifier, new_level, 1)\n\n\nfunc add_silence():\n\t_silence_count += 1\n\n\nfunc remove_silence():\n\t_silence_count -= 1\n\n\nfunc add_stun():\n\tvar stun_started: bool = _stun_count == 0\n\n\t_stun_count += 1\n\n\tif stun_started:\n\t\t_stun_effect_id = Effect.create_simple_at_unit_attached(\"res://src/effects/stun_visual.tscn\", self, Unit.BodyPart.OVERHEAD)\n\t\tEffect.set_auto_destroy_enabled(_stun_effect_id, false)\n\n\nfunc remove_stun():\n\t_stun_count -= 1\n\n\tvar stun_ended: bool = _stun_count == 0\n\t\n\tif stun_ended:\n\t\tEffect.destroy_effect(_stun_effect_id)\n\t\t_stun_effect_id = -1\n\n\nfunc add_ethereal():\n\t_ethereal_count += 1\n\n\nfunc remove_ethereal():\n\t_ethereal_count -= 1\n\n\n# Returns the amount of mana that was actually subtracted.\n# NOTE: unit.subtractMana() in JASS\nfunc subtract_mana(amount: float, subtract_if_not_enough: bool) -> float:\n\tvar enough_mana: bool = _mana >= amount \n\n\tif enough_mana:\n\t\tvar new_mana: float = clampf(_mana - amount, 0.0, _mana)\n\t\tset_mana(new_mana)\n\n\t\treturn amount\n\telse:\n\t\tif subtract_if_not_enough:\n\t\t\tset_mana(0)\n\t\telse:\n\t\t\treturn 0\n\t\n\treturn 0\n\n\nfunc get_selection_outline() -> Node2D:\n\treturn _unit_selection_outline\n\n\n#########################\n###      Private      ###\n#########################\n\nfunc _setup_selection_signals(selection_area: Area2D):\n\tselection_area.mouse_entered.connect(_on_selection_area_mouse_entered)\n\tselection_area.mouse_exited.connect(_on_selection_area_mouse_exited)\n\n\nfunc _on_selection_area_mouse_entered():\n\tEventBus.mouse_entered_unit.emit(self)\n\n\nfunc _on_selection_area_mouse_exited():\n\tEventBus.mouse_exited_unit.emit(self)\n\n\nfunc _modify_property_internal(mod_type: ModificationType.enm, value: float, direction: int):\n\tvar health_ratio: float = get_health_ratio()\n\tvar mana_ratio: float = get_mana_ratio()\n\n\tvar current_value: float = _mod_value_map[mod_type]\n\tvar new_value: float = current_value + direction * value\n\t_mod_value_map[mod_type] = new_value\n\n#\tNOTE: restore original health and mana ratios. For\n#\texample, if original mana was 50/100 and mana was\n#\tincreased by 50, then final values will be 75/150 to\n#\tpreserve the 50% ratio.\n\tvar new_health_max: float = get_overall_health()\n\t_health = health_ratio * new_health_max\n\tvar new_mana_max: float = get_overall_mana()\n\t_mana = mana_ratio * new_mana_max\n\n\n# Changes experience of unit. Change can be positive or\n# negative. Level will also be changed accordingly. Note\n# that level downs are possible.\nfunc _change_experience(amount: float) -> float:\n#\tNOTE: store experience as centiunits (multiply by 100) to\n#\tpreserve fractional values while using integer arithmetic\n#\tfor multiplayer determinism.\n\tvar old_exp_centi: int = _experience_centi\n\tvar amount_centi: int = roundi(amount * 100.0)\n\tvar new_exp_centi: int = maxi(0, _experience_centi + amount_centi)\n\tvar actual_change_centi: int = new_exp_centi - old_exp_centi\n\tvar actual_change: float = actual_change_centi / 100.0\n\n\tif actual_change_centi == 0:\n\t\treturn actual_change\n\n\tvar old_level: int = _level\n\tvar new_exp_float: float = new_exp_centi / 100.0\n\tvar new_level: int = Experience.get_level_at_exp(new_exp_float, get_player())\n\n\t_experience_centi = new_exp_centi\n\n\tvar level_has_changed: bool = new_level != old_level\n\tvar level_increased: bool = new_level > old_level\n\t\n\tif level_has_changed:\n\t\tset_level(new_level)\n\t\t\n#\t\tNOTE: it is important to emit level_changed() signal\n#\t\tmultiple times if level has changed by more than 1.\n#\t\tSome tower logic depend on this behavior.\n\t\tvar level_change_amount: int = absi(new_level - old_level)\n\t\tfor i in range(0, level_change_amount):\n\t\t\tlevel_changed.emit(level_increased)\n\t\t\n\t\tEventBus.unit_leveled_up.emit()\n\n\tvar sign_string: String\n\tif actual_change >= 0:\n\t\tsign_string = \"+\"\n\telse:\n\t\tsign_string = \"-\"\n\tvar number_string: String = String.num(abs(actual_change), 1)\n\tvar exp_text: String = \"%s%s exp\" % [sign_string, number_string]\n\tvar text_color: Color\n\tif actual_change >= 0:\n\t\ttext_color = Color.LIME_GREEN\n\telse:\n\t\ttext_color = Color.RED\n\n\tget_player().display_floating_text(exp_text, self, text_color)\n\n\tif level_increased:\n\t\tvar effect_id: int = Effect.create_simple_at_unit(\"res://src/effects/level_up.tscn\", self)\n\t\tvar effect_scale: float = max(_sprite_dimensions.x, _sprite_dimensions.y) / Constants.LEVEL_UP_EFFECT_SIZE\n\t\tEffect.set_scale(effect_id, effect_scale)\n\t\tvar stomp_effect: int = Effect.create_simple_at_unit(\"res://src/effects/warstomp_caster.tscn\", self, Unit.BodyPart.ORIGIN)\n\t\tEffect.set_z_index(stomp_effect, Effect.Z_INDEX_BELOW_TOWERS)\n\t\tEffect.set_color(stomp_effect, Color.BROWN)\n\n\t\tvar level_up_text: String = \"Level %d\" % _level\n\t\tget_player().display_floating_text(level_up_text, self, Color.GOLD)\n\n\t\tSFX.sfx_at_unit(SfxPaths.LEVEL_UP, self)\n\n\tCombatLog.log_experience(self, actual_change)\n\n\treturn actual_change\n\n\nfunc _add_floating_text_for_damage(damage: float, crit_count: int, damage_source: DamageSource, is_main_target: bool, target: Unit):\n\tvar damage_color: Color\n\tvar damage_text: String = str(floori(damage))\n\n#\tNOTE: do not show crits for 0 damage, because it shows\n#\tup as \"0!\" and looks weird. Do show \"0\" for spell damage\n#\tbecause it indicates helpful info about certain\n#\tabilities.\n\tif crit_count > 0 && roundi(damage) == 0:\n\t\treturn\n\t\n\tmatch damage_source:\n\t\tDamageSource.Attack: \n\t\t\tdamage_color = Color.RED\n\t\tDamageSource.Spell:\n\t\t\tdamage_color = Color.SKY_BLUE\n\t\n\tvar is_critical: bool = crit_count > 0\n\n\tfor i in range(0, crit_count):\n\t\tdamage_text += \"!\"\n\n\tvar text_origin_unit: Unit\n\tif is_critical && damage_source == DamageSource.Attack:\n\t\ttext_origin_unit = self\n\telse:\n\t\ttext_origin_unit = target\n\n#\tNOTE: confusing logic for this boolean but this is how\n#\tit worked in original youtd\n\tvar show_all_damage_numbers: bool = Settings.get_bool_setting(Settings.SHOW_ALL_DAMAGE_NUMBERS)\n\tvar floating_text_should_be_shown: bool = show_all_damage_numbers || (damage_source == DamageSource.Attack && is_critical && is_main_target) || (damage_source == DamageSource.Spell && is_critical)\n\tif !floating_text_should_be_shown:\n\t\treturn\n\t\n\tget_player().display_floating_text_x_2(damage_text, text_origin_unit, damage_color, 0, 0, 1.0, 0, 50)\n\n\n# Example:\n# If crits deal 125% of normal damage and crit ratio is 1.50\n# Then crit count = (1.50 - 1.0) / (1.25 - 1.0) = 0.50 / 0.25 = 2\nfunc _derive_crit_count_from_crit_ratio(crit_ratio: float, damage_source: DamageSource) -> int:\n\tvar crit_damage_mod: float\n\tmatch damage_source:\n\t\tDamageSource.Attack:\n\t\t\tcrit_damage_mod\t= get_prop_atk_crit_damage()\n\t\tDamageSource.Spell:\n\t\t\tcrit_damage_mod\t= get_spell_crit_damage()\n\n\tvar crit_count: int = roundi(Utils.divide_safe((crit_ratio - 1.0), (crit_damage_mod - 1.0)))\n\n\treturn crit_count\n\n\n# Generates a random crit count for attack damage\nfunc _generate_crit_count(bonus_multicrit: float, bonus_chance: float) -> int:\n\tvar multicrit_count_max: int = get_prop_multicrit_count() + int(bonus_multicrit)\n\tvar current_crit_chance: float = get_prop_atk_crit_chance() + bonus_chance\n\n\tvar crit_count: int = 0\n\t\n\tfor _i in range(multicrit_count_max):\n\t\tvar capped_crit_chance: float = min(current_crit_chance, Constants.ATK_CRIT_CHANCE_CAP)\n\t\tvar is_critical: bool = Utils.rand_chance(Globals.synced_rng, capped_crit_chance)\n\n\t\tif is_critical:\n\t\t\tcrit_count += 1\n\n#\t\t\tDecrease chance of each subsequent multicrit to\n#\t\t\timplement diminishing returns.\n\t\t\tcurrent_crit_chance *= Constants.ATK_MULTICRIT_DIMISHING\n\t\telse:\n\t\t\tbreak\n\n\treturn crit_count\n\n\n# Same as calc_attack_multicrit(), but accepts an already\n# calculated crit count. Used by Tower.\nfunc _calc_attack_multicrit_from_crit_count(crit_count: int, bonus_damage: float) -> float:\n\tvar crit_damage: float = get_prop_atk_crit_damage() + bonus_damage\n\n# \tNOTE: subtract 1.0 from crit_damage, so we do\n#\t1.0 + 0.5 + 0.5 + 0.5...\n# \tnot\n#\t1.0 + 1.5 + 1.5 + 1.5...\n\tvar total_crit_damage: float = 1.0 + (crit_damage - 1.0) * crit_count\n\n\ttotal_crit_damage = max(0.0, total_crit_damage)\n\n\treturn total_crit_damage\n\n\nfunc _do_damage(target: Unit, damage_base: float, crit_ratio: float, damage_source: DamageSource, is_main_target: bool, emit_damage_event: bool = false, attack_type: AttackType.enm = get_attack_type(), crit_count: int = -1) -> bool:\n\tif !target is Creep:\n\t\tpush_error(\"Attempted to deal damage to a unit which is not a creep: %s. Can deal damage only to creeps.\" % target)\n\n\t\treturn false\n\n#\tNOTE: if crit_count is -1, then _do_damage() was called\n#\tfrom f-n like do_attack_damage(), where we only have\n#\taccess to crit_ratio. In that case derive crit count\n#\tfrom crit ratio. The only case where we have access to\n#\tcrit_ratio is for regular tower attacks.\n\tif crit_count == -1:\n\t\tcrit_count = _derive_crit_count_from_crit_ratio(crit_ratio, damage_source)\n\n\tvar target_size: CreepSize.enm = target.get_size()\n\tvar size_mod: float = get_damage_to_size(target_size)\n\tvar creep_category: CreepCategory.enm = target.get_category()\n\tvar category_mod: float = get_damage_to_category(creep_category)\n\tvar armor_type: ArmorType.enm = target.get_armor_type()\n\tvar armor_type_mod: float = AttackType.get_damage_against(attack_type, armor_type)\n\tvar spell_damage_multiplier: float = ArmorType.get_spell_damage_taken(armor_type)\n\n\tvar damage: float = damage_base * size_mod * category_mod\n\t\n\tif self is Tower:\n\t\tvar tower: Tower = self as Tower\n\t\tvar element: Element.enm = tower.get_element()\n\t\tvar element_mod: float = target.get_damage_from_element(element)\n\t\tdamage *= element_mod\n\n\tmatch damage_source:\n\t\tDamageSource.Attack: damage *= armor_type_mod\n\t\tDamageSource.Spell: damage *= spell_damage_multiplier\n\n# \tImmune creeps take 0 damage from spells\n\tif damage_source == DamageSource.Spell && target.is_immune():\n\t\tdamage = 0\n\n\tvar damage_before_damage_event: float = damage\n\n#\tNOTE: emit_damage_event arg is true only for tower\n#\tattacks, false for all other calls to this function\n\tif emit_damage_event:\n\t\tvar damage_event: Event = Event.new(target)\n\t\tdamage_event.damage = damage\n\t\tdamage_event._is_main_target = is_main_target\n\t\tdamage_event._number_of_crits = crit_count\n\t\tdealt_damage.emit(damage_event)\n# \t\tNOTE: update damage value because it could've been\n# \t\taltered by DAMAGE callbacks\n\t\tdamage = damage_event.damage\n\n#\tNOTE: crit damage bonus must be applied after \"damage\"\n#\tevent. This is according to this comment in the original\n#\tscript for Burrow tower.\n#\tComment: \"The engine calculates critical strike extra\n#\tdamage ***AFTER*** the onDamage event, so there is no\n#\tneed to care about it in this trigger.\"\n\tdamage *= crit_ratio\n\t\n\tvar total_damage_multiplier: float = get_total_damage_multiplier()\n\tdamage *= total_damage_multiplier\n\n\tvar damage_before_damaged_event: float = damage\n\n\tvar attacker: Unit = self\n\n\tif attacker is Tower:\n\t\tvar damaged_event: Event = Event.new(attacker)\n\t\tdamaged_event.damage = damage\n\t\tdamaged_event._is_main_target = is_main_target\n\t\tdamaged_event._is_spell_damage = damage_source == DamageSource.Spell\n\t\tdamaged_event._number_of_crits = crit_count\n\t\ttarget.damaged.emit(damaged_event)\n\n# \t\tNOTE: update damage value because it could've been\n# \t\taltered by event handlers of target's \"damaged\" event\n\t\tdamage = damaged_event.damage\n\n\tvar damage_is_in_bounds: bool = Constants.DAMAGE_MIN <= damage && damage <= Constants.DAMAGE_MAX\n\n\tif !damage_is_in_bounds:\n\t\tpush_error(\"Damage out of bounds. Damage base = %f, damage before DAMAGE event = %f, damage before DAMAGED event = %f, damage final = %f\" % [damage_base, damage_before_damage_event, damage_before_damaged_event, damage])\n\n\t\tif attacker is Tower:\n\t\t\tpush_error(\"Tower id = %d\" % attacker.get_id())\n\n\t\tdamage = clampf(damage, Constants.DAMAGE_MIN, Constants.DAMAGE_MAX)\n\t\n\t_damage_dealt_total += damage\n\t\n\tvar wave_level: int = target.get_spawn_level()\n\t\n\t# initialize all maps at once on first damage instance to wave_level\n\tif !_damage_dealt_to_wave_map.has(wave_level):\n\t\t_damage_dealt_to_wave_map[wave_level] = 0\n\t\t_spell_damage_dealt_to_wave_map[wave_level] = 0\n\t\t_attack_damage_dealt_to_wave_map[wave_level] = 0\n\t\t\n\t\t\n\t_damage_dealt_to_wave_map[wave_level] += damage\n\t\n\tif damage_source == DamageSource.Spell:\n\t\t# re-init as safety fallback\n\t\tif !_spell_damage_dealt_to_wave_map.has(wave_level):\n\t\t\t_spell_damage_dealt_to_wave_map[wave_level] = 0\n\t\t\n\t\t_spell_damage_dealt += damage\n\t\t_spell_damage_dealt_to_wave_map[wave_level] += damage\n\t\t\n\tif damage_source == DamageSource.Attack:\n\t\t# re-init as safety fallback\n\t\tif !_attack_damage_dealt_to_wave_map.has(wave_level):\n\t\t\t_attack_damage_dealt_to_wave_map[wave_level] = 0\n\t\t\t\n\t\t_attack_damage_dealt += damage\n\t\t_attack_damage_dealt_to_wave_map[wave_level] += damage\n\n\tif damage > _best_hit:\n\t\t_best_hit = damage\n\n\tvar health_before_damage: float = target.get_health()\n\ttarget.set_health(health_before_damage - damage)\n\n\tCombatLog.log_damage(self, target, damage_source, damage, crit_count)\n\n#\tNOTE: round damage to avoid floating point precision\n#\tdesyncs in multiplayer\n\tvar rounded_damage: float = floor(damage)\n\tget_player().add_to_total_damage(rounded_damage)\n\n\t_add_floating_text_for_damage(damage, crit_count, damage_source, is_main_target, target)\n\n\tvar health_after_damage: float = target.get_health()\n\tvar damage_killed_unit: bool = health_before_damage > 0 && health_after_damage <= 0\n\n\tif damage_killed_unit:\n\t\ttarget._killed_by_unit(self)\n\n\treturn damage_killed_unit\n\n\n# Called when unit killed by caster unit\nfunc _killed_by_unit(caster: Unit):\n\tvar death_event: Event = Event.new(caster)\n\tdeath.emit(death_event)\n\n\tif caster != null:\n\t\tcaster._accept_kill(self)\n\n\tvar caster_item_chance: float = caster.get_item_drop_ratio()\n\tvar target_item_chance: float = get_item_drop_ratio_on_death()\n\tvar item_chance: float = Constants.BASE_ITEM_DROP_CHANCE * caster_item_chance * target_item_chance\n\n\tvar creep: Creep = self as Creep\n\n\tif creep != null:\n\t\tvar creep_size: CreepSize.enm = creep.get_size_including_challenge_sizes()\n\t\tvar item_drop_roll_count: int = CreepSize.get_item_drop_roll_count(creep_size)\n\t\t\n\t\tif Config.always_drop_items():\n\t\t\titem_drop_roll_count = 1\n\t\t\titem_chance = 1.0\n\t\t\n\t\tfor i in range(0, item_drop_roll_count):\n\t\t\tvar item_dropped: bool = Utils.rand_chance(Globals.synced_rng, item_chance)\n\n\t\t\tif item_dropped:\n\t\t\t\tcreep.drop_item(caster, true)\n\n\tremove_from_game()\n\n\n# Called when unit kills target unit\nfunc _accept_kill(target: Unit):\n\tCombatLog.log_kill(self, target)\n\t\n\tvar experience_gained: float = _get_experience_for_target(target)\n\t_change_experience(experience_gained)\n\n\tvar target_owner: Player = target.get_player()\n\n\tvar bounty_gained: int = _get_bounty_for_target(target)\n\tif bounty_gained > 0:\n\t\ttarget_owner.give_gold(bounty_gained, target, false, true)\n\n\t_kill_count += 1\n\n\tvar kill_event: Event = Event.new(target)\n\tkill.emit(kill_event)\n\n\n# This is for internal use in buff.gd only. For external\n# use, call BuffType.apply().\nfunc _add_buff_internal(buff: Buff):\n\tvar buff_type_name: String = buff.get_buff_type_name()\n\t_buff_map[buff_type_name] = buff\n\n\t_buff_list.append(buff)\n\tvar buff_modifier: Modifier = buff.get_modifier()\n\t_apply_modifier(buff_modifier, buff.get_level(), 1)\n\t\n\tbuff_list_changed.emit()\n\n\nfunc _apply_modifier(modifier: Modifier, level: int, modify_direction: int):\n\tvar modification_list: Array = modifier.get_modification_list()\n\n\tfor modification in modification_list:\n\t\tvar value: float = modification.value_base + modification.level_add * level\n\n\t\t_modify_property_internal(modification.type, value, modify_direction)\n\n\nfunc _remove_buff_internal(buff: Buff):\n\tvar buff_modifier: Modifier = buff.get_modifier()\n\t_apply_modifier(buff_modifier, buff.get_level(), -1)\n\n\tvar buff_type_name: String = buff.get_buff_type_name()\n\t_buff_map.erase(buff_type_name)\n\n\t_buff_list.erase(buff)\n\tbuff_list_changed.emit()\n\n\n# Set node which will be used to determine the visual\n# position of the unit.\nfunc _set_visual_node(visual_node: Node2D):\n\t_visual_node = visual_node\n\t_visual_node.position.y = -_position_wc3.z\n\n\n# Save the sprite node. Also create a duplicate outline\n# sprite base on the original sprite.\n# NOTE: sprite is Sprite2D in case of tower and\n# AnimatedSprite2D in case of Creeps. The operations we do\n# here are valid for both types.\n# NOTE: sprite parent node is used to chance scale and color of the sprite without affecting default values.\nfunc _setup_unit_sprite(sprite_node: Node2D, sprite_parent_node: Node2D, outline_thickness: float):\n#\tNOTE: delete existing sprite node and selection outline\n\tif _unit_sprite_parent != null:\n\t\t_unit_sprite_parent.queue_free()\n\tif _unit_selection_outline_parent != null:\n\t\t_unit_selection_outline_parent.queue_free()\n\t\n\t_unit_sprite = sprite_node\n\t_unit_sprite_parent = sprite_parent_node\n\n#\tNOTE: create a duplicate sprite to use it as selection\n#\toutline. Outline is implemented by using a shader which\n#\tdraws an outline around the sprite and erases the\n#\toriginal sprite.\n# \tNOTE: also duplicate the shader so that shader\n# \tparameters are individual to scenes.\n\tvar sprite_for_outline = sprite_node.duplicate()\n\tvar selection_shader: ShaderMaterial = Preloads.outline_shader.duplicate()\n\tsprite_for_outline.set_material(selection_shader)\n\tsprite_for_outline.get_material().set_shader_parameter(\"line_thickness\", outline_thickness)\n\n#\tNOTE: set z_index of outline so that it's drawn above\n#\tall other units\n\tsprite_for_outline.z_index = 1\n\n#\tNOTE: need to keep sprite and outline under separate\n#\tparents because outline should not be affected by\n#\tchanges to sprite color, which is done via sprite parent\n\t_unit_selection_outline_parent = Node2D.new()\n\t_unit_sprite_parent.add_sibling(_unit_selection_outline_parent)\n\n\t_unit_selection_outline_parent.add_child(sprite_for_outline)\n\t_unit_selection_outline = sprite_for_outline\n\n#\tNOTE: initially hide the outline, it will get shown when\n#\tunit is hovered or selected.\n\t_unit_selection_outline.hide()\n\n\n# Call this in subclass to set dimensions of unit. Use\n# Utils.get_sprite_dimensions() or\n# Utils.get_animated_sprite_dimensions() to get the\n# dimensions of the sprite in subclass. This will be used to\n# calculate positions of different body parts of the unit.\nfunc _set_unit_dimensions(sprite_dimensions: Vector2):\n\t_sprite_dimensions = sprite_dimensions\n\n\n# Sets size(radius) of selection circle.\n# Should be called in subclasses.\nfunc _set_selection_size(selection_size: float):\n\t_selection_indicator.visual_size = selection_size\n\n\nfunc _get_bounty_for_target(target: Unit) -> int:\n\tif !target is Creep:\n\t\treturn 0\n\n\tvar tower: Unit = self\n\tvar creep: Creep = target as Creep\n\tvar bounty_base: float = creep.get_base_bounty_value()\n\tvar granted_mod: float = creep.get_prop_bounty_granted()\n\tvar received_mod: float = tower.get_prop_bounty_received()\n\tvar bounty: int = floori(bounty_base * granted_mod * received_mod)\n\n\treturn bounty\n\n\nfunc _get_experience_for_target(target: Unit) -> float:\n\tif !target is Creep:\n\t\treturn 0\n\n\tvar tower: Unit = self\n\tvar creep: Creep = target as Creep\n\tvar creep_size: CreepSize.enm = creep.get_size_including_challenge_sizes()\n\tvar experience_base: float = CreepSize.get_experience(creep_size)\n\tvar granted_mod: float = creep.get_prop_exp_granted()\n\tvar received_mod: float = tower.get_prop_exp_received()\n\tvar experience: float = experience_base * granted_mod * received_mod\n\n\treturn experience\n\n\n# Returns a prop value after applying diminishing returns to\n# it. Diminishing returns reduce effectiveness of mods as\n# the prop value gets further away from [0.6, 1.7] range.\nfunc _get_prop_with_diminishing_returns(type: ModificationType.enm) -> float:\n\tvar value: float = max(0, _mod_value_map[type])\n\n\tif value > 1.7:\n\t\treturn 1.7 + (value - 1.7) / pow(1.0 + value - 1.7, 0.66)\n\telif value < 0.6:\n\t\treturn 0.6 / pow(1.0 + 0.6 - value, 1.6)\n\telse:\n\t\treturn value\n\n\n#########################\n###     Callbacks     ###\n#########################\n\nfunc _on_regen_timer_timeout():\n\tvar mana_regen: float = get_overall_mana_regen()\n\tset_mana(_mana + mana_regen)\n\n\tvar health_regen: float = get_overall_health_regen()\n\tset_health(_health + health_regen)\n\n\n#########################\n### Setters / Getters ###\n#########################\n\nfunc get_target_bitmask() -> int:\n\treturn _target_bitmask\n\n\n# Returns name used in the combat log\nfunc get_log_name():\n\tvar instance_id: int = get_instance_id()\n\tvar log_name: String = \"Unit-%d\" % instance_id\n\n\treturn log_name\n\n\nfunc get_aura_list() -> Array[Aura]:\n\treturn _aura_list\n\n\nfunc get_autocast_list() -> Array[Autocast]:\n\treturn _autocast_list\n\n\n# NOTE: for now just returning the one single player\n# instance since multiplayer isn't implemented. Also, the\n# name isn't \"get_player()\" because that is already a\n# function of Node class.\n# \n# NOTE: unit.getOwner() in JASS\n# Node.get_owner() is a built-in godot f-n\nfunc get_player() -> Player:\n\treturn _player\n\n\nfunc belongs_to_local_player() -> bool:\n\tvar result: bool = _player == PlayerManager.get_local_player()\n\t\n\treturn result\n\n\n# NOTE: this is a stub, used in original tower scripts but\n# not needed in godot engine.\n# NOTE: unit.setAnimationByIndex() in JASS\nfunc set_animation_by_index(_unit: Unit, _index: int):\n\tpass\n\n\n# Sets sprite's base color. Sprite will have this color\n# forever and it will be mixed with the color passed to\n# set_sprite_color(). This is intended to be called once\n# when creeps are created to apply color based on wave\n# specials.\nfunc set_sprite_base_color(color: Color):\n\t_unit_sprite.modulate = color\n\n\n# Changes color of sprite. Note that this color will be\n# mixed with base color - it does not overwrite it. Pass\n# Color.WHITE to reset to base color.\n# NOTE: not modifying color of selection outline here because outline should not be affected by sprite color\n# NOTE: SetUnitVertexColor() in JASS\nfunc set_sprite_color(value: Color):\n\t_unit_sprite_parent.modulate = value\n\n\n# NOTE: overriden in Tower to return non-null value\nfunc get_current_target() -> Unit:\n\treturn null\n\n\n# NOTE: unit.isImmune() in JASS\nfunc is_immune() -> bool:\n\treturn _immune\n\n\nfunc set_immune(immune: bool):\n\t_immune = immune\n\n\nfunc set_level(new_level: int):\n\tvar old_level: int = _level\n\t_level = new_level\n\n#\tNOTE: apply level change to modifiers\n\tfor modifier in _direct_modifier_list:\n\t\tchange_modifier_level(modifier, old_level, new_level)\n\n\n# NOTE: Node2D.position and Node2D.get_position() return\n# position of node on the canvas, which is not the same as\n# the 3d position! Use get_position_canvas() instead of\n# get_position() to make the difference explicity.\nfunc get_position_canvas() -> Vector2:\n\treturn position\n\n\nfunc get_visual_position() -> Vector2:\n\treturn _visual_node.global_position\n\n\nfunc get_position_wc3_2d() -> Vector2:\n\tvar position_2d: Vector2 = Vector2(_position_wc3.x, _position_wc3.y)\n\n\treturn position_2d\n\n\nfunc get_position_wc3() -> Vector3:\n\treturn _position_wc3\n\n\nfunc set_position_wc3(value: Vector3):\n\t_position_wc3 = value\n\n\tposition.x = Utils.to_pixels(_position_wc3.x)\n\tposition.y = Utils.to_pixels(_position_wc3.y / 2)\n\n#\tNOTE: it would be more correct to convert z to pixels\n#\tand then multiply by some constant based on isometric\n#\tperspective. By luck, it works by using z without\n#\tconversion.\n\tif _visual_node != null:\n\t\t_visual_node.position.y = -_position_wc3.z\n\n\nfunc set_position_wc3_2d(value: Vector2):\n\tset_position_wc3(Vector3(value.x, value.y, get_z()))\n\n\nfunc set_z(z: float):\n\tvar new_position_wc3: Vector3 = Vector3(_position_wc3.x, _position_wc3.y, z)\n\tset_position_wc3(new_position_wc3)\n\n\n# Returns approximate position of the body part of unit on\n# the canvas coordinate space (not 3d wc3).\n# NOTE: body parts were used in original API based on\n# coordinates of body parts of 3D models. Approximate this\n# feature for 2d tiles by defining body part positions as:\n# ORIGIN = bottom of sprite\n# CHEST = middle of sprite\n# HEAD = top of sprite\n# Note that \"sprite\" here means the occupied part of the\n# texture. Some sprites occupy only a small portion of the\n# total texture so using texture center/dimensions would\n# cause incorrect results.\nfunc get_body_part_position(body_part: Unit.BodyPart) -> Vector3:\n\tvar origin_pos: Vector3 = get_position_wc3()\n\t\n\tif _visual_node == null:\n\t\tprint_debug(\"No visual node defined\")\n\n\t\treturn origin_pos\n\n\tvar body_part_offset_canvas: Vector2 = get_body_part_offset(body_part)\n\tvar body_part_offset_z: float = -body_part_offset_canvas.y\n\tvar body_part_position: Vector3 = origin_pos + Vector3(0, 0, body_part_offset_z)\n\n\treturn body_part_position\n\n\n# NOTE: returns position in canvas coords\nfunc get_body_part_offset(body_part: Unit.BodyPart) -> Vector2:\n\tvar sprite_height: float = float(_sprite_dimensions.y)\n\n\tmatch body_part:\n\t\tBodyPart.OVERHEAD: return Vector2(0, -sprite_height * 1.0)\n\t\tBodyPart.HEAD: return Vector2(0, -sprite_height * 0.75)\n\t\tBodyPart.CHEST: return Vector2(0, -sprite_height * 0.5)\n\t\tBodyPart.ORIGIN: return Vector2.ZERO\n\t\n\treturn Vector2.ZERO\n\n\n# NOTE: unit.getX() in JASS\nfunc get_x() -> float:\n\treturn _position_wc3.x\n\n\n# NOTE: unit.getY() in JASS\nfunc get_y() -> float:\n\treturn _position_wc3.y\n\n\n# NOTE: unit.getZ() in JASS\nfunc get_z() -> float:\n\treturn _position_wc3.z\n\n\nfunc get_visual_node() -> Node2D:\n\treturn _visual_node\n\n\n# NOTE: \"getProp_BuffDuration()\" in JASS\nfunc get_prop_buff_duration() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_BUFF_DURATION)\n\n# NOTE: \"getProp_DebuffDuration()\" in JASS\nfunc get_prop_debuff_duration() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_DEBUFF_DURATION)\n\n# NOTE: \"getProp_AtkCritChance()\" in JASS\nfunc get_prop_atk_crit_chance() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_ATK_CRIT_CHANCE])\n\n# NOTE: \"getProp_AtkCritDamage()\" in JASS\nfunc get_prop_atk_crit_damage() -> float:\n\treturn max(1.0, _mod_value_map[ModificationType.enm.MOD_ATK_CRIT_DAMAGE])\n\n# NOTE: \"getProp_BountyReceived()\" in JASS\nfunc get_prop_bounty_received() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_BOUNTY_RECEIVED)\n\n# NOTE: \"getProp_BountyGranted()\" in JASS\nfunc get_prop_bounty_granted() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_BOUNTY_GRANTED])\n\n# NOTE: \"getProp_ExpReceived()\" in JASS\nfunc get_prop_exp_received() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_EXP_RECEIVED)\n\n# NOTE: \"getProp_ExpGranted()\" in JASS\nfunc get_prop_exp_granted() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_EXP_GRANTED])\n\nfunc get_damage_to_air() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_AIR])\n\nfunc get_damage_to_boss() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_BOSS])\n\nfunc get_damage_to_mass() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_MASS])\n\nfunc get_damage_to_normal() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_NORMAL])\n\nfunc get_damage_to_champion() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_CHAMPION])\n\nfunc get_damage_to_undead() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_UNDEAD])\n\nfunc get_damage_to_humanoid() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_HUMANOID])\n\nfunc get_damage_to_challenge() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_CHALLENGE])\n\nfunc get_damage_to_nature() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_NATURE])\n\nfunc get_damage_to_magic() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_MAGIC])\n\nfunc get_damage_to_orc() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TO_ORC])\n\nfunc get_item_drop_ratio() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_ITEM_CHANCE_ON_KILL)\n\nfunc get_item_quality_ratio() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_ITEM_QUALITY_ON_KILL)\n\nfunc get_item_drop_ratio_on_death() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_ITEM_CHANCE_ON_DEATH])\n\nfunc get_item_quality_ratio_on_death() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_ITEM_QUALITY_ON_DEATH])\n\n# NOTE: \"getProp_TriggerChances()\" in JASS\nfunc get_prop_trigger_chances() -> float:\n\treturn _get_prop_with_diminishing_returns(ModificationType.enm.MOD_TRIGGER_CHANCES)\n\nfunc get_prop_multicrit_count() -> int:\n\treturn int(max(0, _mod_value_map[ModificationType.enm.MOD_MULTICRIT_COUNT]))\n\n# NOTE: \"getProp_SpellDmgDealt()\" in JASS\nfunc get_prop_spell_damage_dealt() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_SPELL_DAMAGE_DEALT])\n\n# NOTE: \"getProp_SpellDmgReceived()\" in JASS\nfunc get_prop_spell_damage_received() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_SPELL_DAMAGE_RECEIVED])\n\n# NOTE: \"getProp_SpellCritChance()\" in JASS\nfunc get_spell_crit_chance() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_SPELL_CRIT_CHANCE])\n\n# NOTE: \"getProp_SpellCritDamage()\" in JASS\nfunc get_spell_crit_damage() -> float:\n\treturn max(1.0, _mod_value_map[ModificationType.enm.MOD_SPELL_CRIT_DAMAGE])\n\n\n# NOTE: [ORIGINAL_GAME_DEVIATION] in original game,\n# attack speed mod is not clamped when displayed, only when\n# used. So if attack speed is -50% it would show as \"-50%\"\n# in tower details but would actually by clamped to the min\n# value (20%).\n# \n# Changed it so that both displayed and actually used values\n# are clamped.\n# \n# NOTE: in original youtd, this f-n returns a value which\n# starts from 0%. In youtd2, this f-n returns a value which\n# starts from 100%. Keep this in mind when\n# translating/comparing original JASS tower scripts.\n# \n# NOTE: \"getProp_Attackspeed()\" in JASS\nfunc get_attack_speed_modifier() -> float:\n\tvar attack_speed_mod: float = _mod_value_map[ModificationType.enm.MOD_ATTACKSPEED]\n\tattack_speed_mod = clampf(attack_speed_mod, Constants.MOD_ATTACKSPEED_MIN, Constants.MOD_ATTACKSPEED_MAX)\n\n\treturn attack_speed_mod\n\n\nfunc get_level() -> int:\n\treturn _level\n\nfunc is_silenced() -> bool:\n\treturn _silence_count > 0\n\nfunc is_stunned() -> bool:\n\treturn _stun_count > 0\n\n# Returns the total amount of time that this unit was\n# stunned for during it's lifetime.\nfunc get_total_stun_duration() -> float:\n\treturn _total_stun_duration\n\n# NOTE: unit.isBanished() in JASS\nfunc is_ethereal() -> bool:\n\treturn _ethereal_count > 0\n\n# NOTE: overriden in Tower and Creep subclasses\nfunc is_in_combat() -> bool:\n\treturn false\n\n# NOTE: unit.getBuffOfType() in JASS\nfunc get_buff_of_type(buff_type: BuffType) -> Buff:\n\tvar buff_type_name: String = buff_type.get_unique_name()\n\tvar buff: Buff = _buff_map.get(buff_type_name, null)\n\n\treturn buff\n\n\n# NOTE: this f-n is not implemented, see comment for\n# BuffType.set_stacking_group() for reason.\n# \n# NOTE: unit.getBuffOfGroup() in JASS\n# func get_buff_of_group(stacking_group: String) -> Buff:\n#\treturn null\n\n\n# NOTE: analog of SetUnitState(unit, UNIT_STATE_MANA) in JASS\nfunc set_mana(new_mana: float):\n\tvar overall_mana: float = get_overall_mana()\n\t_mana = clampf(new_mana, 0.0, overall_mana)\n\tmana_changed.emit()\n\n\nfunc set_base_mana(base_mana: float):\n\t_base_mana = base_mana\n\n\nfunc get_base_mana() -> float:\n\treturn _base_mana\n\nfunc get_base_mana_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_MANA]\n\nfunc get_base_mana_bonus_percent() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_MANA_PERC])\n\n# NOTE: \"GetUnitState(unit, UNIT_STATE_MAX_MANA)\" in JASS\nfunc get_overall_mana() -> float:\n\treturn max(0, (get_base_mana() + get_base_mana_bonus()) * get_base_mana_bonus_percent())\n\n# Returns current percentage of mana\nfunc get_mana_ratio() -> float:\n\tvar overall_mana: float = get_overall_mana()\n\tvar ratio: float = Utils.divide_safe(_mana, overall_mana)\n\n\treturn ratio\n\n\nfunc set_base_mana_regen(base_mana_regen: float):\n\t_base_mana_regen = base_mana_regen\n\nfunc get_base_mana_regen() -> float:\n\treturn _base_mana_regen\n\n# NOTE: \"getProp_ManaRegBonus()\" in JASS\nfunc get_base_mana_regen_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_MANA_REGEN]\n\n# NOTE: \"getProp_ManaRegPercBonus()\" in JASS\nfunc get_base_mana_regen_bonus_percent() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_MANA_REGEN_PERC]\n\n# NOTE: regen values can be negative - this is on purpose.\n# If regen is negative, then unit will start losing mana.\n# This is how it works in original game.\nfunc get_overall_mana_regen() -> float:\n\treturn (get_base_mana_regen() + get_base_mana_regen_bonus()) * get_base_mana_regen_bonus_percent()\n\n\n# Returns damage done, in percentage.\n# Example: current health = 30/100 => damage done = 0.7 (70%)\nfunc get_damage_done() -> float:\n\tvar overall_health: float = get_overall_health()\n\tvar lowest_health_ratio: float = Utils.divide_safe(_lowest_health, overall_health)\n\tvar damage_done: float = 1.0 - lowest_health_ratio\n\t\n\treturn damage_done\n\n\n# NOTE: analog of SetUnitState(unit, UNIT_STATE_LIFE) in JASS\nfunc set_health(new_health: float):\n\tvar overall_health: float = get_overall_health()\n\t_health = clampf(new_health, 0.0, overall_health)\n\tif _health < _lowest_health:\n\t\t_lowest_health = _health\n\thealth_changed.emit()\n\n\n# NOTE: need this function for \"Second Chance\" special where\n# creep health needs to be set over max health.\nfunc set_health_over_max(new_health: float):\n\t_health = max(new_health, 0.0)\n\thealth_changed.emit()\n\n\n# NOTE: analog of GetUnitState(unit, UNIT_STATE_LIFE) in JASS\nfunc get_health() -> float:\n\treturn _health\n\nfunc get_base_health() -> float:\n\treturn _base_health\n\nfunc set_base_health(value: float):\n\t_base_health = value\n\t_lowest_health = value\n\nfunc get_base_health_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_HP]\n\nfunc get_base_health_bonus_percent() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_HP_PERC])\n\n# NOTE: do not allow max hp to go below 1 because that\n# doesn't make sense and the combat system won't work\n# correctly if a unit has max hp of 0\n# NOTE: analog of GetUnitState(unit, UNIT_STATE_MAX_LIFE) in JASS\nfunc get_overall_health() -> float:\n\treturn max(1, (get_base_health() + get_base_health_bonus()) * get_base_health_bonus_percent())\n\n# Returns current percentage of health\n# NOTE: unit.getLifePercent() in JASS\nfunc get_health_ratio() -> float:\n\tvar overall_health: float = get_overall_health()\n\tvar ratio: float = Utils.divide_safe(_health, overall_health)\n\n\treturn ratio\n\nfunc get_base_health_regen() -> float:\n\treturn _base_health_regen\n\nfunc get_base_health_regen_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_HP_REGEN]\n\nfunc get_base_health_regen_bonus_percent() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_HP_REGEN_PERC])\n\n# NOTE: regen values can be negative - this is on purpose.\n# If regen is negative, then unit will start losing health.\n# This is how it works in original game.\nfunc get_overall_health_regen() -> float:\n\treturn (get_base_health_regen() + get_base_health_regen_bonus()) * get_base_health_regen_bonus_percent()\n\nfunc get_prop_move_speed() -> float:\n\tvar base_value: float = _mod_value_map[ModificationType.enm.MOD_MOVESPEED]\n\tvar value: float\n\n\tif base_value > 1.0:\n\t\tvalue = base_value\n\telse:\n\t\tvalue = pow(3.0, base_value - 1.0)\n\n\treturn value\n\n\nfunc get_prop_move_speed_absolute() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_MOVESPEED_ABSOLUTE]\n\nfunc get_base_movespeed() -> float:\n\treturn Constants.DEFAULT_MOVE_SPEED\n\nfunc get_prop_atk_damage_received() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_ATK_DAMAGE_RECEIVED])\n\nfunc get_display_name() -> String:\n\treturn \"Generic Unit\"\n\n\nfunc set_hovered(hovered: bool):\n\tif _selected:\n\t\treturn\n\n\tvar indicator_color: Color\n\tif belongs_to_local_player():\n\t\tindicator_color = Color.WHITE\n\telse:\n\t\tindicator_color = Color.YELLOW\n\n\t_selection_indicator.modulate = indicator_color\n\t_unit_selection_outline.material.set_shader_parameter(\"line_color\", indicator_color)\n\t_selection_indicator.set_visible(hovered)\n\t_unit_selection_outline.set_visible(hovered)\n\t_hovered = hovered\n\thovered_changed.emit()\n\n\nfunc is_selected() -> bool:\n\treturn _selected\n\n\nfunc is_hovered() -> bool:\n\treturn _hovered\n\n\n# NOTE: this function only changes the visual state of this\n# unit - it doesn't make it THE selected unit. SelectUnit\n# does that.\nfunc set_selected(selected_arg: bool):\n\tvar selection_color: Color\n\tif self is Creep:\n\t\tselection_color = Color.RED\n\telse:\n\t\tif belongs_to_local_player():\n\t\t\tselection_color = Color.GREEN\n\t\telse:\n\t\t\tselection_color = Color.ORANGE\n\n\t_selection_indicator.modulate = selection_color\n\t_selection_indicator.set_visible(selected_arg)\n\t_unit_selection_outline.material.set_shader_parameter(\"line_color\", selection_color)\n\t_unit_selection_outline.set_visible(selected_arg)\n\t_selected = selected_arg\n\tselected_changed.emit()\n\nfunc get_base_damage_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_DAMAGE_BASE]\n\nfunc get_base_damage_bonus_percent() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DAMAGE_BASE_PERC])\n\nfunc get_damage_add() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DAMAGE_ADD])\n\nfunc get_damage_add_percent() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DAMAGE_ADD_PERC])\n\nfunc get_current_armor_damage_reduction() -> float:\n\tvar armor: float = get_overall_armor()\n\n\tvar reduction: float\n\tif armor >= 0:\n\t\treduction = armor / (armor + 25)\n\telse:\n\t\treduction = 0.0\n#\t\tNOTE: JASS code has the formula below, not sure why.\n#\t\tThis would mean that if armor is reduced below 0\n#\t\tthen reduction would be negative - meaning that\n#\t\tcreep would get healed??? Probably somewhere else in\n#\t\tJASS code this value would be forced to 0 anyway.\n\t\t# reduction = pow(0.94, -armor) - 1.0\n\n\treturn reduction\n\n# NOTE: analog of GetUnitState(unit, UNIT_STATE_MANA) in JASS\nfunc get_mana() -> float:\n\treturn _mana\n\nfunc set_base_armor(value: float):\n\t_base_armor = value\n\nfunc get_base_armor() -> float:\n\treturn _base_armor\n\nfunc get_base_armor_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_ARMOR]\n\nfunc get_base_armor_bonus_percent() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_ARMOR_PERC])\n\nfunc get_overall_armor() -> float:\n\treturn max(0, (get_base_armor() + get_base_armor_bonus()) * get_base_armor_bonus_percent())\n\nfunc get_overall_armor_bonus() -> float:\n\treturn (get_base_armor() + get_base_armor_bonus()) * get_base_armor_bonus_percent() - get_base_armor()\n\nfunc get_dps_bonus() -> float:\n\treturn _mod_value_map[ModificationType.enm.MOD_DPS_ADD]\n\n\nfunc get_damage_from_element(element: Element.enm) -> float:\n\tvar mod_type: ModificationType.enm = Element.convert_to_dmg_from_element_mod(element)\n\tvar damage_mod: float = max(0, _mod_value_map[mod_type])\n\n\treturn damage_mod\n\n\n# NOTE: unit.getDamageToCategory() in JASS\nfunc get_damage_to_category(category: CreepCategory.enm) -> float:\n\tvar mod_type: ModificationType.enm = CreepCategory.convert_to_mod_dmg_type(category)\n\tvar damage_mod: float = max(0, _mod_value_map[mod_type])\n\n\treturn damage_mod\n\n\n# NOTE: unit.getDamageToSize() in JASS\nfunc get_damage_to_size(creep_size: CreepSize.enm) -> float:\n\tvar mod_type: ModificationType.enm = CreepSize.convert_to_mod_dmg_type(creep_size)\n\tvar damage_mod: float = max(0, _mod_value_map[mod_type])\n\n\treturn damage_mod\n\nfunc get_total_damage_multiplier() -> float:\n\treturn max(0, _mod_value_map[ModificationType.enm.MOD_DMG_TOTAL_MULTIPLIER])\n\nfunc get_attack_type() -> AttackType.enm:\n\treturn AttackType.enm.PHYSICAL\n\nfunc get_exp() -> float:\n\treturn _experience_centi / 100.0\n\n\nfunc reached_max_level() -> bool:\n\tvar max_level: int = get_max_level()\n\tvar is_max_level: bool = _level == max_level\n\n\treturn is_max_level\n\n\nfunc get_max_level() -> int:\n\tvar max_level: int\n\n\tvar player: Player = get_player()\n\tif player != null:\n\t\tmax_level = player.get_max_tower_level()\n\telse:\n\t\tmax_level = Constants.TOWER_MAX_LEVEL_BASE\n\n\treturn max_level\n\n\nfunc get_buff_groups(mode_list: Array) -> Array[int]:\n\tvar result: Array[int] = []\n\n# \tNOTE: need ordered iteration for determinism\n\tfor buff_group in range(1, Constants.BUFFGROUP_COUNT + 1):\n\t\tvar this_mode: BuffGroupMode.enm = _buff_groups[buff_group]\n\t\tif mode_list.has(this_mode):\n\t\t\tresult.append(buff_group)\n\n\treturn result\n\n\nfunc set_buff_group_mode(buff_group: int, mode: BuffGroupMode.enm):\n\tif !_buff_groups.has(buff_group):\n\t\tpush_error(\"Invalid buff group: \", buff_group)\n\n\t\treturn\n\n\t_buff_groups[buff_group] = mode\n\n\tbuff_group_changed.emit()\n\n\nfunc get_buff_group_mode(buff_group: int) -> BuffGroupMode.enm:\n\tvar mode: BuffGroupMode.enm = _buff_groups[buff_group]\n\n\treturn mode\n"
  },
  {
    "path": "tools/README.md",
    "content": "This folder contains tool scripts which are intended to be used via a command-line.\nThese scripts are not used by the game itself.\n\nRun the scripts like this:\n\n\"path/to/Godot/Godot_v4.1.4-rc1_win64_console.exe\" -s \"path/to/youtd2/tools/tool_script.gd\" -- arg1 arg2\n\n"
  },
  {
    "path": "tools/check_buff_icons.gd",
    "content": "extends MainLoop\n\n\n# Checks which buff icons do not point to existing assets.\n\n\nconst SET_BUFF_ICON_FUNC: String = \".set_buff_icon(\"\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tprint(\" \\n\")\n\tprint(\"List of files which use invalid buff icons:\")\n\tprint(\" \\n\")\n\n\tprocess_dir(\"res://src\")\n\n\nfunc process_dir(dir_path: String):\n# \tProcess files in current dir\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\tvar dir: DirAccess = DirAccess.open(dir_path)\n\tfor filename in file_list:\n\t\tvar file_path: String = \"%s/%s\" % [dir_path, filename]\n\t\tprocess_file(file_path)\n\n#\tProcess child dirs\n\tvar dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor child_dir in dir_list:\n\t\tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t\tprocess_dir(child_dir_path)\n\n\nfunc process_file(file_path: String):\n\tvar file_is_script: bool = file_path.ends_with(\".gd\")\n\n\tif !file_is_script:\n\t\treturn\n\n\tvar file: FileAccess = FileAccess.open(file_path, FileAccess.READ)\n\tvar content: String = file.get_as_text()\n\n\tvar find_index: int = 0\n\n\twhile true:\n\t\tvar find_result: int = content.find(SET_BUFF_ICON_FUNC, find_index)\n\n\t\tif find_result == -1:\n\t\t\tbreak\n\n\t\tvar opening_bracket_index: int = content.find(\"(\", find_result)\n\t\tvar closing_bracket_index: int = content.find(\")\", find_result)\n\n\t\tvar buff_icon_path: String = content.substr(opening_bracket_index + 1, closing_bracket_index - opening_bracket_index - 1)\n\t\tbuff_icon_path = buff_icon_path.replace(\"\\\"\", \"\")\n\n\t\tvar script_uses_valid_buff_icon: bool = ResourceLoader.exists(buff_icon_path)\n\n\t\tif !script_uses_valid_buff_icon:\n\t\t\tprint(\"%s => %s\" % [file_path, buff_icon_path])\n\n\t\tfind_index = closing_bracket_index\n"
  },
  {
    "path": "tools/check_rng_sync.gd",
    "content": "extends MainLoop\n\n\n# Checks that all scripts use random functions via\n# RandomNumberGenerator instance. This is to prevent desyncs\n# because using random functions from global namespace\n# causes desyncs.\n\n\nconst RESULT_FOLDER: String = \"placeholders\"\n\nconst GOOD_PREFIX: String = \"rng.\"\n\nconst RANDOM_FUNC_LIST: Array = [\n\t[GOOD_PREFIX, \"randf\"],\n\t[GOOD_PREFIX, \"randfn\"],\n\t[GOOD_PREFIX, \"randf_range\"],\n\t[GOOD_PREFIX, \"randi\"],\n\t[GOOD_PREFIX, \"randi_range\"],\n#\tNOTE: pick_random() and shuffle() are attached to Utils\n#\tbecause RandomNumberGenerator doesn't have these\n#\tfunctions\n\t[\"Utils.\", \"pick_random\"],\n\t[\"Utils.\", \"shuffle\"],\n]\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tprocess_dir(\".\")\n\n\nfunc process_dir(dir_path: String):\n# \tProcess files in current dir\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\tvar dir: DirAccess = DirAccess.open(dir_path)\n\tfor filename in file_list:\n\t\tvar file_path: String = \"%s/%s\" % [dir_path, filename]\n\t\tprocess_file(file_path)\n\n#\tProcess child dirs\n\tvar dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor child_dir in dir_list:\n\t\tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t\tprocess_dir(child_dir_path)\n\n\nfunc process_file(file_path: String):\n\tvar file_is_script: bool = file_path.ends_with(\".gd\")\n\n\tif !file_is_script:\n\t\treturn\n\n\tvar file: FileAccess = FileAccess.open(file_path, FileAccess.READ)\n\tvar content: String = file.get_as_text()\n\n\tvar misused_func_list: Array[String] = []\n\n\tfor element in RANDOM_FUNC_LIST:\n\t\tvar good_prefix: String = element[0]\n\t\tvar function: String = element[1]\n\t\t\n\t\tvar func_without_prefix: String = \"%s(\" % [function]\n\t\tvar func_with_prefix: String = \"%s%s(\" % [good_prefix, function]\n\t\tvar all_func_count: int = content.count(func_without_prefix)\n\t\tvar good_prefix_count: int = content.count(func_with_prefix)\n\n\t\tvar func_was_used_with_good_prefixes: bool = all_func_count == good_prefix_count\n\n\t\tif !func_was_used_with_good_prefixes:\n\t\t\tmisused_func_list.append(function)\n\n\tif !misused_func_list.is_empty():\n\t\tprint(\"!!! Issue found in file %s\" % file_path)\n\t\tprint(\"Misused functions: \", misused_func_list)\n\n\treturn content\n"
  },
  {
    "path": "tools/check_translations.gd",
    "content": "extends MainLoop\n\n\n# Checks validity of translations in texts.csv file. Run\n# this tool when adding new things to texts.csv.\n\nconst ARG_COUNT: int = 2\n\nvar all_is_ok: bool = true\n# NOTE: reduce this value to process a smaller amount of\n# lines. Useful when there are too many issues posted in\n# output.\nconst LINE_LIMIT: int = 10000\nconst PRINT_CHANGED_IDS: bool = true\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 2 args - old texts.csv + new texts.csv\")\n\n\t\treturn\n\n\tvar text_csv_path_old: String = arg_list[0]\n\tvar text_csv_path_new: String = arg_list[1]\n\n\tvar text_id_map: Dictionary = {}\n\n\tvar csv_old: Array[PackedStringArray] = load_csv(text_csv_path_old)\n\tvar csv_new: Array[PackedStringArray] = load_csv(text_csv_path_new)\n\n\tvar row_count_old: int = csv_old.size()\n\tvar row_count_new: int = csv_new.size()\n\tvar row_count_is_ok: bool = row_count_old == row_count_new\n\tif !row_count_is_ok:\n\t\tprint(\"Mismatch in row counts: old = %s, new = %s\" % [row_count_old, row_count_new])\n\t\tall_is_ok = false\n\n\n\tvar digit_list: Array = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\"]\n\n\tvar line_count: int = 0\n\n\tfor i in range(csv_old.size()):\n\t\tline_count += 1\n\n\t\tif line_count > LINE_LIMIT:\n\t\t\tbreak\n\n\t\tvar line_old: PackedStringArray = csv_old[i]\n\t\tvar line_new: PackedStringArray = csv_new[i]\n\n\t\tvar text_id_old: String = line_old[0]\n\t\tvar text_id_new: String = line_new[0]\n\t\tvar text_id_is_ok: bool = text_id_old == text_id_new\n\t\tif !text_id_is_ok:\n\t\t\tprint(\"\\n !!!!Mismatch in text id: old = %s, new = %s\" % [text_id_old, text_id_new])\n\t\t\tall_is_ok = false\n\n\t\t# NOTE: disabled for now, there are too many bad text ids, will fix later\n\t\t# var text_id_first_char_is_ok: bool = !digit_list.has(text_id_new.substr(0, 1))\n\t\t# if !text_id_first_char_is_ok:\n\t\t# \tprint(\"\\n !!!!Bad text id: %s\" % [text_id_new])\n\t\t# \tall_is_ok = false\n\n\t\tvar english_text_old: String = line_old[1]\n\t\tvar english_text_new: String = line_new[1]\n\t\tvar english_text_is_ok: bool = english_text_old == english_text_new\n\t\tif !english_text_is_ok:\n\t\t\tprint(\" \\n!!!!Mismatch in english text:\\nOLD:\\n\\\"\\\"\\\"\\n%s\\n\\\"\\\"\\\"\\n \\nNEW:\\n\\\"\\\"\\\"\\n%s\\n\\\"\\\"\\\"\" % [english_text_old, english_text_new])\n\t\t\tall_is_ok = false\n\n\t\tvar text_id_is_duplicate: bool = text_id_map.has(text_id_old)\n\t\tif text_id_is_duplicate:\n\t\t\tprint(\" \\n!!!!Detected duplicate text id: %s\" % text_id_old)\n\t\t\tall_is_ok = false\n\t\ttext_id_map[text_id_old] = true\n\n\t\tif text_id_is_ok && PRINT_CHANGED_IDS:\n\t\t\tvar chinese_text_old: String = line_old[2]\n\t\t\tvar chinese_text_new: String = line_new[2]\n\t\t\tvar chinese_text_changed: bool = chinese_text_old != chinese_text_new\n\n\t\t\tif chinese_text_changed:\n\t\t\t\tprint(\"Text change at this id: %s\" % text_id_old)\n\n\tcheck_for_broken_tags(text_csv_path_new)\n\n\tif all_is_ok:\n\t\tprint(\"All is okay!\")\n\n\n# This f-n checks for issues with BBCode tags:\n# \"]blahbla\"\n# or \"blahbla color=GOLD] blahbla\"\n# or \"blahbla [color=GOLD blahblah\"\nfunc check_for_broken_tags(path: String):\n\tvar file: FileAccess = FileAccess.open(path, FileAccess.READ)\n\n\tvar line_index: int = 0\n\n\twhile !file.eof_reached():\n\t\tvar line: String = file.get_line()\n\n\t\tvar closing_bracket_count: int = line.count(\"]\")\n\t\tvar opening_bracket_count: int = line.count(\"[\")\n\n\t\tvar bracket_mismatch: bool = closing_bracket_count != opening_bracket_count\n\n\t\tif bracket_mismatch:\n\t\t\tprint(\" \\n!!!!Detected mismatched brackets on line %s\" % line_index)\n\t\t\tall_is_ok = false\n\n\t\tline_index += 1\n\n\n# NOTE: need to duplicate this f-n from Utils unfortunately\n# because Utils is not accessible in a tool script.\nstatic func load_csv(path: String) -> Array[PackedStringArray]:\n\tvar file_exists: bool = FileAccess.file_exists(path)\n\n\tif !file_exists:\n\t\tprint_debug(\"Failed to load CSV because file doesn't exist. Path: %s\" % path)\n\n\t\treturn []\n\n\tvar list: Array[PackedStringArray] = []\n\n\tvar file: FileAccess = FileAccess.open(path, FileAccess.READ)\n\n\tvar skip_title_row: bool = true\n\twhile !file.eof_reached():\n\t\tvar csv_line: PackedStringArray = file.get_csv_line()\n\n\t\tif skip_title_row:\n\t\t\tskip_title_row = false\n\t\t\tcontinue\n\n\t\tvar is_last_line: bool = csv_line.size() == 0 || (csv_line.size() == 1 && csv_line[0].is_empty())\n\t\tif is_last_line:\n\t\t\tcontinue\n\n\t\tlist.append(csv_line)\n\n\tfile.close()\n\n\treturn list\n"
  },
  {
    "path": "tools/check_tscn_paths_in_scripts.gd",
    "content": "extends MainLoop\n\n\n# Checks that all scripts use valid .tscn paths.\n\n\nvar tscn_path_list: Array = []\nvar tscn_regex: RegEx\n\n\nfunc _initialize():\t\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\ttscn_regex = RegEx.new()\n\ttscn_regex.compile(\"\\\"[^\\\"]*.tscn\\\"\")\n\n\ttscn_path_list = generate_tscn_path_list()\n\n\tcheck_scripts_in_dir(\".\")\n\n\nfunc generate_tscn_path_list() -> Array[String]:\n\tvar result: Array[String] = []\n\t\n\tgenerate_tscn_path_list_helper(\".\", result)\n\t\n\treturn result\n\n\nfunc generate_tscn_path_list_helper(dir_path: String, result: Array[String]):\n# \tProcess files in current dir\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\tvar dir: DirAccess = DirAccess.open(dir_path)\n\tfor filename in file_list:\n\t\tvar file_path: String = \"%s/%s\" % [dir_path, filename]\n\t\tvar file_extension: String = file_path.get_extension()\n\t\tvar file_is_tscn: bool = file_extension == \"tscn\"\n\n\t\tif file_is_tscn:\n\t\t\tvar file_path_via_res: String = file_path.replace(\"./src/\", \"res://src/\")\n\t\t\tresult.append(file_path_via_res)\n\n#\tProcess child dirs\n\tvar dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor child_dir in dir_list:\n\t\tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t\tgenerate_tscn_path_list_helper(child_dir_path, result)\n\n\nfunc check_scripts_in_dir(dir_path: String):\n# \tProcess files in current dir\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\tvar dir: DirAccess = DirAccess.open(dir_path)\n\tfor filename in file_list:\n\t\tvar file_path: String = \"%s/%s\" % [dir_path, filename]\n\t\tvar file_extension: String = file_path.get_extension()\n\t\tvar file_is_gd: bool = file_extension == \"gd\"\n\n\t\tif file_is_gd:\n\t\t\tcheck_script_file(file_path)\n\n#\tProcess child dirs\n\tvar dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor child_dir in dir_list:\n\t\tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t\tcheck_scripts_in_dir(child_dir_path)\n\n\nfunc check_script_file(file_path: String):\n\tvar file: FileAccess = FileAccess.open(file_path, FileAccess.READ)\n\tvar content: String = file.get_as_text()\n\n\tvar regex_match_list: Array[RegExMatch] = tscn_regex.search_all(content)\n\n\tfor regex_match in regex_match_list:\n\t\tvar tscn_path: String = regex_match.get_string().replace(\"\\\"\", \"\")\n\t\tvar path_is_valid: bool = tscn_path_list.has(tscn_path)\n\n\t\tif !path_is_valid:\n\t\t\tprint(\"Found invalid tscn path in script! Path: %s, script: %s.\" % [tscn_path, file_path])\n"
  },
  {
    "path": "tools/convert_blender_export.gd",
    "content": "extends MainLoop\n\n\n# Script to take results of blender export and turn it into\n# spritesheets.\n# Input: directory structure with separate sprites.\n# Output: a set of spritesheets\n\n\nconst CELL_WIDTH = 512\nconst COLUMNS = 4 \nconst ANIMATIONS = [\"floating\", \"slow_run\", \"run\", \"death\", \"stunned\"]\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tfor dir in ANIMATIONS:\n\t\tvar direction_dirs: PackedStringArray = DirAccess.get_directories_at(dir)\n\n\t\tfor direction_dirname in direction_dirs:\n\t\t\tcombine_tiles(dir, direction_dirname)\n\n\nfunc combine_tiles(animation: String, direction_dirname: String):\n\tvar direction_dir_path: String = \"%s/%s\" % [animation, direction_dirname]\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(direction_dir_path)\n\t\n\tprint(\"Processing [%s] frames for [%s] animation.\" % [file_list.size(), animation])\n\t\n\tvar row_count: int = int(ceil(float(file_list.size()) / COLUMNS))\n\n\tvar atlas_width: float = COLUMNS * CELL_WIDTH\n\tvar atlas_height: float = row_count * CELL_WIDTH\n\n\tvar atlas_image: = Image.create(atlas_width, atlas_height, false, Image.FORMAT_RGBA8)\n\n\tfor i in range(0, file_list.size()):\n\t\tvar file_name: String = file_list[i]\n\t\tvar file_path: String = \"%s/%s\" % [direction_dir_path, file_name]\n\t\tvar image: Image = Image.load_from_file(file_path)\n\t\tvar buffer: PackedByteArray = image.save_png_to_buffer()\n\n\t\tfor x in range(0, CELL_WIDTH):\n\t\t\tfor y in range(0, CELL_WIDTH):\n\t\t\t\tvar atlas_x = CELL_WIDTH * (i % COLUMNS) + x\n\t\t\t\tvar atlas_y = CELL_WIDTH * (i / COLUMNS) + y\n\n\t\t\t\tvar pixel: Color = image.get_pixel(x, y)\n\t\t\t\tatlas_image.set_pixel(atlas_x, atlas_y, pixel)\n\n\tvar atlas_filename: String = \"%s_%s.png\" % [animation, direction_dirname]\n\tvar atlas_folder: String = \"res://generated-atlases\"\n\tDirAccess.make_dir_absolute(atlas_folder)\n\tvar atlas_path: String = \"%s/%s\" % [atlas_folder, atlas_filename]\n\tatlas_image.save_png(atlas_path)\n"
  },
  {
    "path": "tools/convert_tower_scene_to_sprite.gd",
    "content": "extends MainLoop\n\n\n# NOTE: this script works for most towers but stumbles on\n# some. Run TestTowersTool to check which towers failed and\n# fix manually.\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(\".\")\n\n\tfor file in file_list:\n\t\tprocess_file(file)\n\n\nfunc process_file(path: String):\n\tif !FileAccess.file_exists(path):\n\t\tpush_error(\"No file found at path %s\" % path)\n\n\t\treturn\n\n\tvar original_content: String = FileAccess.get_file_as_string(path)\n\tvar result_content: String = make_result_content(original_content)\n\n\t# var result_path: String = path.replace(\".tscn\", \"-result.tscn\")\n\tvar result_path: String = path\n\tvar result_file: FileAccess = FileAccess.open(result_path, FileAccess.WRITE)\n\tresult_file.store_string(result_content)\n\n\nfunc make_result_content(original_content: String) -> String:\n\tvar original_lines: Array = original_content.split(\"\\n\")\n\tvar result_lines: Array = []\n\n\tfor line in original_lines:\n\t\tvar tower_resource: bool = line.contains(\"ext_resource type=\\\"PackedScene\\\"\")\n\t\tvar script_resource: bool = line.contains(\"ext_resource type=\\\"Script\\\"\")\n\t\tif tower_resource || script_resource:\n\t\t\tcontinue\n\n\t\tvar script_node: bool = line.contains(\"script = \")\n\t\tif script_node:\n\t\t\t# NOTE: also remove previous line and previous\n\t\t\t# empty line\n\t\t\tresult_lines.pop_back()\n\t\t\tresult_lines.pop_back()\n\n\t\t\tcontinue\n\n\t\tvar sprite_node: bool = line.contains(\"node name=\")\n\t\tif sprite_node:\n\t\t\tline = \"[node name=\\\"Sprite2D\\\" type=\\\"Sprite2D\\\"]\"\n\n\t\tvar load_steps: bool = line.contains(\"load_steps\")\n\t\tif load_steps:\n\t\t\tline = fix_load_steps(line)\n\n\t\tresult_lines.append(line)\n\n\tvar result_content: String = \"\\n\".join(result_lines)\n\n\treturn result_content\n\n\nfunc fix_load_steps(line: String) -> String:\n\tvar load_steps_left: String = \"load_steps=\"\n\tvar split_load_steps: Array = line.split(load_steps_left)\n\n\tif split_load_steps.size() == 1:\n\t\tpush_error(\"Failed to fix load steps, error 1\")\n\n\t\treturn line\n\n\tvar split_space: Array = split_load_steps[1].split(\" \")\n\n\tif split_space.size() == 1:\n\t\tpush_error(\"Failed to fix load steps, error 2\")\n\n\t\treturn line\n\n\tvar original_steps_string: String = split_space[0]\n\tvar original_steps: int = original_steps_string as int\n#\tNOTE: subtract 2 because there's -1 step from removal of\n#\tscript and another -1 step from removal of Tower.tscn\n\tvar result_steps: int = original_steps - 2\n\n\tvar original_load_steps_substr: String = load_steps_left + original_steps_string\n\tvar fixed_load_steps_substr: String = load_steps_left + str(result_steps)\n\n\tvar fixed_line: String = line.replace(original_load_steps_substr, fixed_load_steps_substr)\n\n\treturn fixed_line\n"
  },
  {
    "path": "tools/create_tilesheet.gd",
    "content": "extends MainLoop\n\n\n# This script takes individual tiles from current folder and\n# combines them into a tilesheet.\n#\n# Takes one arg which should be the beginning of filenames to process\n#\n# Example: if you pass \"Barrel\", then script will process all files which start with \"Barrel\"\n# And save result to \"Barrel-combined.png\"\n#\n# Input tiles must be 256x512\n# Output will have margins of 4 around tiles.\n# Output will have 8 rows.\n\n\nconst ARG_COUNT: int = 1\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\nconst MARGIN: int = 0\nconst CELL_WIDTH_WITH_MARGIN: int = CELL_WIDTH + MARGIN * 2\nconst CELL_HEIGHT_WITH_MARGIN: int = CELL_HEIGHT + MARGIN * 2\nconst RESULT_COLUMN_COUNT: int = 8\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tprint(arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 1 arg, the beginning of filenames to process\")\n\n\t\treturn\n\n\tvar filename_beginning: String = arg_list[0]\n\n\tprocess(filename_beginning)\n\n\nfunc process(filename_beginning: String):\n\tvar filename_list: Array = get_filename_list(filename_beginning)\n\n\tif filename_list.is_empty():\n\t\tpush_error(\"No files found\")\n\n\t\treturn\n\n\tvar file_count: int = filename_list.size()\n\tvar result_column_count: int = min(file_count, RESULT_COLUMN_COUNT)\n\tvar result_row_count: int = ceil(float(file_count) / result_column_count)\n\tvar result_width: int = result_column_count * CELL_WIDTH_WITH_MARGIN\n\tvar result_height: int = result_row_count * CELL_HEIGHT_WITH_MARGIN\n\n\tvar tilesheet_image: = Image.create(result_width, result_height, false, Image.FORMAT_RGBA8)\n\n\tfor i in range(0, filename_list.size()):\n\t\tvar filename: String = filename_list[i]\n\t\tvar tile_image: Image = Image.load_from_file(filename)\n\t\t\n\t\tvar current_column: int = i % result_column_count\n\t\tvar current_row: int = i / result_column_count\n\t\tvar src_rect_pos: Vector2i = Vector2i(0, 0)\n\t\tvar src_rect_size: Vector2i = Vector2i(CELL_WIDTH, CELL_HEIGHT)\n\t\tvar src_rect: Rect2i = Rect2i(src_rect_pos, src_rect_size)\n\t\tvar blit_dst: Vector2i = Vector2i(current_column * CELL_WIDTH_WITH_MARGIN + MARGIN, current_row * CELL_HEIGHT_WITH_MARGIN + MARGIN)\n\t\ttilesheet_image.blit_rect(tile_image, src_rect, blit_dst)\n\n\tvar result_path: String = \"%s-combined.png\" % filename_beginning\n\ttilesheet_image.save_png(result_path)\n\n\nfunc get_filename_list(filename_beginning: String) -> Array[String]:\n\tvar result: Array[String] = []\n\n\tvar current_dir: DirAccess = DirAccess.open(\".\")\n\tvar filename_list: Array = current_dir.get_files()\n\n\tfor filename in filename_list:\n\t\tvar filename_ok: bool = filename.begins_with(filename_beginning)\n\n\t\tif filename_ok:\n\t\t\tresult.append(filename)\n\n\treturn result\n"
  },
  {
    "path": "tools/cut_single_tile.gd",
    "content": "extends MainLoop\n\n\n# Cuts all single tiles in current directory to look like\n# they are behind a floor2 tile. Creates two \"left\" and\n# \"right\" versions. Note that this script assumes that the\n# cut tiles will be placed above brick tiles. There will be\n# a gap if you place these tiles above dirt tiles.\n\n\nconst ARG_COUNT: int = 0\nconst PNG_SUFFIX: String = \".png\"\nconst LEFT_SUFFIX: String = \"-cut-left.png\"\nconst RIGHT_SUFFIX: String = \"-cut-right.png\"\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\n\nconst left_section: PackedVector2Array = [Vector2(0, 449), Vector2(256, 319), Vector2(256, 0), Vector2(0, 0)]\nconst right_section: PackedVector2Array = [Vector2(0, 319), Vector2(256, 449), Vector2(256, 0), Vector2(0, 0)]\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 0 args.\")\n\t\tprint(arg_list)\n\n\t\treturn\n\n\tprocess_current_dir()\n\n\nfunc process_current_dir():\n\tvar current_dir: DirAccess = DirAccess.open(\".\")\n\tvar current_dir_path: String = current_dir.get_current_dir()\n\tvar filename_list: Array = current_dir.get_files()\n\n\tvar results_dir_path: String = \"%s/results\" % current_dir_path\n\tDirAccess.make_dir_absolute(results_dir_path)\n\n\tfor filename in filename_list:\n\t\tvar file_is_png: bool = filename.ends_with(PNG_SUFFIX)\n\n\t\tif file_is_png:\n\t\t\tprocess_file(results_dir_path, filename)\n\n\nfunc process_file(results_dir_path: String, filename: String):\n\tprint(\"Processing file:\", filename)\n\n\tvar original_image: Image = Image.load_from_file(filename)\n\tvar left_result_image: = Image.create(original_image.get_width(), original_image.get_height(), false, Image.FORMAT_RGBA8)\n\tvar right_result_image: = Image.create(original_image.get_width(), original_image.get_height(), false, Image.FORMAT_RGBA8)\n\n\tfor cell_x in range(0, CELL_WIDTH):\n\t\tfor cell_y in range(0, CELL_HEIGHT):\n\t\t\tvar cell_pos: Vector2 = Vector2(cell_x, cell_y)\n\t\t\tvar pixel: Color = original_image.get_pixel(cell_x, cell_y)\n\n\t\t\tvar is_part_of_left: bool = need_to_copy_pixel(cell_pos, left_section)\n\t\t\tvar is_part_of_right: bool = need_to_copy_pixel(cell_pos, right_section)\n\n\t\t\tif is_part_of_left:\n\t\t\t\tleft_result_image.set_pixel(cell_x, cell_y, pixel)\n\t\t\tif is_part_of_right:\n\t\t\t\tright_result_image.set_pixel(cell_x, cell_y, pixel)\n\n\tvar left_result_path: String = \"%s/%s\" % [results_dir_path, filename]\n\tleft_result_path = left_result_path.replace(PNG_SUFFIX, LEFT_SUFFIX)\n\tleft_result_image.save_png(left_result_path)\n\n\tvar right_result_path: String = \"%s/%s\" % [results_dir_path, filename]\n\tright_result_path = right_result_path.replace(PNG_SUFFIX, RIGHT_SUFFIX)\n\tright_result_image.save_png(right_result_path)\n\n\nfunc need_to_copy_pixel(pos: Vector2, polygon: PackedVector2Array):\n\tvar pixel_is_in_poly: bool = Geometry2D.is_point_in_polygon(pos, polygon)\n\t\n\treturn pixel_is_in_poly\n"
  },
  {
    "path": "tools/cut_tiles_into_connectors.gd",
    "content": "extends MainLoop\n\n\n# Script to take a tileset and cut into 2 sections:\n# 1. part below floor1\n# 2. part above floor1\n# These tiles are intended to be used as \"connectors\" to be\n# placed between two layers of floor tiles.\n\n\nconst ARG_COUNT: int = 1\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\nconst MARGIN: int = 0\nconst CELL_WIDTH_WITH_MARGIN: int = CELL_WIDTH + MARGIN * 2\nconst CELL_HEIGHT_WITH_MARGIN: int = CELL_HEIGHT + MARGIN * 2\n\n# Cuts out bottom section in v shape\nconst polygon_bottom_v: PackedVector2Array = [Vector2(128, 511), Vector2(127, 511), Vector2(0, 447), Vector2(0, 319), Vector2(127, 383), Vector2(128, 383), Vector2(255, 319), Vector2(255, 447)]\n# Cuts out top section in hexagon shape. It's basically the\n# rest of the tile above the bottom v shape.\nconst polygon_top_hexagon: PackedVector2Array = [Vector2(128, 383), Vector2(127, 383), Vector2(0, 319), Vector2(0, 191), Vector2(127, 127), Vector2(128, 127), Vector2(255, 191), Vector2(255, 320)]\n\n# NOTE: modify these to change which shape is used to cut\n# bottom/top sections\nconst POLYGON_FOR_BOTTOM: PackedVector2Array = polygon_bottom_v\nconst POLYGON_FOR_TOP: PackedVector2Array = polygon_top_hexagon\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 1 args: path to tileset.\")\n\t\tprint(arg_list)\n\n\t\treturn\n\n\tvar path: String = arg_list[0]\n\n\tprocess_path(path)\n\n\nfunc process_path(path: String):\n\tprint(\"Processing path:\", path)\n\n\tvar original_image: Image = Image.load_from_file(path)\n\n\tvar column_count: int = int(original_image.get_width() / CELL_WIDTH_WITH_MARGIN)\n\tvar row_count: int = int(original_image.get_height() / CELL_HEIGHT_WITH_MARGIN)\n\tvar new_row_count: int = row_count * 2\n\tvar new_column_count: int = column_count\n\tvar new_tilesheet_width: int = new_column_count * CELL_WIDTH_WITH_MARGIN\n\tvar new_tilesheet_height: int = new_row_count * CELL_HEIGHT_WITH_MARGIN\n\n\tvar atlas_image: = Image.create(new_tilesheet_width, new_tilesheet_height, false, Image.FORMAT_RGBA8)\n\n\tfor column in range(0, column_count):\n\t\tfor row in range(0, row_count):\n\t\t\tfor cell_x in range(0, CELL_WIDTH):\n\t\t\t\tfor cell_y in range(0, CELL_HEIGHT):\n\t\t\t\t\tvar cell_pos: Vector2 = Vector2(cell_x, cell_y)\n\t\t\t\t\tvar tilesheet_x: int = cell_x + MARGIN + CELL_WIDTH_WITH_MARGIN * column\n\t\t\t\t\tvar tilesheet_y: int = cell_y + MARGIN + CELL_HEIGHT_WITH_MARGIN * row\n\t\t\t\t\tvar pixel: Color = original_image.get_pixel(tilesheet_x, tilesheet_y)\n\n\t\t\t\t\tvar is_part_of_bottom_v: bool = need_to_copy_pixel(cell_pos, POLYGON_FOR_BOTTOM)\n\t\t\t\t\tvar is_part_of_top_v: bool = need_to_copy_pixel(cell_pos, POLYGON_FOR_TOP)\n\n#\t\t\t\t\tNOTE: shift down top section so that\n#\t\t\t\t\tit's bottom section touches bottom of\n#\t\t\t\t\tcell\n\t\t\t\t\tvar new_tilesheet_y_for_top_section: int = cell_y + MARGIN + CELL_HEIGHT_WITH_MARGIN * row * 2 + 128\n#\t\t\t\t\tNOTE: draw bottom section on next row,\n#\t\t\t\t\tbelow top section\n\t\t\t\t\tvar new_tilesheet_y_for_bottom_section: int = cell_y + MARGIN + CELL_HEIGHT_WITH_MARGIN * row * 2 + CELL_HEIGHT_WITH_MARGIN\n\n\t\t\t\t\tif is_part_of_top_v:\n\t\t\t\t\t\tatlas_image.set_pixel(tilesheet_x, new_tilesheet_y_for_top_section, pixel)\n\n\t\t\t\t\tif is_part_of_bottom_v:\n\t\t\t\t\t\tatlas_image.set_pixel(tilesheet_x, new_tilesheet_y_for_bottom_section, pixel)\n\n\n\tvar original_filename: String = path.get_file()\n\tvar new_path: String = path.replace(\".png\", \"-cut.png\")\n\tatlas_image.save_png(new_path)\n\n\nfunc need_to_copy_pixel(pos: Vector2, polygon: PackedVector2Array):\n\tvar pixel_is_in_poly: bool = Geometry2D.is_point_in_polygon(pos, polygon)\n\t\n\treturn pixel_is_in_poly\n"
  },
  {
    "path": "tools/cut_tiles_into_decorations.gd",
    "content": "extends MainLoop\n\n\n# Script to take a decoration tileset and transform into 2 variations:\n# 1. cut version to place above and left of floor2\n# 2. cut version to place above and right of floor2\n# Note that this script adds +20 to height because it\n# assumes that floor2 tiles are the full height brick\n# versions. If floor2 tiles are \"short\" dirt tiles, then\n# there will be a gap.\n# \n# Note also that original file will be renamed to have \"\n# (raw).png\" suffix if it's not named like that already. New\n# file will have the name of the original file without the\n# suffix.\n# Examples:\n# \"foo.png\" -> \"foo (raw).png\" (original) + \"foo.png\" (cut)\n# \"foo (raw).png\" -> \"foo (raw).png\" (original) + \"foo.png\" (cut)\n\n\nconst ARG_COUNT: int = 1\nconst RAW_SUFFIX: String = \" (raw).png\"\nconst PNG_SUFFIX: String = \".png\"\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\nconst MARGIN: int = 0\nconst CELL_WIDTH_WITH_MARGIN: int = CELL_WIDTH + MARGIN * 2\nconst CELL_HEIGHT_WITH_MARGIN: int = CELL_HEIGHT + MARGIN * 2\n\nconst above_and_left_of_wall: PackedVector2Array = [Vector2(0, 449), Vector2(256, 319), Vector2(256, 0), Vector2(0, 0)]\nconst above_and_right_of_wall: PackedVector2Array = [Vector2(0, 319), Vector2(256, 449), Vector2(256, 0), Vector2(0, 0)]\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 1 args: path to tileset.\")\n\t\tprint(arg_list)\n\n\t\treturn\n\n\tvar path: String = arg_list[0]\n\n\tprocess_path(path)\n\n\nfunc process_path(path: String):\n\tprint(\"Processing path:\", path)\n\n\tvar current_dir = DirAccess.open(\".\")\n\n\tvar raw_path: String\n\tif path.ends_with(RAW_SUFFIX):\n\t\traw_path = path\n\telse:\n\t\traw_path = path.replace(PNG_SUFFIX, RAW_SUFFIX)\n\n#\t\tIf original file doesn't end with raw suffix, rename\n#\t\tit so it has the suffix.\n\t\tcurrent_dir.rename(path, raw_path)\n\n\tvar result_path: String = raw_path.replace(RAW_SUFFIX, PNG_SUFFIX)\n\n\tvar original_image: Image = Image.load_from_file(raw_path)\n\n\tvar column_count: int = int(original_image.get_width() / CELL_WIDTH_WITH_MARGIN)\n\tvar row_count: int = int(original_image.get_height() / CELL_HEIGHT_WITH_MARGIN)\n\tvar new_row_count: int = row_count * 2\n\tvar new_column_count: int = column_count\n\tvar new_tilesheet_width: int = new_column_count * CELL_WIDTH_WITH_MARGIN\n\tvar new_tilesheet_height: int = new_row_count * CELL_HEIGHT_WITH_MARGIN\n\n\tvar atlas_image: = Image.create(new_tilesheet_width, new_tilesheet_height, false, Image.FORMAT_RGBA8)\n\n\tfor column in range(0, column_count):\n\t\tfor row in range(0, row_count):\n\t\t\tfor cell_x in range(0, CELL_WIDTH):\n\t\t\t\tfor cell_y in range(0, CELL_HEIGHT):\n\t\t\t\t\tvar cell_pos: Vector2 = Vector2(cell_x, cell_y)\n\t\t\t\t\tvar tilesheet_x: int = cell_x + MARGIN + CELL_WIDTH_WITH_MARGIN * column\n\t\t\t\t\tvar tilesheet_y: int = cell_y + MARGIN + CELL_HEIGHT_WITH_MARGIN * row\n\t\t\t\t\tvar pixel: Color = original_image.get_pixel(tilesheet_x, tilesheet_y)\n\n\t\t\t\t\tvar is_part_of_section_2: bool = need_to_copy_pixel(cell_pos, above_and_left_of_wall)\n\t\t\t\t\tvar is_part_of_section_3: bool = need_to_copy_pixel(cell_pos, above_and_right_of_wall)\n\n\t\t\t\t\tvar new_tilesheet_y_1: int = cell_y + MARGIN + CELL_HEIGHT_WITH_MARGIN * row * 2\n\t\t\t\t\tvar new_tilesheet_y_2: int = new_tilesheet_y_1 + CELL_HEIGHT_WITH_MARGIN\n\n\t\t\t\t\tif is_part_of_section_2:\n\t\t\t\t\t\tatlas_image.set_pixel(tilesheet_x, new_tilesheet_y_1, pixel)\n\n\t\t\t\t\tif is_part_of_section_3:\n\t\t\t\t\t\tatlas_image.set_pixel(tilesheet_x, new_tilesheet_y_2, pixel)\n\n\tatlas_image.save_png(result_path)\n\n\nfunc need_to_copy_pixel(pos: Vector2, polygon: PackedVector2Array):\n\tvar pixel_is_in_poly: bool = Geometry2D.is_point_in_polygon(pos, polygon)\n\t\n\treturn pixel_is_in_poly\n"
  },
  {
    "path": "tools/generate_censored_assets.gd",
    "content": "extends MainLoop\n\n\n# This script generates censored assets to be placed in\n# public assets shared folder. This censoring is necessary\n# because some assets have licenses which do not allow\n# redistribution.\n# \n# Processes all files in current directory and saves results\n# into a new \"censored assets\" folder.\n# \n# Placeholder assets are \"censored\" by replacing all\n# original pixels with one color and applying extra\n# distortion so that the asset is unrecognizable from the\n# original.\n\n\nconst ARG_COUNT: int = 1\n\nconst PLACEHOLDER_COLOR = Color(Color.GRAY, 0.6)\nconst RESULT_FOLDER: String = \"censored assets\"\nconst DISTORTION_STRENGTH: int = 15\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tprocess_dir(\".\")\n\n\nfunc process_dir(dir_path: String):\n\tif dir_path.ends_with(RESULT_FOLDER):\n\t\treturn\n\t\n\tgenerate_placeholder_assets(dir_path)\n\n\tvar dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor child_dir in dir_list:\n\t\tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t\tprocess_dir(child_dir_path)\n\n\nfunc generate_placeholder_assets(dir_path: String):\n\tprint(\" \\n\")\n\tprint(\"Processing dir %s.\" % [dir_path])\n\t\n\tvar result_folder: String = \"%s/%s\" % [dir_path, RESULT_FOLDER]\n\tDirAccess.make_dir_absolute(result_folder)\n\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\n\tfor file_name in file_list:\n\t\tvar is_png: bool = file_name.ends_with(\".png\")\n\n\t\tif !is_png:\n\t\t\tcontinue\n\n\t\tvar file_path: String = \"%s/%s\" % [dir_path, file_name]\n\n\t\tprocess_file(file_path, file_name, result_folder)\n\n\nfunc process_file(file_path: String, file_name: String, result_folder: String):\n\tprint(\"Processing file %s.\" % [file_path])\n\n\tvar original_image: Image = Image.load_from_file(file_path)\n\tvar result_image: Image = generate_placeholder_image(original_image)\n\tvar result_path: String = \"%s/%s\" % [result_folder, file_name]\n\tresult_image.save_png(result_path)\n\n\nfunc generate_placeholder_image(original_image: Image) -> Image:\n\tvar width: float = original_image.get_width()\n\tvar height: float = original_image.get_height()\n\tvar result_image: Image = Image.create(width, height, false, Image.FORMAT_RGBA8)\n\tvar center: Vector2 = Vector2(width, height) / 2\n\n\tvar time_since_last_pixel: int = 100\n\n\tfor x in range(0, width):\n\t\tfor y in range(0, height):\n\t\t\tvar original_pixel: Color = original_image.get_pixel(x, y)\n\t\t\tvar pixel_is_set: bool = original_pixel.a != 0\n\n\t\t\tif pixel_is_set:\n\t\t\t\ttime_since_last_pixel = 0\n\t\t\telse:\n\t\t\t\ttime_since_last_pixel += 1\n\n\t\t\tif time_since_last_pixel < DISTORTION_STRENGTH:\n\t\t\t\tresult_image.set_pixel(x, y, PLACEHOLDER_COLOR)\n\n\treturn result_image\n"
  },
  {
    "path": "tools/pack_sprite_sheet.gd",
    "content": "class_name PackSpriteSheet extends MainLoop\n\n\n# Takes sprite sheets in a given folder/subfolders and\n# generates versions that are more tightly packed, with less\n# empty space. Also performs an optional resize.\n\n# How to use:\n# 1. Open terminal.\n# \n# 2. Run the script with godot's command line executable.\n# \n# 3. Resulting packed sprite sheets will overwrite\n#    originals, so make sure to backup.\n# \n# 4. In addition to packed sprite sheets, this script also\n#    generates metadata. This metadata needs to be used to\n#    display the packed sprite sheet correctly.\n\n\nconst ARG_COUNT: int = 3\n\nvar _raw_frame_size: int = 0\nvar _original_frame_size: int = 0\n\n\nfunc _initialize():\t\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 2 args: path and original frame size.\")\n\n\t\treturn\n\n\tvar root_dir_path: String = arg_list[0]\n\t_raw_frame_size = arg_list[1].to_float()\n\t_original_frame_size = arg_list[2].to_float()\n\n\tprocess_dir(root_dir_path)\n\n\nfunc process_dir(dir_path: String):\n\tprint(\"Processing dir:\", dir_path)\n\n# \tProcess sheets in current dir\n\tvar sheet_list: Array = DirAccess.get_files_at(dir_path)\n\tsheet_list = sheet_list.filter(\n\t\tfunc(sheet: String) -> bool:\n\t\t\tvar is_png: bool = sheet.ends_with(\".png\")\n\t\t\treturn is_png\n\t\t\t)\n\n\tfor sheet in sheet_list:\n\t\tvar sheet_path: String = \"%s/%s\" % [dir_path, sheet]\n\t\tprocess_sheet(sheet_path)\n\n# \tRecurse into subdirs\n\tvar subdir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor subdir_name in subdir_list:\n\t\tvar subdir_path: String = \"%s/%s\" % [dir_path, subdir_name]\n\t\tprocess_dir(subdir_path)\n\n\nfunc process_sheet(sheet_path: String):\n\tprint(\"Processing sheet: \", sheet_path)\n\t\n\tvar sprite_sheet: Image = Image.load_from_file(sheet_path)\n\n\tvar need_to_resize: bool = _raw_frame_size != _original_frame_size\n\n\tif need_to_resize:\n\t\tvar new_size: Vector2 = sprite_sheet.get_size() * _original_frame_size / _raw_frame_size\n\t\tsprite_sheet.resize(new_size.x, new_size.y)\n\n\tvar max_used_rect: Rect2i = get_max_used_rect(sprite_sheet)\n\tvar sprite_count: int = get_sprite_count(sprite_sheet)\n\tvar packed_sheet: Image = create_packed_sheet(sprite_sheet, max_used_rect)\n\n\tpacked_sheet.save_png(sheet_path)\n\tsave_metadata(sheet_path, packed_sheet, max_used_rect, sprite_count)\n\n\n# Calculate a rect that fits all sprites in the sprite sheet\nfunc get_max_used_rect(sheet_image: Image) -> Rect2i:\n\tvar sheet_texture: ImageTexture = ImageTexture.create_from_image(sheet_image)\n\t\n\tvar original_size: Vector2 = Vector2(_original_frame_size, _original_frame_size)\n\tvar row_count: int = int(float(sheet_image.get_height()) / original_size.y)\n\tvar column_count: int = int(float(sheet_image.get_width()) / original_size.x)\n\t\n\tvar max_used_rect: Rect2i = Rect2i()\n\tvar first_rect: bool = true\n\n\tfor row in range(0, row_count):\n\t\tfor col in range(0, column_count):\n\t\t\tvar used_rect: Rect2i = get_used_rect_at_cell(sheet_texture, row, col, original_size)\n\n\t\t\tvar sprite_is_empty: bool = used_rect.size == Vector2i(0, 0)\n\n\t\t\tif sprite_is_empty:\n\t\t\t\tcontinue\n\t\t\t\n\t\t\tif first_rect:\n\t\t\t\tmax_used_rect = used_rect\n\t\t\t\tfirst_rect = false\n\t\t\t\n\t\t\tmax_used_rect = max_used_rect.merge(used_rect)\n\t\n\treturn max_used_rect\n\n\nfunc get_sprite_count(sheet_image: Image) -> int:\n\tvar sprite_count: int = 0\n\n\tvar sheet_texture: ImageTexture = ImageTexture.create_from_image(sheet_image)\n\t\n\tvar original_size: Vector2 = Vector2(_original_frame_size, _original_frame_size)\n\tvar row_count: int = int(float(sheet_image.get_height()) / original_size.y)\n\tvar column_count: int = int(float(sheet_image.get_width()) / original_size.x)\n\t\n\tfor row in range(0, row_count):\n\t\tfor col in range(0, column_count):\n\t\t\tsprite_count\n\t\t\tvar used_rect: Rect2i = get_used_rect_at_cell(sheet_texture, row, col, original_size)\n\n\t\t\tvar sprite_is_empty: bool = used_rect.size == Vector2i(0, 0)\n\n\t\t\tif !sprite_is_empty:\n\t\t\t\tsprite_count += 1\n\t\t\telse:\n\t\t\t\tbreak\n\t\n\treturn sprite_count\n\n\n# Get used rect for sprite in sprite sheet at position\nfunc get_used_rect_at_cell(sheet_texture: ImageTexture, row: int, col: int, original_size: Vector2) -> Rect2i:\n\tvar sprite = AtlasTexture.new()\n\tsprite.atlas = sheet_texture\n\n\tvar region_position: Vector2 = Vector2(col * original_size.x, row * original_size.y)\n\tvar region_size: Vector2 = original_size\n\tsprite.region = Rect2(region_position, region_size)\n\n\tvar image: Image = sprite.get_image()\n\tvar used_rect = image.get_used_rect()\n\n\treturn used_rect\n\n\n# Create packed sheet copying sprites within given rect from source sprite sheet.\nfunc create_packed_sheet(sheet_image: Image, max_used_rect: Rect2i) -> Image:\n\tvar original_size: Vector2 = Vector2(_original_frame_size, _original_frame_size)\n\tvar packed_size: Vector2 = max_used_rect.size\n\tvar row_count: int = int(float(sheet_image.get_height()) / original_size.y)\n\tvar column_count: int = int(float(sheet_image.get_width()) / original_size.x)\n\t\n\tvar packed_sheet: Image = Image.create(packed_size.x * column_count, packed_size.y * row_count, false, Image.FORMAT_RGBA8)\n\n\tfor row in range(0, row_count):\n\t\tfor col in range(0, column_count):\n\t\t\tvar src_rect: Rect2i = Rect2i()\n\t\t\tsrc_rect.position = Vector2i(original_size.x * col, original_size.y * row) + max_used_rect.position\n\t\t\tsrc_rect.size = max_used_rect.size\n\n\t\t\tvar dst: Vector2i = Vector2i(packed_size.x * col, packed_size.y * row)\n\n\t\t\tpacked_sheet.blit_rect(sheet_image, src_rect, dst)\n\t\n\treturn packed_sheet\n\n\nfunc save_metadata(sheet_path: String, packed_sheet: Image, max_used_rect: Rect2i, sprite_count: int):\n\tvar metadata_path: String = PackedMetadata.get_metadata_path(sheet_path)\n\n# \tCreate and write first line if opening metadata file for\n# \tthe first time\n# \tNOTE: WRITE_READ creates file if doesn't exist and\n# \ttruncates it. READ_WRITE is the opposite.\n\tif !FileAccess.file_exists(metadata_path):\n\t\tvar file_created: FileAccess = FileAccess.open(metadata_path, FileAccess.WRITE_READ)\n\t\t\n\t\tvar legend_line: Array = PackedMetadata.get_legend_line()\n\t\tfile_created.store_csv_line(legend_line)\n\n\t\tfile_created.close()\n\n\tvar original_center: Vector2 = Vector2(_original_frame_size / 2, _original_frame_size / 2)\n\tvar used_rect_center: Vector2 = max_used_rect.position + max_used_rect.size / 2\n\tvar offset_pixels: Vector2 = used_rect_center - original_center\n\n\tvar metadata: PackedMetadata = PackedMetadata.make(sheet_path, packed_sheet, max_used_rect, offset_pixels, sprite_count)\n\tvar metadata_csv_line: Array = metadata.convert_to_csv_line()\n\n\tvar metadata_file: FileAccess = FileAccess.open(metadata_path, FileAccess.READ_WRITE)\n\n\tmetadata_file.seek_end()\n\tmetadata_file.store_csv_line(metadata_csv_line)\n\n\nfunc get_row_count() -> int:\n\treturn 0\n"
  },
  {
    "path": "tools/remove_empty_space_tilesheet.gd",
    "content": "class_name RemoveEmptySpaceTilesheet extends MainLoop\n\n\n# Takes a sprite sheet and removes empty space from it. Only\n# removes empty space above tiles and removes equal amounts\n# from all tiles.\n\n# This script will also print the modified tile sizes and\n# texture origins, which you should input into the tileset\n# editor.\n\n# NOTE: the minimum result tile height is 128, so that tile\n# is usable in tilesets.\n\n\nconst ARG_COUNT: int = 1\n\nconst MIN_HEIGHT: int = 128\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\nconst MARGIN: int = 0\nconst CELL_WIDTH_WITH_MARGIN: int = CELL_WIDTH + MARGIN * 2\nconst CELL_HEIGHT_WITH_MARGIN: int = CELL_HEIGHT + MARGIN * 2\nconst RESULT_FOLDER: String = \"results\"\n\n\nfunc _initialize():\t\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected args: sheet dir.\")\n\n\t\treturn\n\n\tvar sheets_dir: String = arg_list[0]\n\n\tprocess_dir(sheets_dir)\n\n\nfunc process_dir(dir_path: String):\n\tif dir_path.ends_with(RESULT_FOLDER):\n\t\treturn\n\n\tprocess_files_in_dir(dir_path)\n\n\tvar dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\tfor child_dir in dir_list:\n\t\tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t\tprocess_dir(child_dir_path)\n\n\nfunc process_files_in_dir(dir_path: String):\n\tprint(\" \\n\")\n\tprint(\"Processing dir %s.\" % [dir_path])\n\t\n\tvar result_folder: String = \"%s/%s\" % [dir_path, RESULT_FOLDER]\n\tDirAccess.make_dir_absolute(result_folder)\n\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\n\tfor file_name in file_list:\n\t\tvar is_png: bool = file_name.ends_with(\".png\")\n\n\t\tif !is_png:\n\t\t\tcontinue\n\n\t\tvar file_path: String = \"%s/%s\" % [dir_path, file_name]\n\n\t\tprocess_file(file_path, file_name, result_folder)\n\n\nfunc process_file(file_path: String, file_name: String, result_folder: String):\n\tprint(\" \")\n\tprint(\"Processing sheet:\", file_path)\n\n\tvar empty_height: int = calculate_empty_height(file_path)\n\n\tvar original_sheet: Image = Image.load_from_file(file_path)\n\tvar original_size: Vector2 = Vector2(CELL_WIDTH_WITH_MARGIN, CELL_HEIGHT_WITH_MARGIN)\n\tvar modified_size: Vector2 = Vector2(CELL_WIDTH_WITH_MARGIN, CELL_HEIGHT_WITH_MARGIN - empty_height)\n\tvar row_count: int = int(float(original_sheet.get_height()) / original_size.y)\n\tvar column_count: int = int(float(original_sheet.get_width()) / original_size.x)\n\tvar modified_sheet: Image = Image.create(modified_size.x * column_count, modified_size.y * row_count, false, Image.FORMAT_RGBA8)\n\n\tvar original_size_without_margins: Vector2 = Vector2(CELL_WIDTH, CELL_HEIGHT)\n\tvar modified_size_without_margins: Vector2 = Vector2(CELL_WIDTH, CELL_HEIGHT - empty_height)\n\tprint(\"Original size: \", original_size_without_margins)\n\tprint(\"Modified size: \", modified_size_without_margins)\n\tprint(\"Modified texture origin Y: \", (modified_size_without_margins.y - 64) - modified_size_without_margins.y / 2)\n\n#\tCut part of the original tile, without the empty space\n#\tabove. Past it into modified tilesheet.\n\tfor row in range(0, row_count):\n\t\tfor col in range(0, column_count):\n\t\t\tvar original_frame_pos: Vector2i = Vector2i(col * original_size.x + MARGIN, row * original_size.y + MARGIN)\n\t\t\tvar modified_frame_pos: Vector2i = Vector2i(col * modified_size.x + MARGIN, row * modified_size.y + MARGIN)\n\t\t\tvar src_rect_pos: Vector2i = original_frame_pos + Vector2i(0, empty_height)\n\t\t\tvar src_rect_size: Vector2i = Vector2i(CELL_WIDTH, CELL_HEIGHT - empty_height)\n\t\t\tvar src_rect: Rect2i = Rect2i(src_rect_pos, src_rect_size)\n\t\t\tvar blit_dst: Vector2i = modified_frame_pos\n\n\t\t\tmodified_sheet.blit_rect(original_sheet, src_rect, blit_dst)\n\n\tvar result_path: String = \"%s/%s\" % [result_folder, file_name]\n\tmodified_sheet.save_png(result_path)\n\n\nfunc calculate_empty_height(file_path: String) -> int:\n\tvar sheet: Image = Image.load_from_file(file_path)\n\tvar max_used_rect: Rect2i = get_max_used_rect(sheet)\n\tvar empty_height: int = max_used_rect.position.y\n\n#\tNOTE: only return even heights so that texture origin Y\n#\tis a whole number\n\tif empty_height % 2 != 0:\n\t\tempty_height -= 1\n\n\tif CELL_HEIGHT - empty_height < MIN_HEIGHT:\n\t\tempty_height = CELL_HEIGHT - MIN_HEIGHT\n\n\treturn empty_height\n\n\n# Calculate a rect that fits all sprites in the sprite sheet\nfunc get_max_used_rect(sheet_image: Image) -> Rect2i:\n\tvar sheet_texture: ImageTexture = ImageTexture.create_from_image(sheet_image)\n\t\n\tvar original_size: Vector2 = Vector2(CELL_WIDTH_WITH_MARGIN, CELL_HEIGHT_WITH_MARGIN)\n\tvar row_count: int = int(float(sheet_image.get_height()) / original_size.y)\n\tvar column_count: int = int(float(sheet_image.get_width()) / original_size.x)\n\t\n\tvar max_used_rect: Rect2i = Rect2i()\n\tvar first_rect: bool = true\n\n\tfor row in range(0, row_count):\n\t\tfor col in range(0, column_count):\n\t\t\tvar used_rect: Rect2i = get_used_rect_at_cell(sheet_texture, row, col, original_size)\n\n\t\t\tvar sprite_is_empty: bool = used_rect.size == Vector2i(0, 0)\n\n\t\t\tif sprite_is_empty:\n\t\t\t\tcontinue\n\t\t\t\n\t\t\tif first_rect:\n\t\t\t\tmax_used_rect = used_rect\n\t\t\t\tfirst_rect = false\n\t\t\t\n\t\t\tmax_used_rect = max_used_rect.merge(used_rect)\n\t\n\treturn max_used_rect\n\n\n# Get used rect for sprite in sprite sheet at position\nfunc get_used_rect_at_cell(sheet_texture: ImageTexture, row: int, col: int, original_size: Vector2) -> Rect2i:\n\tvar sprite = AtlasTexture.new()\n\tsprite.atlas = sheet_texture\n\n\tvar region_position: Vector2 = Vector2(col * original_size.x, row * original_size.y)\n\tvar region_size: Vector2 = original_size\n\tsprite.region = Rect2(region_position, region_size)\n\n\tvar image: Image = sprite.get_image()\n\tvar used_rect = image.get_used_rect()\n\n\treturn used_rect\n"
  },
  {
    "path": "tools/remove_sheet_margins.gd",
    "content": "class_name RemoveSheetMargins extends MainLoop\n\n\n# Takes a tilesheet and removes margins from it.\n# Overwrites original file.\n\n\nconst ARG_COUNT: int = 1\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\nconst MARGIN: int = 0\nconst CELL_WIDTH_WITH_MARGIN: int = CELL_WIDTH + MARGIN * 2\nconst CELL_HEIGHT_WITH_MARGIN: int = CELL_HEIGHT + MARGIN * 2\n\n\nfunc _initialize():\t\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected args: sheet.\")\n\n\t\treturn\n\n\tvar sheet_path: String = arg_list[0]\n\n\tprocess_sheet(sheet_path)\n\n\nfunc process_sheet(sheet_path: String):\n\tprint(\"Processing sheet:\", sheet_path)\n\n\tvar original_sheet: Image = Image.load_from_file(sheet_path)\n\tvar original_size: Vector2 = Vector2(CELL_WIDTH_WITH_MARGIN, CELL_HEIGHT_WITH_MARGIN)\n\tvar modified_size: Vector2 = Vector2(CELL_WIDTH, CELL_HEIGHT)\n\tvar row_count: int = floori(float(original_sheet.get_height()) / original_size.y)\n\tvar column_count: int = floori(float(original_sheet.get_width()) / original_size.x)\n\tvar modified_sheet: Image = Image.create(modified_size.x * column_count, modified_size.y * row_count, false, Image.FORMAT_RGBA8)\n\n\tfor row in range(0, row_count):\n\t\tfor col in range(0, column_count):\n\t\t\tvar original_frame_pos: Vector2i = Vector2i(col * original_size.x + MARGIN, row * original_size.y + MARGIN)\n\t\t\tvar modified_frame_pos: Vector2i = Vector2i(col * modified_size.x, row * modified_size.y)\n\t\t\tvar src_rect_pos: Vector2i = original_frame_pos\n\t\t\tvar src_rect_size: Vector2i = Vector2i(CELL_WIDTH, CELL_HEIGHT)\n\t\t\tvar src_rect: Rect2i = Rect2i(src_rect_pos, src_rect_size)\n\t\t\tvar blit_dst: Vector2i = modified_frame_pos\n\n\t\t\tmodified_sheet.blit_rect(original_sheet, src_rect, blit_dst)\n\n\tmodified_sheet.save_png(sheet_path)\n"
  },
  {
    "path": "tools/rename_files.gd",
    "content": "extends MainLoop\n\n\n# Renames all files in current directory according to a\n# pattern.\n\n\nconst PLACEHOLDER_COLOR = Color.BLUE\nconst RESULT_FOLDER: String = \"placeholders\"\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tprocess_dir(\".\")\n\n\nfunc process_dir(dir_path: String):\n\tprint(\" \")\n\tprint(\"Processing dir %s.\" % [dir_path])\n\n\tvar file_list: PackedStringArray = DirAccess.get_files_at(dir_path)\n\tvar dir: DirAccess = DirAccess.open(dir_path)\n\tvar remove_via_tmp_list: Array[String] = []\n\tfor old_filename in file_list:\n\t\tvar new_filename: String = old_filename.to_snake_case()\n\n\t\tvar filename_length_changed: bool = new_filename.length() != old_filename.length()\n\n\t\tif filename_length_changed:\n\t\t\tprint(\"Renaming %s->%s\" % [old_filename, new_filename])\n\t\t\tdir.rename(old_filename, new_filename)\n\t\telse:\n\t\t\tremove_via_tmp_list.append(old_filename)\n\n\tif !remove_via_tmp_list.is_empty():\n\t\tprint(\"\\n \\n \\nSome files need to be renamed via git mv + tmp trick:\")\n\t\t\n\t\tfor filename in remove_via_tmp_list:\n\t\t\tprint(filename)\n\n\t# var dir_list: Array = DirAccess.get_directories_at(dir_path)\n\n\t# for child_dir in dir_list:\n\t# \tvar child_dir_path: String = \"%s/%s\" % [dir_path, child_dir]\n\t# \tprocess_dir(child_dir_path)\n"
  },
  {
    "path": "tools/render_8_direction_sprites.py",
    "content": "# MIT License\n\n# Copyright (c) 2023 Dmitry Degtyarev\n# Copyright (c) 2022 Joe\n\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n\n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n# Obtained this script here:\n# https://github.com/FoozleCC/blender_scripts\n# Added some modifications\n\nimport bpy\nimport os\nimport math\nimport mathutils\n\n\ndef render8directions_selected_objects(path):\n    # path fixing\n    path = os.path.abspath(path)\n\n    # get list of selected objects\n    selected_list = bpy.context.selected_objects\n\n    # deselect all in scene\n    bpy.ops.object.select_all(action='TOGGLE')\n\n    s = bpy.context.scene\n\n    s.render.resolution_x = 256\n    s.render.resolution_y = 256\n    \n    scn = bpy.context.scene\n\n    # Calculate the center of the bounding box of the selected objects\n    bounding_box_center = mathutils.Vector((0, 0, 0))\n    for o in selected_list:\n        o_bbox_center = sum((mathutils.Vector(b) for b in o.bound_box), mathutils.Vector()) / 8\n        bounding_box_center += o.matrix_world @ o_bbox_center\n    bounding_box_center /= len(selected_list)\n    \n    # Add or use existing camera\n    if \"Camera\" in bpy.data.objects:\n        cam = bpy.data.objects[\"Camera\"]\n    else:\n        cam_data = bpy.data.cameras.new('Camera')\n        cam = bpy.data.objects.new('Camera', cam_data)\n        bpy.context.collection.objects.link(cam)\n    \n    # Set camera distance from the center and its height\n    cam_distance = 10\n    cam_height = 5\n\n    # loop all initial selected objects (which will likely just be one object.. I haven't tried setting up multiple yet)\n    for o in selected_list:\n\n        # select the object\n        bpy.context.scene.objects[o.name].select_set(True)\n\n        # loop through the actions\n        for a in bpy.data.actions:\n            # assign the action\n            bpy.context.active_object.animation_data.action = bpy.data.actions.get(a.name)\n\n            # dynamically set the last frame to render based on action\n            scn.frame_end = int(bpy.context.active_object.animation_data.action.frame_range[1])\n\n            # create folder for animation\n            action_folder = os.path.join(path, a.name)\n            if not os.path.exists(action_folder):\n                os.makedirs(action_folder)\n\n            # loop through all 8 directions\n            for angle in range(0, 360, 90):\n                if angle == 0:\n                    cardinalDirection = \"S\"\n                if angle == 90:\n                    cardinalDirection = \"E\"\n                if angle == 180:\n                    cardinalDirection = \"N\"\n                if angle == 270:\n                    cardinalDirection = \"W\"\n                \n                # restore original rotation\n                bpy.context.active_object.rotation_euler[2] = math.radians(0)\n                \n                # Set camera position in polar coordinates\n                cam_x = bounding_box_center.x + cam_distance * math.cos(math.radians(angle))\n                cam_y = bounding_box_center.y + cam_distance * math.sin(math.radians(angle))\n                cam.location = mathutils.Vector((cam_x, cam_y, cam_height))\n\n                # Set camera to point to the center of the bounding box\n                direction = bounding_box_center - cam.location\n                rot_quat = direction.to_track_quat('-Z', 'Y')\n                cam.rotation_euler = rot_quat.to_euler()\n\n                 # create folder for specific angle\n                animation_folder = os.path.join(action_folder, cardinalDirection)\n                if not os.path.exists(animation_folder):\n                    os.makedirs(animation_folder)\n            \n                                # loop through and render frames.  Can set how \"often\" it renders.\n                # Every frame is likely not needed.  Currently set to 2 (every other).\n                for i in range(s.frame_start,s.frame_end,2):\n                    s.frame_current = i\n\n                    s.render.filepath = (\n                                        animation_folder\n                                        + \"\\\\\"\n                                        + str(a.name)\n                                        + \"_\"\n                                        + str(cardinalDirection)\n                                        + \"_\"\n                                        + str(s.frame_current).zfill(3)\n                                        )\n                    bpy.ops.render.render( #{'dict': \"override\"},\n                                          #'INVOKE_DEFAULT',  \n                                          False,            # undo support\n                                          animation=False, \n                                          write_still=True\n                                         ) \n\n\n\ndef get_export_path() -> str:\n\tscript_path = os.path.realpath(__file__)\n\tblender_file_path = os.path.dirname(script_path)\n\tparent_folder_path = os.path.dirname(blender_file_path)\n\texport_path = os.path.join(parent_folder_path, \"script-export\")\n\n\treturn export_path\n\n\nexport_path = get_export_path()\nrender8directions_selected_objects(export_path)\n"
  },
  {
    "path": "tools/separate_tilesheet.gd",
    "content": "extends MainLoop\n\n\n# Script to take a tilesheet and separate it into individual\n# tiles.\n\n#\n# Examples:\n# \"foo.png\" -> \"foo-1.png\", \"foo-2.png\"...\n\n\nconst ARG_COUNT: int = 1\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tprint(arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 1 args: path.\")\n\t\tprint(arg_list)\n\n\t\treturn\n\n\tvar path: String = arg_list[0]\n\n\tprocess_path(path)\n\n\nfunc process_path(path: String):\n\tprint(\"Processing path:\", path)\n\n\tvar original_image: Image = Image.load_from_file(path)\n\tvar original_width: int = original_image.get_width()\n\tvar original_height: int = original_image.get_height()\n\tvar row_count: int = original_height / CELL_HEIGHT\n\tvar column_count: int = original_width / CELL_WIDTH\n\n\tvar tile_index: int = 0\n\n\tfor column in range(0, column_count):\n\t\tfor row in range(0, row_count):\n\t\t\tvar result_image: = Image.create(CELL_WIDTH, CELL_HEIGHT, false, Image.FORMAT_RGBA8)\n\n\t\t\tvar src_rect_pos: Vector2i = Vector2i(column * CELL_WIDTH, row * CELL_HEIGHT)\n\t\t\tvar src_rect_size: Vector2i = Vector2i(CELL_WIDTH, CELL_HEIGHT)\n\t\t\tvar src_rect: Rect2i = Rect2i(src_rect_pos, src_rect_size)\n\t\t\tvar blit_dst: Vector2i = Vector2i(0, 0)\n\t\t\tresult_image.blit_rect(original_image, src_rect, blit_dst)\n\n\t\t\tvar tile_index_padded: String = str(tile_index).lpad(3, \"0\")\n\n\t\t\tvar result_path: String = path.replace(\".png\", \"-%s.png\" % tile_index_padded)\n\t\t\tresult_image.save_png(result_path)\n\t\t\t\n\t\t\ttile_index += 1\n"
  },
  {
    "path": "tools/show_missing_imports.py",
    "content": "import os\nimport sys\n\ndef print_usage():\n    print(\"Usage: python find_pairs.py <directory_path> [--delete] [--used]\")\n    sys.exit(1)\n\n# Supported file extensions\nfile_extensions = [\n    # Archives\n    \".7z\", \".br\", \".gz\", \".tar\", \".zip\",\n    \n    # Documents\n    \".pdf\",\n    \n    # Images\n    \".gif\", \".ico\", \".jpg\", \".png\", \".psd\", \".webp\",\n    \n    # Fonts\n    \".woff2\", \".otf\",\n    \n    # Audio\n    \".mp3\", \".wav\",\n    \n    # Other\n    \".exe\"\n]\n\n# Check arguments\nif len(sys.argv) < 2:\n    print_usage()\n\n# Starting directory\nsearch_directory = sys.argv[1]\n\n# Check for delete and used flags\ndelete_unmatched = \"--delete\" in sys.argv\nused_only = \"--used\" in sys.argv\n\n# Initialize lists to store all found files\nfiles = []\nimport_files = {}\ntext_files = {}\n\n# Walk through directory recursively\nfor dirpath, dirnames, filenames in os.walk(search_directory):\n    for filename in filenames:\n        full_path = os.path.join(dirpath, filename)\n        if filename.endswith(tuple(file_extensions)):\n            files.append(full_path)\n        elif filename.endswith('.import') and any(filename.replace('.import', '').endswith(ext) for ext in file_extensions):\n            import_files[os.path.basename(full_path).replace('.import', '')] = full_path\n        elif filename.endswith(('.tscn', '.gd')):\n            with open(full_path, 'r', encoding=\"utf-8\", errors=\"ignore\") as f:\n                content = f.read()\n                text_files[full_path] = content\n\n# Convert the main files list to their .import version for easy comparison\nfiles_with_import = [f + \".import\" for f in files]\n\n# Find .import files that don't have a corresponding file\nunmatched_import_files = set(import_files.values()) - set(files_with_import)\n\nif unmatched_import_files:\n    print(\"Files with .import format but missing corresponding files:\")\n    for file in unmatched_import_files:\n        base_name = os.path.basename(file).replace('.import', '')\n        print(file)\n        if used_only:\n            mentioned_in = [path for path, content in text_files.items() if base_name in content]\n            if mentioned_in:\n                print(f\"  Mentioned in:\")\n                for m in mentioned_in:\n                    print(f\"    {m}\")\n            else:\n                continue  # Skip to next iteration if the missing file is not mentioned\n        if delete_unmatched:\n            try:\n                os.remove(file)\n                print(f\"  Deleted: {file}\")\n            except Exception as e:\n                print(f\"  Error deleting {file}: {e}\")\n        print(\"\")\n\nprint(\"\\nFinished processing unmatched .import files.\")\n"
  },
  {
    "path": "tools/slice_sheet_into_rows.gd",
    "content": "extends MainLoop\n\n\n# Script to take an image and slice it into slices. Each\n# slice is named with \"original_name-N.png\". Use this to\n# break down very large tilesheets into multiple smaller\n# tilesheets.\n\n#\n# Examples:\n# \"foo.png\" -> \"foo-1.png\", \"foo-2.png\"...\n\n\nconst ARG_COUNT: int = 2\n\nconst CELL_WIDTH: int = 256\nconst CELL_HEIGHT: int = 512\nconst MARGIN: int = 0\nconst CELL_WIDTH_WITH_MARGIN: int = CELL_WIDTH + MARGIN * 2\nconst CELL_HEIGHT_WITH_MARGIN: int = CELL_HEIGHT + MARGIN * 2\n\n\nfunc _initialize():\n\tprint(\"Begin\")\n\trun()\n\tprint(\"End\")\n\n\n# NOTE: returning true from _process() is the only way to\n# quit from MainLoop.\nfunc _process(_delta: float):\n\tvar end_main_loop: bool = true\n\treturn end_main_loop\n\n\nfunc run():\n\tvar arg_list: Array = OS.get_cmdline_user_args()\n\n\tprint(\"Argument list: \", arg_list)\n\n\tprint(arg_list)\n\n\tif arg_list.size() != ARG_COUNT:\n\t\tprint(\"Incorrect args provided. Expected 2 args: path and row count per slice.\")\n\t\tprint(arg_list)\n\n\t\treturn\n\n\tvar path: String = arg_list[0]\n\tvar row_count: int = arg_list[1].to_int()\n\n\tprocess_path(path, row_count)\n\n\nfunc process_path(path: String, row_count: int):\n\tprint(\"Processing path:\", path)\n\n\tvar original_image: Image = Image.load_from_file(path)\n\tvar original_width: int = original_image.get_width()\n\tvar original_height: int = original_image.get_height()\n\tvar slice_height: int = row_count * CELL_HEIGHT_WITH_MARGIN\n\tvar slice_count: int = ceil(float(original_height) / slice_height)\n\t\n\tif slice_height > original_height:\n\t\tpush_error(\"Row count arg is larger than row count in original image.\")\n\n\t\treturn\n\n\tprint(\"Slice count will be:\", slice_count)\n\n\tfor i in range(0, slice_count):\n\t\tvar result_image: = Image.create(original_width, slice_height, false, Image.FORMAT_RGBA8)\n\n\t\tvar src_rect_pos: Vector2i = Vector2i(0, i * slice_height)\n\t\tvar src_rect_size: Vector2i = Vector2i(original_width, slice_height)\n\t\tvar src_rect: Rect2i = Rect2i(src_rect_pos, src_rect_size)\n\t\tvar blit_dst: Vector2i = Vector2i(0, 0)\n\t\tresult_image.blit_rect(original_image, src_rect, blit_dst)\n\n\t\tvar result_path: String = path.replace(\".png\", \"-%d.png\" % i)\n\t\tresult_image.save_png(result_path)\n"
  },
  {
    "path": "webrtc/README.md",
    "content": "WebRtc plugin is not included in the git repo. You need to install it separately.\nThis plugin is required for multiplayer.\n\nHow to install:\n1. Open \"AssetLib\" in Godot editor. It's a button in the top middle of the window.\n2. Search for \"webrtc\".\n3. Download \"WebRTC plugin - Godot 4.1+\".\n4. Press \"Change Install Folder\".\n5. Create new folder \"webrtc\" in the game repository and select it as install folder.\n6. Press \"Install\".\n"
  }
]